diff options
Diffstat (limited to 'configserver/src/main/java')
19 files changed, 281 insertions, 373 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index 9e8010cf8a7..819049c6517 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -223,10 +223,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - public PrepareResult deploy(CompressedApplicationInputStream in, PrepareParams prepareParams) { - return deploy(in, prepareParams, false, clock.instant()); - } - public PrepareResult deploy(CompressedApplicationInputStream in, PrepareParams prepareParams, boolean ignoreSessionStaleFailure, Instant now) { File tempDir = uncheck(() -> Files.createTempDirectory("deploy")).toFile(); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java index 42c80acd80d..657e113475b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java @@ -16,7 +16,6 @@ import com.yahoo.vespa.config.protocol.DefContent; import com.yahoo.vespa.config.server.model.SuperModelConfigProvider; import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; -import java.io.IOException; import java.io.StringReader; /** @@ -74,7 +73,7 @@ public class SuperModelController { long getGeneration() { return generation; } - public <CONFIGTYPE extends ConfigInstance> CONFIGTYPE getConfig(Class<CONFIGTYPE> configClass, ApplicationId applicationId, String configId) throws IOException { + public <CONFIGTYPE extends ConfigInstance> CONFIGTYPE getConfig(Class<CONFIGTYPE> configClass, ApplicationId applicationId, String configId) { return model.getConfig(configClass, applicationId, configId); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelGenerationCounter.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelGenerationCounter.java index 6adbcc8dae9..6d5c4a81c92 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelGenerationCounter.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelGenerationCounter.java @@ -2,11 +2,9 @@ package com.yahoo.vespa.config.server; import com.yahoo.path.Path; -import com.yahoo.transaction.AbstractTransaction; -import com.yahoo.transaction.Transaction; import com.yahoo.vespa.config.GenerationCounter; -import com.yahoo.vespa.curator.recipes.CuratorCounter; import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.curator.recipes.CuratorCounter; /** * Distributed global generation counter for the super model. diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelRequestHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelRequestHandler.java index 6fcfde80510..aa06c07f8af 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelRequestHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelRequestHandler.java @@ -3,21 +3,20 @@ package com.yahoo.vespa.config.server; import com.google.inject.Inject; import com.yahoo.cloud.config.ConfigserverConfig; +import com.yahoo.component.Version; import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.ConfigDefinitionRepo; -import com.yahoo.component.Version; -import java.util.logging.Level; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.vespa.config.ConfigKey; import com.yahoo.vespa.config.GetConfigRequest; import com.yahoo.vespa.config.protocol.ConfigResponse; -import com.yahoo.config.provision.ApplicationId; import com.yahoo.vespa.config.server.application.ApplicationSet; import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; -import java.io.IOException; import java.util.Optional; import java.util.Set; +import java.util.logging.Level; /** * Handles request for supermodel config. @@ -84,7 +83,7 @@ public class SuperModelRequestHandler implements RequestHandler { return null; } - public <CONFIGTYPE extends ConfigInstance> CONFIGTYPE getConfig(Class<CONFIGTYPE> configClass, ApplicationId applicationId, String configId) throws IOException { + public <CONFIGTYPE extends ConfigInstance> CONFIGTYPE getConfig(Class<CONFIGTYPE> configClass, ApplicationId applicationId, String configId) { return handler.getConfig(configClass, applicationId, configId); } @@ -128,4 +127,5 @@ public class SuperModelRequestHandler implements RequestHandler { superModelManager.markAsComplete(); updateHandler(); } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java index 4f04724a0a8..0b16a41dcba 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java @@ -1,16 +1,26 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.application; -import com.yahoo.concurrent.StripedExecutor; +import com.yahoo.component.Version; +import com.yahoo.config.FileReference; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.TenantName; -import java.util.logging.Level; import com.yahoo.path.Path; import com.yahoo.text.Utf8; import com.yahoo.transaction.Transaction; +import com.yahoo.vespa.config.ConfigKey; +import com.yahoo.vespa.config.GetConfigRequest; +import com.yahoo.vespa.config.protocol.ConfigResponse; import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.NotFoundException; import com.yahoo.vespa.config.server.ReloadHandler; +import com.yahoo.vespa.config.server.ReloadListener; +import com.yahoo.vespa.config.server.RequestHandler; +import com.yahoo.vespa.config.server.host.HostRegistry; +import com.yahoo.vespa.config.server.host.HostValidator; +import com.yahoo.vespa.config.server.monitoring.MetricUpdater; +import com.yahoo.vespa.config.server.monitoring.Metrics; +import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.curator.Lock; @@ -19,15 +29,20 @@ import com.yahoo.vespa.curator.transaction.CuratorTransaction; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; +import java.time.Clock; import java.time.Duration; +import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; +import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; + /** * The applications of a tenant, backed by ZooKeeper. * @@ -38,7 +53,7 @@ import java.util.stream.Collectors; * @author Ulf Lilleengen * @author jonmv */ -public class TenantApplications { +public class TenantApplications implements RequestHandler, ReloadHandler, HostValidator<ApplicationId> { private static final Logger log = Logger.getLogger(TenantApplications.class.getName()); @@ -46,24 +61,35 @@ public class TenantApplications { private final Path applicationsPath; private final Path locksPath; private final Curator.DirectoryCache directoryCache; - private final ReloadHandler reloadHandler; private final Executor zkWatcherExecutor; + private final Metrics metrics; + private final TenantName tenant; + private final List<ReloadListener> reloadListeners; + private final ConfigResponseFactory responseFactory; + private final HostRegistry<ApplicationId> hostRegistry; + private final ApplicationMapper applicationMapper = new ApplicationMapper(); + private final MetricUpdater tenantMetricUpdater; + private final Clock clock = Clock.systemUTC(); - private TenantApplications(Curator curator, ReloadHandler reloadHandler, TenantName tenant, - ExecutorService zkCacheExecutor, StripedExecutor<TenantName> zkWatcherExecutor) { - this.curator = curator; + + private TenantApplications(TenantName tenant, GlobalComponentRegistry registry) { + this.curator = registry.getCurator(); this.applicationsPath = TenantRepository.getApplicationsPath(tenant); this.locksPath = TenantRepository.getLocksPath(tenant); - this.reloadHandler = reloadHandler; - this.zkWatcherExecutor = command -> zkWatcherExecutor.execute(tenant, command); - this.directoryCache = curator.createDirectoryCache(applicationsPath.getAbsolute(), false, false, zkCacheExecutor); + this.tenant = tenant; + this.zkWatcherExecutor = command -> registry.getZkWatcherExecutor().execute(tenant, command); + this.directoryCache = curator.createDirectoryCache(applicationsPath.getAbsolute(), false, false, registry.getZkCacheExecutor()); this.directoryCache.start(); this.directoryCache.addListener(this::childEvent); + this.metrics = registry.getMetrics(); + this.reloadListeners = List.of(registry.getReloadListener()); + this.responseFactory = ConfigResponseFactory.create(registry.getConfigserverConfig()); + this.tenantMetricUpdater = metrics.getOrCreateMetricUpdater(Metrics.createDimensions(tenant)); + this.hostRegistry = registry.getHostRegistries().createApplicationHostRegistry(tenant); } - public static TenantApplications create(GlobalComponentRegistry registry, ReloadHandler reloadHandler, TenantName tenant) { - return new TenantApplications(registry.getCurator(), reloadHandler, tenant, - registry.getZkCacheExecutor(), registry.getZkWatcherExecutor()); + public static TenantApplications create(GlobalComponentRegistry registry, TenantName tenant) { + return new TenantApplications(tenant, registry); } /** @@ -132,7 +158,7 @@ public class TenantApplications { * Removes all applications not known to this from the config server state. */ public void removeUnusedApplications() { - reloadHandler.removeApplicationsExcept(Set.copyOf(activeApplications())); + removeApplicationsExcept(Set.copyOf(activeApplications())); } /** @@ -170,7 +196,7 @@ public class TenantApplications { } private void applicationRemoved(ApplicationId applicationId) { - reloadHandler.removeApplication(applicationId); + removeApplication(applicationId); log.log(Level.INFO, TenantRepository.logPre(applicationId) + "Application removed: " + applicationId); } @@ -186,4 +212,201 @@ public class TenantApplications { return locksPath.append(id.serializedForm()); } + + /** + * Gets a config for the given app, or null if not found + */ + @Override + public ConfigResponse resolveConfig(ApplicationId appId, GetConfigRequest req, Optional<Version> vespaVersion) { + Application application = getApplication(appId, vespaVersion); + if (log.isLoggable(Level.FINE)) { + log.log(Level.FINE, TenantRepository.logPre(appId) + "Resolving for tenant '" + tenant + "' with handler for application '" + application + "'"); + } + return application.resolveConfig(req, responseFactory); + } + + // For testing only + long getApplicationGeneration(ApplicationId appId, Optional<Version> vespaVersion) { + Application application = getApplication(appId, vespaVersion); + return application.getApplicationGeneration(); + } + + private void notifyReloadListeners(ApplicationSet applicationSet) { + for (ReloadListener reloadListener : reloadListeners) { + reloadListener.hostsUpdated(tenant, hostRegistry.getAllHosts()); + reloadListener.configActivated(applicationSet); + } + } + + /** + * Activates the config of the given app. Notifies listeners + * + * @param applicationSet the {@link ApplicationSet} to be reloaded + */ + @Override + public void reloadConfig(ApplicationSet applicationSet) { + ApplicationId id = applicationSet.getId(); + try (Lock lock = lock(id)) { + if ( ! exists(id)) + return; // Application was deleted before activation. + if (applicationSet.getApplicationGeneration() != requireActiveSessionOf(id)) + return; // Application activated a new session before we got here. + + setLiveApp(applicationSet); + notifyReloadListeners(applicationSet); + } + } + + @Override + public void removeApplication(ApplicationId applicationId) { + try (Lock lock = lock(applicationId)) { + if (exists(applicationId)) + return; // Application was deployed again. + + if (applicationMapper.hasApplication(applicationId, clock.instant())) { + applicationMapper.remove(applicationId); + hostRegistry.removeHostsForKey(applicationId); + reloadListenersOnRemove(applicationId); + tenantMetricUpdater.setApplications(applicationMapper.numApplications()); + metrics.removeMetricUpdater(Metrics.createDimensions(applicationId)); + } + } + } + + @Override + public void removeApplicationsExcept(Set<ApplicationId> applications) { + for (ApplicationId activeApplication : applicationMapper.listApplicationIds()) { + if ( ! applications.contains(activeApplication)) { + log.log(Level.INFO, "Will remove deleted application " + activeApplication.toShortString()); + removeApplication(activeApplication); + } + } + } + + private void reloadListenersOnRemove(ApplicationId applicationId) { + for (ReloadListener listener : reloadListeners) { + listener.hostsUpdated(tenant, hostRegistry.getAllHosts()); + listener.applicationRemoved(applicationId); + } + } + + private void setLiveApp(ApplicationSet applicationSet) { + ApplicationId id = applicationSet.getId(); + Collection<String> hostsForApp = applicationSet.getAllHosts(); + hostRegistry.update(id, hostsForApp); + applicationSet.updateHostMetrics(); + tenantMetricUpdater.setApplications(applicationMapper.numApplications()); + applicationMapper.register(id, applicationSet); + } + + @Override + public Set<ConfigKey<?>> listNamedConfigs(ApplicationId appId, Optional<Version> vespaVersion, ConfigKey<?> keyToMatch, boolean recursive) { + Application application = getApplication(appId, vespaVersion); + return listConfigs(application, keyToMatch, recursive); + } + + private Set<ConfigKey<?>> listConfigs(Application application, ConfigKey<?> keyToMatch, boolean recursive) { + Set<ConfigKey<?>> ret = new LinkedHashSet<>(); + for (ConfigKey<?> key : application.allConfigsProduced()) { + String configId = key.getConfigId(); + if (recursive) { + key = new ConfigKey<>(key.getName(), configId, key.getNamespace()); + } else { + // Include first part of id as id + key = new ConfigKey<>(key.getName(), configId.split("/")[0], key.getNamespace()); + } + if (keyToMatch != null) { + String n = key.getName(); // Never null + String ns = key.getNamespace(); // Never null + if (n.equals(keyToMatch.getName()) && + ns.equals(keyToMatch.getNamespace()) && + configId.startsWith(keyToMatch.getConfigId()) && + !(configId.equals(keyToMatch.getConfigId()))) { + + if (!recursive) { + // For non-recursive, include the id segment we were searching for, and first part of the rest + key = new ConfigKey<>(key.getName(), appendOneLevelOfId(keyToMatch.getConfigId(), configId), key.getNamespace()); + } + ret.add(key); + } + } else { + ret.add(key); + } + } + return ret; + } + + @Override + public Set<ConfigKey<?>> listConfigs(ApplicationId appId, Optional<Version> vespaVersion, boolean recursive) { + Application application = getApplication(appId, vespaVersion); + return listConfigs(application, null, recursive); + } + + /** + * Given baseIdSegment search/ and id search/qrservers/default.0, return search/qrservers + * @return id segment with one extra level from the id appended + */ + String appendOneLevelOfId(String baseIdSegment, String id) { + if ("".equals(baseIdSegment)) return id.split("/")[0]; + String theRest = id.substring(baseIdSegment.length()); + if ("".equals(theRest)) return id; + theRest = theRest.replaceFirst("/", ""); + String theRestFirstSeg = theRest.split("/")[0]; + return baseIdSegment+"/"+theRestFirstSeg; + } + + @Override + public Set<ConfigKey<?>> allConfigsProduced(ApplicationId appId, Optional<Version> vespaVersion) { + Application application = getApplication(appId, vespaVersion); + return application.allConfigsProduced(); + } + + private Application getApplication(ApplicationId appId, Optional<Version> vespaVersion) { + try { + return applicationMapper.getForVersion(appId, vespaVersion, clock.instant()); + } catch (VersionDoesNotExistException ex) { + throw new NotFoundException(String.format("%sNo such application (id %s): %s", TenantRepository.logPre(tenant), appId, ex.getMessage())); + } + } + + @Override + public Set<String> allConfigIds(ApplicationId appId, Optional<Version> vespaVersion) { + Application application = getApplication(appId, vespaVersion); + return application.allConfigIds(); + } + + @Override + public boolean hasApplication(ApplicationId appId, Optional<Version> vespaVersion) { + return hasHandler(appId, vespaVersion); + } + + private boolean hasHandler(ApplicationId appId, Optional<Version> vespaVersion) { + return applicationMapper.hasApplicationForVersion(appId, vespaVersion, clock.instant()); + } + + @Override + public ApplicationId resolveApplicationId(String hostName) { + ApplicationId applicationId = hostRegistry.getKeyForHost(hostName); + if (applicationId == null) { + applicationId = ApplicationId.defaultId(); + } + return applicationId; + } + + @Override + public Set<FileReference> listFileReferences(ApplicationId applicationId) { + return applicationMapper.listApplications(applicationId).stream() + .flatMap(app -> app.getModel().fileReferences().stream()) + .collect(toSet()); + } + + @Override + public void verifyHosts(ApplicationId key, Collection<String> newHosts) { + hostRegistry.verifyHosts(key, newHosts); + for (ReloadListener reloadListener : reloadListeners) { + reloadListener.verifyHostsAreAvailable(tenant, newHosts); + } + } + + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java index e2cf84d6715..7e83d7013e0 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java @@ -21,7 +21,6 @@ import com.yahoo.vespa.config.server.zookeeper.ZKApplicationPackage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HostHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HostHandler.java index ffe3d39b524..2c888df6658 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HostHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HostHandler.java @@ -9,13 +9,14 @@ import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.jdisc.Response; import com.yahoo.jdisc.application.BindingMatch; -import java.util.logging.Level; import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.host.HostRegistries; import com.yahoo.vespa.config.server.host.HostRegistry; -import com.yahoo.vespa.config.server.http.*; +import com.yahoo.vespa.config.server.http.HttpErrorResponse; +import com.yahoo.vespa.config.server.http.HttpHandler; +import com.yahoo.vespa.config.server.http.JSONResponse; -import java.util.concurrent.Executor; +import java.util.logging.Level; /** diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java index 7828ce8963f..6b42ca7fa95 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java @@ -36,7 +36,6 @@ import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.flags.FlagSource; import java.net.URI; -import java.time.Instant; import java.util.Map; import java.util.Optional; import java.util.logging.Level; @@ -88,8 +87,8 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { ApplicationId applicationId, Optional<DockerImage> wantedDockerImageRepository, Version wantedNodeVespaVersion, - Optional<AllocatedHosts> ignored, // Ignored since we have this in the app package for activated models - Instant now) { + Optional<AllocatedHosts> ignored // Ignored since we have this in the app package for activated models + ) { log.log(Level.FINE, String.format("Loading model version %s for session %s application %s", modelFactory.version(), appGeneration, applicationId)); ModelContext.Properties modelContextProperties = createModelContextProperties(applicationId); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java index 455731d9cb6..245b9db020b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java @@ -166,8 +166,7 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { applicationId, wantedDockerImageRepository, wantedNodeVespaVersion, - allocatedHosts.asOptional(), - now); + allocatedHosts.asOptional()); allocatedHosts.set(latestModelVersion.getModel().allocatedHosts()); // Update with additional clusters allocated allApplicationVersions.add(latestModelVersion); } @@ -189,8 +188,7 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { applicationId, wantedDockerImageRepository, wantedNodeVespaVersion, - allocatedHosts.asOptional(), - now); + allocatedHosts.asOptional()); allocatedHosts.set(modelVersion.getModel().allocatedHosts()); // Update with additional clusters allocated allApplicationVersions.add(modelVersion); } catch (RuntimeException e) { @@ -245,8 +243,7 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { protected abstract MODELRESULT buildModelVersion(ModelFactory modelFactory, ApplicationPackage applicationPackage, ApplicationId applicationId, Optional<DockerImage> dockerImageRepository, - Version wantedNodeVespaVersion, Optional<AllocatedHosts> allocatedHosts, - Instant now); + Version wantedNodeVespaVersion, Optional<AllocatedHosts> allocatedHosts); /** * Returns a host provisioner returning the previously allocated hosts if available and when on hosted Vespa, diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java index e6d275fccdd..2397dba6b5e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java @@ -32,7 +32,6 @@ import com.yahoo.vespa.config.server.session.PrepareParams; import java.io.File; import java.io.IOException; -import java.time.Instant; import java.util.List; import java.util.Optional; import java.util.logging.Level; @@ -78,13 +77,12 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P } @Override - protected PreparedModelResult buildModelVersion(ModelFactory modelFactory, + protected PreparedModelResult buildModelVersion(ModelFactory modelFactory, ApplicationPackage applicationPackage, ApplicationId applicationId, Optional<DockerImage> wantedDockerImageRepository, Version wantedNodeVespaVersion, - Optional<AllocatedHosts> allocatedHosts, - Instant now) { + Optional<AllocatedHosts> allocatedHosts) { Version modelVersion = modelFactory.version(); log.log(Level.FINE, "Building model " + modelVersion + " for " + applicationId); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/monitoring/ZKMetricUpdater.java b/configserver/src/main/java/com/yahoo/vespa/config/server/monitoring/ZKMetricUpdater.java index 62da6fcffbe..52ca73c68b9 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/monitoring/ZKMetricUpdater.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/monitoring/ZKMetricUpdater.java @@ -14,8 +14,6 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/HostProvisionerProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/HostProvisionerProvider.java index eb14947f73f..13c21a065ff 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/HostProvisionerProvider.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/HostProvisionerProvider.java @@ -5,10 +5,8 @@ import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.component.ComponentId; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.config.provision.Provisioner; -import java.util.logging.Level; import java.util.Optional; -import java.util.logging.Logger; /** * This class is necessary to support both having and not having a host provisioner. We inject diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java index 307ec5c0c3c..6a681ae143d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java @@ -9,7 +9,6 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.ProvisionLogger; import com.yahoo.config.provision.Provisioner; -import com.yahoo.config.provision.NetworkPorts; import java.util.*; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java index 7809000695a..62f7d3ce5d0 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java @@ -3,10 +3,9 @@ package com.yahoo.vespa.config.server.rpc; import com.yahoo.cloud.config.SentinelConfig; import com.yahoo.collections.Pair; -import com.yahoo.config.provision.TenantName; import com.yahoo.component.Version; +import com.yahoo.config.provision.TenantName; import com.yahoo.jrt.Request; -import java.util.logging.Level; import com.yahoo.net.HostName; import com.yahoo.vespa.config.ConfigPayload; import com.yahoo.vespa.config.ErrorCode; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/DefaultRpcAuthorizerProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/DefaultRpcAuthorizerProvider.java index 5c760f0a25a..8d1d4f58e37 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/DefaultRpcAuthorizerProvider.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/DefaultRpcAuthorizerProvider.java @@ -8,8 +8,6 @@ import com.yahoo.container.di.componentgraph.Provider; import com.yahoo.security.tls.TransportSecurityUtils; import com.yahoo.vespa.config.server.host.HostRegistries; import com.yahoo.vespa.config.server.rpc.RequestHandlerProvider; -import com.yahoo.vespa.flags.FlagSource; -import com.yahoo.vespa.flags.Flags; /** * A provider for {@link RpcAuthorizer}. The instance provided is dependent on the configuration of the configserver. diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java index 9a5a45bc03b..4a2e7cb405b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java @@ -153,8 +153,6 @@ public class SessionPreparer { final DeployLogger logger; final PrepareParams params; - final Optional<ApplicationSet> currentActiveApplicationSet; - final Path tenantPath; final ApplicationId applicationId; /** The repository part of docker image to be used for this deployment */ @@ -187,8 +185,6 @@ public class SessionPreparer { SessionZooKeeperClient sessionZooKeeperClient) { this.logger = logger; this.params = params; - this.currentActiveApplicationSet = currentActiveApplicationSet; - this.tenantPath = tenantPath; this.applicationPackage = preprocessedApplicationPackage; this.sessionZooKeeperClient = sessionZooKeeperClient; this.applicationId = params.getApplicationId(); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java index 43b25826507..e2776dc382e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java @@ -12,9 +12,7 @@ import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.ReloadHandler; import com.yahoo.vespa.config.server.RequestHandler; import com.yahoo.vespa.config.server.application.TenantApplications; -import com.yahoo.vespa.config.server.host.HostValidator; import com.yahoo.vespa.config.server.monitoring.MetricUpdater; -import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; import com.yahoo.vespa.config.server.session.LocalSessionRepo; import com.yahoo.vespa.config.server.session.RemoteSessionRepo; import com.yahoo.vespa.config.server.session.SessionFactory; @@ -75,7 +73,7 @@ public class TenantRepository { private static final Logger log = Logger.getLogger(TenantRepository.class.getName()); private final Map<TenantName, Tenant> tenants = Collections.synchronizedMap(new LinkedHashMap<>()); - private final GlobalComponentRegistry globalComponentRegistry; + private final GlobalComponentRegistry componentRegistry; private final List<TenantListener> tenantListeners = Collections.synchronizedList(new ArrayList<>()); private final Curator curator; @@ -90,30 +88,30 @@ public class TenantRepository { /** * Creates a new tenant repository * - * @param globalComponentRegistry a {@link com.yahoo.vespa.config.server.GlobalComponentRegistry} + * @param componentRegistry a {@link com.yahoo.vespa.config.server.GlobalComponentRegistry} */ @Inject - public TenantRepository(GlobalComponentRegistry globalComponentRegistry) { - this(globalComponentRegistry, true); + public TenantRepository(GlobalComponentRegistry componentRegistry) { + this(componentRegistry, true); } /** * Creates a new tenant repository * - * @param globalComponentRegistry a {@link com.yahoo.vespa.config.server.GlobalComponentRegistry} + * @param componentRegistry a {@link com.yahoo.vespa.config.server.GlobalComponentRegistry} * @param useZooKeeperWatchForTenantChanges set to false for tests where you want to control adding and deleting * tenants yourself */ - public TenantRepository(GlobalComponentRegistry globalComponentRegistry, boolean useZooKeeperWatchForTenantChanges) { - this.globalComponentRegistry = globalComponentRegistry; - ConfigserverConfig configserverConfig = globalComponentRegistry.getConfigserverConfig(); + public TenantRepository(GlobalComponentRegistry componentRegistry, boolean useZooKeeperWatchForTenantChanges) { + this.componentRegistry = componentRegistry; + ConfigserverConfig configserverConfig = componentRegistry.getConfigserverConfig(); this.bootstrapExecutor = Executors.newFixedThreadPool(configserverConfig.numParallelTenantLoaders()); this.throwExceptionIfBootstrappingFails = configserverConfig.throwIfBootstrappingTenantRepoFails(); - this.curator = globalComponentRegistry.getCurator(); - metricUpdater = globalComponentRegistry.getMetrics().getOrCreateMetricUpdater(Collections.emptyMap()); - this.tenantListeners.add(globalComponentRegistry.getTenantListener()); - this.zkCacheExecutor = globalComponentRegistry.getZkCacheExecutor(); - this.zkWatcherExecutor = globalComponentRegistry.getZkWatcherExecutor(); + this.curator = componentRegistry.getCurator(); + metricUpdater = componentRegistry.getMetrics().getOrCreateMetricUpdater(Collections.emptyMap()); + this.tenantListeners.add(componentRegistry.getTenantListener()); + this.zkCacheExecutor = componentRegistry.getZkCacheExecutor(); + this.zkWatcherExecutor = componentRegistry.getZkWatcherExecutor(); curator.framework().getConnectionStateListenable().addListener(this::stateChanged); curator.create(tenantsPath); @@ -210,34 +208,21 @@ public class TenantRepository { private void createTenant(TenantName tenantName, RequestHandler requestHandler, ReloadHandler reloadHandler) { if (tenants.containsKey(tenantName)) return; - TenantRequestHandler tenantRequestHandler = null; - if (requestHandler == null) { - tenantRequestHandler = new TenantRequestHandler(globalComponentRegistry.getMetrics(), - tenantName, - List.of(globalComponentRegistry.getReloadListener()), - ConfigResponseFactory.create(globalComponentRegistry.getConfigserverConfig()), - globalComponentRegistry); - requestHandler = tenantRequestHandler; - } - - if (reloadHandler == null && tenantRequestHandler != null) - reloadHandler = tenantRequestHandler; - - HostValidator<ApplicationId> hostValidator = tenantRequestHandler; - TenantApplications applicationRepo = TenantApplications.create(globalComponentRegistry, - reloadHandler, - tenantName); - - SessionFactory sessionFactory = new SessionFactory(globalComponentRegistry, applicationRepo, hostValidator, tenantName); - LocalSessionRepo localSessionRepo = new LocalSessionRepo(tenantName, globalComponentRegistry, sessionFactory); - RemoteSessionRepo remoteSessionRepo = new RemoteSessionRepo(globalComponentRegistry, + TenantApplications applicationRepo = TenantApplications.create(componentRegistry, tenantName); + if (requestHandler == null) + requestHandler = applicationRepo; + if (reloadHandler == null) + reloadHandler = applicationRepo; + SessionFactory sessionFactory = new SessionFactory(componentRegistry, applicationRepo, applicationRepo, tenantName); + LocalSessionRepo localSessionRepo = new LocalSessionRepo(tenantName, componentRegistry, sessionFactory); + RemoteSessionRepo remoteSessionRepo = new RemoteSessionRepo(componentRegistry, sessionFactory, reloadHandler, tenantName, applicationRepo); log.log(Level.INFO, "Creating tenant '" + tenantName + "'"); - Tenant tenant = new Tenant(tenantName, sessionFactory, localSessionRepo, remoteSessionRepo, requestHandler, - reloadHandler, applicationRepo, globalComponentRegistry.getCurator()); + Tenant tenant = new Tenant(tenantName, sessionFactory, localSessionRepo, remoteSessionRepo, requestHandler, + reloadHandler, applicationRepo, componentRegistry.getCurator()); notifyNewTenant(tenant); tenants.putIfAbsent(tenantName, tenant); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java deleted file mode 100644 index 25d6f194fdc..00000000000 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.config.server.tenant; - -import com.yahoo.component.Version; -import com.yahoo.config.FileReference; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.TenantName; -import com.yahoo.vespa.config.ConfigKey; -import com.yahoo.vespa.config.GetConfigRequest; -import com.yahoo.vespa.config.protocol.ConfigResponse; -import com.yahoo.vespa.config.server.GlobalComponentRegistry; -import com.yahoo.vespa.config.server.NotFoundException; -import com.yahoo.vespa.config.server.ReloadHandler; -import com.yahoo.vespa.config.server.ReloadListener; -import com.yahoo.vespa.config.server.RequestHandler; -import com.yahoo.vespa.config.server.application.Application; -import com.yahoo.vespa.config.server.application.ApplicationMapper; -import com.yahoo.vespa.config.server.application.ApplicationSet; -import com.yahoo.vespa.config.server.application.TenantApplications; -import com.yahoo.vespa.config.server.application.VersionDoesNotExistException; -import com.yahoo.vespa.config.server.host.HostRegistry; -import com.yahoo.vespa.config.server.host.HostValidator; -import com.yahoo.vespa.config.server.monitoring.MetricUpdater; -import com.yahoo.vespa.config.server.monitoring.Metrics; -import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; -import com.yahoo.vespa.curator.Lock; - -import java.time.Clock; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.logging.Level; - -import static java.util.stream.Collectors.toSet; - -/** - * A per tenant request handler, for handling reload (activate application) and getConfig requests for - * a set of applications belonging to a tenant. - * - * @author Harald Musum - */ -public class TenantRequestHandler implements RequestHandler, ReloadHandler, HostValidator<ApplicationId> { - - private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TenantRequestHandler.class.getName()); - - private final Metrics metrics; - private final TenantName tenant; - private final List<ReloadListener> reloadListeners; - private final ConfigResponseFactory responseFactory; - private final HostRegistry<ApplicationId> hostRegistry; - private final ApplicationMapper applicationMapper = new ApplicationMapper(); - private final MetricUpdater tenantMetricUpdater; - private final Clock clock = Clock.systemUTC(); - private final TenantApplications applications; - - public TenantRequestHandler(Metrics metrics, - TenantName tenant, - List<ReloadListener> reloadListeners, - ConfigResponseFactory responseFactory, - GlobalComponentRegistry registry) { // TODO jvenstad: Merge this class with TenantApplications, and straighten this out. - this.metrics = metrics; - this.tenant = tenant; - this.reloadListeners = List.copyOf(reloadListeners); - this.responseFactory = responseFactory; - this.tenantMetricUpdater = metrics.getOrCreateMetricUpdater(Metrics.createDimensions(tenant)); - this.hostRegistry = registry.getHostRegistries().createApplicationHostRegistry(tenant); - this.applications = TenantApplications.create(registry, this, tenant); - - } - - /** - * Gets a config for the given app, or null if not found - */ - @Override - public ConfigResponse resolveConfig(ApplicationId appId, GetConfigRequest req, Optional<Version> vespaVersion) { - Application application = getApplication(appId, vespaVersion); - if (log.isLoggable(Level.FINE)) { - log.log(Level.FINE, TenantRepository.logPre(appId) + "Resolving for tenant '" + tenant + "' with handler for application '" + application + "'"); - } - return application.resolveConfig(req, responseFactory); - } - - // For testing only - long getApplicationGeneration(ApplicationId appId, Optional<Version> vespaVersion) { - Application application = getApplication(appId, vespaVersion); - return application.getApplicationGeneration(); - } - - private void notifyReloadListeners(ApplicationSet applicationSet) { - for (ReloadListener reloadListener : reloadListeners) { - reloadListener.hostsUpdated(tenant, hostRegistry.getAllHosts()); - reloadListener.configActivated(applicationSet); - } - } - - /** - * Activates the config of the given app. Notifies listeners - * - * @param applicationSet the {@link ApplicationSet} to be reloaded - */ - @Override - public void reloadConfig(ApplicationSet applicationSet) { - ApplicationId id = applicationSet.getId(); - try (Lock lock = applications.lock(id)) { - if ( ! applications.exists(id)) - return; // Application was deleted before activation. - if (applicationSet.getApplicationGeneration() != applications.requireActiveSessionOf(id)) - return; // Application activated a new session before we got here. - - setLiveApp(applicationSet); - notifyReloadListeners(applicationSet); - } - } - - @Override - public void removeApplication(ApplicationId applicationId) { - try (Lock lock = applications.lock(applicationId)) { - if (applications.exists(applicationId)) - return; // Application was deployed again. - - if (applicationMapper.hasApplication(applicationId, clock.instant())) { - applicationMapper.remove(applicationId); - hostRegistry.removeHostsForKey(applicationId); - reloadListenersOnRemove(applicationId); - tenantMetricUpdater.setApplications(applicationMapper.numApplications()); - metrics.removeMetricUpdater(Metrics.createDimensions(applicationId)); - } - } - } - - @Override - public void removeApplicationsExcept(Set<ApplicationId> applications) { - for (ApplicationId activeApplication : applicationMapper.listApplicationIds()) { - if ( ! applications.contains(activeApplication)) { - log.log(Level.INFO, "Will remove deleted application " + activeApplication.toShortString()); - removeApplication(activeApplication); - } - } - } - - private void reloadListenersOnRemove(ApplicationId applicationId) { - for (ReloadListener listener : reloadListeners) { - listener.hostsUpdated(tenant, hostRegistry.getAllHosts()); - listener.applicationRemoved(applicationId); - } - } - - private void setLiveApp(ApplicationSet applicationSet) { - ApplicationId id = applicationSet.getId(); - Collection<String> hostsForApp = applicationSet.getAllHosts(); - hostRegistry.update(id, hostsForApp); - applicationSet.updateHostMetrics(); - tenantMetricUpdater.setApplications(applicationMapper.numApplications()); - applicationMapper.register(id, applicationSet); - } - - @Override - public Set<ConfigKey<?>> listNamedConfigs(ApplicationId appId, Optional<Version> vespaVersion, ConfigKey<?> keyToMatch, boolean recursive) { - Application application = getApplication(appId, vespaVersion); - return listConfigs(application, keyToMatch, recursive); - } - - private Set<ConfigKey<?>> listConfigs(Application application, ConfigKey<?> keyToMatch, boolean recursive) { - Set<ConfigKey<?>> ret = new LinkedHashSet<>(); - for (ConfigKey<?> key : application.allConfigsProduced()) { - String configId = key.getConfigId(); - if (recursive) { - key = new ConfigKey<>(key.getName(), configId, key.getNamespace()); - } else { - // Include first part of id as id - key = new ConfigKey<>(key.getName(), configId.split("/")[0], key.getNamespace()); - } - if (keyToMatch != null) { - String n = key.getName(); // Never null - String ns = key.getNamespace(); // Never null - if (n.equals(keyToMatch.getName()) && - ns.equals(keyToMatch.getNamespace()) && - configId.startsWith(keyToMatch.getConfigId()) && - !(configId.equals(keyToMatch.getConfigId()))) { - - if (!recursive) { - // For non-recursive, include the id segment we were searching for, and first part of the rest - key = new ConfigKey<>(key.getName(), appendOneLevelOfId(keyToMatch.getConfigId(), configId), key.getNamespace()); - } - ret.add(key); - } - } else { - ret.add(key); - } - } - return ret; - } - - @Override - public Set<ConfigKey<?>> listConfigs(ApplicationId appId, Optional<Version> vespaVersion, boolean recursive) { - Application application = getApplication(appId, vespaVersion); - return listConfigs(application, null, recursive); - } - - /** - * Given baseIdSegment search/ and id search/qrservers/default.0, return search/qrservers - * @return id segment with one extra level from the id appended - */ - String appendOneLevelOfId(String baseIdSegment, String id) { - if ("".equals(baseIdSegment)) return id.split("/")[0]; - String theRest = id.substring(baseIdSegment.length()); - if ("".equals(theRest)) return id; - theRest = theRest.replaceFirst("/", ""); - String theRestFirstSeg = theRest.split("/")[0]; - return baseIdSegment+"/"+theRestFirstSeg; - } - - @Override - public Set<ConfigKey<?>> allConfigsProduced(ApplicationId appId, Optional<Version> vespaVersion) { - Application application = getApplication(appId, vespaVersion); - return application.allConfigsProduced(); - } - - private Application getApplication(ApplicationId appId, Optional<Version> vespaVersion) { - try { - return applicationMapper.getForVersion(appId, vespaVersion, clock.instant()); - } catch (VersionDoesNotExistException ex) { - throw new NotFoundException(String.format("%sNo such application (id %s): %s", TenantRepository.logPre(tenant), appId, ex.getMessage())); - } - } - - @Override - public Set<String> allConfigIds(ApplicationId appId, Optional<Version> vespaVersion) { - Application application = getApplication(appId, vespaVersion); - return application.allConfigIds(); - } - - @Override - public boolean hasApplication(ApplicationId appId, Optional<Version> vespaVersion) { - return hasHandler(appId, vespaVersion); - } - - private boolean hasHandler(ApplicationId appId, Optional<Version> vespaVersion) { - return applicationMapper.hasApplicationForVersion(appId, vespaVersion, clock.instant()); - } - - @Override - public ApplicationId resolveApplicationId(String hostName) { - ApplicationId applicationId = hostRegistry.getKeyForHost(hostName); - if (applicationId == null) { - applicationId = ApplicationId.defaultId(); - } - return applicationId; - } - - @Override - public Set<FileReference> listFileReferences(ApplicationId applicationId) { - return applicationMapper.listApplications(applicationId).stream() - .flatMap(app -> app.getModel().fileReferences().stream()) - .collect(toSet()); - } - - @Override - public void verifyHosts(ApplicationId key, Collection<String> newHosts) { - hostRegistry.verifyHosts(key, newHosts); - for (ReloadListener reloadListener : reloadListeners) { - reloadListener.verifyHostsAreAvailable(tenant, newHosts); - } - } - - TenantApplications applications() { return applications; } - -} diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ConfigCurator.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ConfigCurator.java index f3f9c914be8..35e8b0917cf 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ConfigCurator.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ConfigCurator.java @@ -111,11 +111,6 @@ public class ConfigCurator { return (data == null) ? null : Utf8.toString(data); } - /** Returns the data at a path and node. Replaces / by # in node names. Returns null if the path doesn't exist. */ - public byte[] getBytes(String path, String node) { - return getBytes(createFullPath(path, node)); - } - /** * Returns the data at a path, or null if the path does not exist. * |