diff options
Diffstat (limited to 'configserver')
37 files changed, 297 insertions, 303 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 c2c42054109..78a4d71158f 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 @@ -6,13 +6,13 @@ import ai.vespa.http.HttpURL; import ai.vespa.http.HttpURL.Query; import ai.vespa.http.HttpURL.Scheme; import com.yahoo.cloud.config.ConfigserverConfig; +import com.yahoo.collections.Pair; import com.yahoo.component.Version; import com.yahoo.component.annotation.Inject; import com.yahoo.config.FileReference; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.config.application.api.ApplicationMetaData; import com.yahoo.config.application.api.DeployLogger; -import com.yahoo.config.model.api.HostInfo; import com.yahoo.config.model.api.ServiceInfo; import com.yahoo.config.provision.ActivationContext; import com.yahoo.config.provision.ApplicationId; @@ -70,6 +70,7 @@ import com.yahoo.vespa.config.server.deploy.DeployHandlerLogger; import com.yahoo.vespa.config.server.deploy.Deployment; import com.yahoo.vespa.config.server.deploy.InfraDeployerProvider; import com.yahoo.vespa.config.server.filedistribution.FileDirectory; +import com.yahoo.vespa.config.server.http.HttpErrorResponse; import com.yahoo.vespa.config.server.http.InternalServerException; import com.yahoo.vespa.config.server.http.LogRetriever; import com.yahoo.vespa.config.server.http.SecretStoreValidator; @@ -101,6 +102,7 @@ import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.orchestrator.Orchestrator; +import com.yahoo.yolean.Exceptions; import java.io.File; import java.io.IOException; @@ -111,7 +113,6 @@ import java.nio.file.attribute.BasicFileAttributes; import java.time.Clock; import java.time.Duration; import java.time.Instant; -import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -774,10 +775,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } public List<Version> getAllVersions(ApplicationId applicationId) { - Optional<ApplicationVersions> applicationSet = getActiveApplicationSet(applicationId); - return applicationSet.isEmpty() - ? List.of() - : applicationSet.get().versions(applicationId); + return getActiveApplicationVersions(applicationId).map(ApplicationVersions::versions).orElse(List.of()); } public HttpResponse validateSecretStore(ApplicationId applicationId, SystemName systemName, Slime slime) { @@ -812,8 +810,16 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye // ---------------- Logs ---------------------------------------------------------------- public HttpResponse getLogs(ApplicationId applicationId, Optional<DomainName> hostname, Query apiParams) { - HttpURL logServerURI = getLogServerURI(applicationId, hostname).withQuery(apiParams); - return logRetriever.getLogs(logServerURI, activationTime(applicationId)); + Exception exception = null; + for (var uri : getLogServerUris(applicationId, hostname)) { + try { + return logRetriever.getLogs(uri.withQuery(apiParams), activationTime(applicationId)); + } catch (RuntimeException e) { + exception = e; + log.log(Level.INFO, e.getMessage()); + } + } + return HttpErrorResponse.internalServerError(Exceptions.toMessageString(exception)); } // ---------------- Methods to do call against tester containers in hosted ------------------------------ @@ -899,15 +905,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye * @return the active session, or null if there is no active session for the given application id. */ public Optional<Session> getActiveSession(ApplicationId applicationId) { - return getActiveRemoteSession(applicationId); - } - - /** - * Gets the active Session for the given application id. - * - * @return the active session, or null if there is no active session for the given application id. - */ - public Optional<Session> getActiveRemoteSession(ApplicationId applicationId) { Tenant tenant = getTenant(applicationId); if (tenant == null) throw new IllegalArgumentException("Could not find any tenant for '" + applicationId + "'"); return getActiveSession(tenant, applicationId); @@ -915,15 +912,12 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye public long getSessionIdForApplication(ApplicationId applicationId) { Tenant tenant = getTenant(applicationId); - if (tenant == null) throw new NotFoundException("Tenant '" + applicationId.tenant() + "' not found"); - return getSessionIdForApplication(tenant, applicationId); - } - - private long getSessionIdForApplication(Tenant tenant, ApplicationId applicationId) { - TenantApplications applicationRepo = tenant.getApplicationRepo(); - if (! applicationRepo.exists(applicationId)) + if (tenant == null) + throw new NotFoundException("Tenant '" + applicationId.tenant() + "' not found"); + if (! tenant.getApplicationRepo().exists(applicationId)) throw new NotFoundException("Unknown application id '" + applicationId + "'"); - return applicationRepo.requireActiveSessionOf(applicationId); + + return requireActiveSession(tenant, applicationId).getSessionId(); } public void validateThatSessionIsNotActive(Tenant tenant, long sessionId) { @@ -944,7 +938,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye DeployLogger deployLogger) { Tenant tenant = getTenant(applicationId); SessionRepository sessionRepository = tenant.getSessionRepository(); - Session fromSession = getExistingSession(tenant, applicationId); + Session fromSession = requireActiveSession(tenant, applicationId); return sessionRepository.createSessionFromExisting(fromSession, internalRedeploy, timeoutBudget, deployLogger).getSessionId(); } @@ -972,10 +966,10 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - public int deleteExpiredRemoteSessions(Clock clock) { + public int deleteExpiredRemoteSessions() { return tenantRepository.getAllTenants() .stream() - .map(tenant -> tenant.getSessionRepository().deleteExpiredRemoteSessions(clock, session -> sessionIsActiveForItsApplication(tenant, session))) + .map(tenant -> tenant.getSessionRepository().deleteExpiredRemoteSessions(session -> sessionIsActiveForItsApplication(tenant, session))) .mapToInt(i -> i) .sum(); } @@ -1103,7 +1097,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye return session; } - public Optional<ApplicationVersions> getActiveApplicationSet(ApplicationId appId) { + public Optional<ApplicationVersions> getActiveApplicationVersions(ApplicationId appId) { return getTenant(appId).getSessionRepository().activeApplicationVersions(appId); } @@ -1130,10 +1124,9 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - // TODO: Merge this and getActiveSession(), they are almost identical - private Session getExistingSession(Tenant tenant, ApplicationId applicationId) { - TenantApplications applicationRepo = tenant.getApplicationRepo(); - return getRemoteSession(tenant, applicationRepo.requireActiveSessionOf(applicationId)); + private Session requireActiveSession(Tenant tenant, ApplicationId applicationId) { + return getActiveSession(tenant, applicationId) + .orElseThrow(() -> new IllegalArgumentException("Application '" + applicationId + "' has no active session.")); } public Optional<Session> getActiveSession(Tenant tenant, ApplicationId applicationId) { @@ -1185,33 +1178,41 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - private HttpURL getLogServerURI(ApplicationId applicationId, Optional<DomainName> hostname) { + private List<HttpURL> getLogServerUris(ApplicationId applicationId, Optional<DomainName> hostname) { // Allow to get logs from a given hostname if the application is under the hosted-vespa tenant. // We make no validation that the hostname is actually allocated to the given application since // most applications under hosted-vespa are not known to the model, and it's OK for a user to get // logs for any host if they are authorized for the hosted-vespa tenant. if (hostname.isPresent() && HOSTED_VESPA_TENANT.equals(applicationId.tenant())) { int port = List.of(InfrastructureApplication.CONFIG_SERVER.id(), InfrastructureApplication.CONTROLLER.id()).contains(applicationId) ? 19071 : 8080; - return HttpURL.create(Scheme.http, hostname.get(), port).withPath(HttpURL.Path.empty().append("logs")); + return List.of(HttpURL.create(Scheme.http, hostname.get(), port).withPath(HttpURL.Path.parse("logs"))); } - Application application = getApplication(applicationId); - Collection<HostInfo> hostInfos = application.getModel().getHosts(); + ApplicationVersions applicationVersions = getActiveApplicationVersions(applicationId) + .orElseThrow(() -> new NotFoundException("Unable to get logs for for " + applicationId + " (application not found)")); + List<Pair<String, Integer>> hostInfo = logserverHostInfo(applicationVersions); + return hostInfo.stream() + .map(h -> HttpURL.create(Scheme.http, DomainName.of(h.getFirst()), h.getSecond(), HttpURL.Path.parse("logs"))) + .toList(); + } - HostInfo logServerHostInfo = hostInfos.stream() - .filter(host -> host.getServices().stream() + // Returns a list with hostname and port pairs for logserver container for all models/versions + private List<Pair<String, Integer>> logserverHostInfo(ApplicationVersions applicationVersions) { + return applicationVersions.applications().stream() + .peek(app -> log.log(Level.FINE, "Finding logserver host and port for version " + app.getVespaVersion())) + .map(Application::getModel) + .flatMap(model -> model.getHosts().stream()) + .filter(hostInfo -> hostInfo.getServices().stream() .anyMatch(serviceInfo -> serviceInfo.getServiceType().equalsIgnoreCase("logserver"))) - .findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find host info for logserver")); - - ServiceInfo logService = logServerHostInfo.getServices().stream() - .filter(service -> LOGSERVER_CONTAINER.serviceName.equals(service.getServiceType())) - .findFirst() - .or(() -> logServerHostInfo.getServices().stream() - .filter(service -> CONTAINER.serviceName.equals(service.getServiceType())) - .findFirst()) - .orElseThrow(() -> new IllegalArgumentException("No container running on logserver host")); - int port = servicePort(logService); - return HttpURL.create(Scheme.http, DomainName.of(logServerHostInfo.getHostname()), port, HttpURL.Path.empty().append("logs")); + .map(hostInfo -> hostInfo.getServices().stream() + .filter(service -> LOGSERVER_CONTAINER.serviceName.equals(service.getServiceType())) + .findFirst() + .or(() -> hostInfo.getServices().stream() + .filter(service -> CONTAINER.serviceName.equals(service.getServiceType())) + .findFirst()) + .orElseThrow(() -> new IllegalArgumentException("No container running on logserver host"))) + .map(s -> new Pair<>(s.getHostName(), servicePort(s))) + .toList(); } private int servicePort(ServiceInfo serviceInfo) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java index c5204f5690f..6d0f0e3af68 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelManager.java @@ -1,5 +1,4 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - package com.yahoo.vespa.config.server; import com.yahoo.component.annotation.Inject; @@ -13,7 +12,6 @@ import com.yahoo.config.provision.Zone; import com.yahoo.vespa.config.GenerationCounter; import com.yahoo.vespa.config.server.application.ApplicationVersions; import com.yahoo.vespa.config.server.model.SuperModelConfigProvider; -import com.yahoo.vespa.flags.FlagSource; import java.time.Instant; import java.util.ArrayList; @@ -33,7 +31,6 @@ public class SuperModelManager implements SuperModelProvider { private final Zone zone; private final Object monitor = new Object(); - private final FlagSource flagSource; private SuperModelConfigProvider superModelConfigProvider; // Guarded by 'this' monitor private final List<SuperModelListener> listeners = new ArrayList<>(); // Guarded by 'this' monitor @@ -46,11 +43,7 @@ public class SuperModelManager implements SuperModelProvider { private final Optional<Set<ApplicationId>> bootstrapApplicationSet = Optional.empty(); @Inject - public SuperModelManager(ConfigserverConfig configserverConfig, - Zone zone, - GenerationCounter generationCounter, - FlagSource flagSource) { - this.flagSource = flagSource; + public SuperModelManager(ConfigserverConfig configserverConfig, Zone zone, GenerationCounter generationCounter) { this.zone = zone; this.generationCounter = generationCounter; this.masterGeneration = configserverConfig.masterGeneration(); @@ -123,12 +116,12 @@ public class SuperModelManager implements SuperModelProvider { // there is no need to bump generation counter. logger.log(Level.FINE, "Super model is complete"); SuperModel newSuperModel = getSuperModel().cloneAsComplete(); - superModelConfigProvider = new SuperModelConfigProvider(newSuperModel, zone, flagSource); + superModelConfigProvider = new SuperModelConfigProvider(newSuperModel, zone); listeners.forEach(listener -> listener.notifyOfCompleteness(newSuperModel)); } private void makeNewSuperModelConfigProvider(SuperModel newSuperModel) { generation = masterGeneration + generationCounter.get(); - superModelConfigProvider = new SuperModelConfigProvider(newSuperModel, zone, flagSource); + superModelConfigProvider = new SuperModelConfigProvider(newSuperModel, zone); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java index ccf8f7d50ea..b39377eb30d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java @@ -30,10 +30,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Phaser; import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER; -import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER; import static com.yahoo.slime.SlimeUtils.entriesStream; import static com.yahoo.slime.SlimeUtils.jsonToSlime; -import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; /** @@ -57,8 +55,7 @@ public class ActiveTokenFingerprintsClient implements ActiveTokenFingerprints, A return getFingerprints(application.getModel().getHosts().stream() .filter(host -> containersWithTokenFilter.contains(host.getHostname())) .flatMap(host -> host.getServices().stream()) - .filter(service -> service.getServiceType().equals(CONTAINER.serviceName) - || service.getServiceType().equals(QRSERVER.serviceName)) + .filter(service -> service.getServiceType().equals(CONTAINER.serviceName)) .toList()); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationVersions.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationVersions.java index 458815c500b..553a82f11e4 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationVersions.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationVersions.java @@ -12,7 +12,8 @@ import java.util.List; import java.util.Optional; /** - * Immutable set of {@link Application}s with the same {@link ApplicationId}, applications have difference vespa versions. + * Immutable set of {@link Application}s with the same {@link ApplicationId}, + * applications have different vespa versions. There will always be at least one application version. * * @author vegard */ @@ -24,23 +25,17 @@ public final class ApplicationVersions { private final HashMap<Version, Application> applications = new HashMap<>(); private ApplicationVersions(List<Application> applications) { - if (applications.isEmpty()) throw new IllegalArgumentException("application list cannot be empty"); + if (applications.isEmpty()) + throw new IllegalArgumentException("application list cannot be empty"); + if (applications.stream().map(Application::getId).distinct().count() > 1) + throw new IllegalArgumentException("All application ids must be equal"); + if (applications.stream().map(Application::getApplicationGeneration).distinct().count() > 1) + throw new IllegalArgumentException("All config generations must be equal"); Application firstApp = applications.get(0); applicationId = firstApp.getId(); generation = firstApp.getApplicationGeneration(); - for (Application application : applications) { - this.applications.put(application.getVespaVersion(), application); - ApplicationId applicationId = application.getId(); - if ( ! applicationId.equals(this.applicationId)) { - throw new IllegalArgumentException("Trying to create set with different application ids (" + - application + " and " + this.applicationId + ")"); - } - if ( ! application.getApplicationGeneration().equals(generation)) { - throw new IllegalArgumentException("Trying to create set with different generations (" + - generation + " and " + this.generation + ")"); - } - } + applications.forEach(application -> this.applications.put(application.getVespaVersion(), application)); latestVersion = this.applications.keySet().stream().max(Version::compareTo).get(); } @@ -71,7 +66,7 @@ public final class ApplicationVersions { if (application != null) return Optional.of(application); - // Does the latest version specify we can use it regardless? + // Does the latest version specify that we can use it regardless? Application latest = applications.get(latestVersion); if (latest.getModel().allowModelVersionMismatch(now)) return Optional.of(latest); @@ -90,6 +85,7 @@ public final class ApplicationVersions { return applications.values().stream() .flatMap(app -> app.getModel().getHosts().stream() .map(HostInfo::getHostname)) + .distinct() .toList(); } @@ -101,13 +97,12 @@ public final class ApplicationVersions { return generation; } - List<Application> applications() { + public List<Application> applications() { return new ArrayList<>(applications.values()); } - public List<Version> versions(ApplicationId applicationId) { + public List<Version> versions() { return applications.values().stream() - .filter(application -> application.getId().equals(applicationId)) .map(Application::getVespaVersion) .sorted() .toList(); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java index c03cb7ade8c..0ba68cd71d2 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java @@ -52,7 +52,6 @@ import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERC import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER; import static com.yahoo.config.model.api.container.ContainerServiceType.LOGSERVER_CONTAINER; import static com.yahoo.config.model.api.container.ContainerServiceType.METRICS_PROXY_CONTAINER; -import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER; /** * Checks for convergence of config generation for a given application. @@ -67,7 +66,6 @@ public class ConfigConvergenceChecker extends AbstractComponent { private final static Set<String> serviceTypesToCheck = Set.of( CONTAINER.serviceName, - QRSERVER.serviceName, LOGSERVER_CONTAINER.serviceName, CLUSTERCONTROLLER_CONTAINER.serviceName, METRICS_PROXY_CONTAINER.serviceName, @@ -151,7 +149,7 @@ public class ConfigConvergenceChecker extends AbstractComponent { } private boolean isNotContainer(ServiceInfo serviceInfo) { - return ! List.of(CONTAINER.serviceName, QRSERVER.serviceName, METRICS_PROXY_CONTAINER).contains(serviceInfo.getServiceType()); + return ! List.of(CONTAINER.serviceName, METRICS_PROXY_CONTAINER).contains(serviceInfo.getServiceType()); } // Don't check service in a cluster which uses restartOnDeploy (new config will not be used until service is restarted) @@ -285,7 +283,7 @@ public class ConfigConvergenceChecker extends AbstractComponent { private static RequestConfig createRequestConfig(Duration timeout) { return RequestConfig.custom() - .setConnectionRequestTimeout(Timeout.ofSeconds(1)) + .setConnectionRequestTimeout(Timeout.ofSeconds(10)) .setResponseTimeout(Timeout.ofMilliseconds(timeout.toMillis())) .build(); } @@ -298,7 +296,7 @@ public class ConfigConvergenceChecker extends AbstractComponent { .setMaxConnPerRoute(10) .setDefaultConnectionConfig(ConnectionConfig.custom() .setTimeToLive(TimeValue.ofMilliseconds(1)) - .setConnectTimeout(Timeout.ofSeconds(1)) + .setConnectTimeout(Timeout.ofSeconds(10)) // Times out at 1s over wireguard with 500+ services. .build()) .setTlsStrategy(tlsStrategy) .build()) 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 b83a8290cac..7b31b77d43c 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 @@ -242,10 +242,7 @@ public class TenantApplications implements RequestHandler, HostValidator { } private void notifyConfigActivationListeners(ApplicationVersions applicationVersions) { - List<Application> applications = applicationVersions.applications(); - if (applications.isEmpty()) throw new IllegalArgumentException("application set cannot be empty"); - - hostRegistry.update(applications.get(0).getId(), applicationVersions.allHosts()); + hostRegistry.update(applicationVersions.getId(), applicationVersions.allHosts()); configActivationListener.configActivated(applicationVersions); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 1c285270cb1..4b86d8834b9 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -180,7 +180,6 @@ public class ModelContextImpl implements ModelContext { private final double feedNiceness; private final List<String> allowedAthenzProxyIdentities; private final int maxActivationInhibitedOutOfSyncGroups; - private final Predicate<ClusterSpec.Type> jvmOmitStackTraceInFastThrow; private final double resourceLimitDisk; private final double resourceLimitMemory; private final double minNodeRatioPerGroup; @@ -213,6 +212,9 @@ public class ModelContextImpl implements ModelContext { private final boolean logserverOtelCol; private final SharedHosts sharedHosts; private final Architecture adminClusterArchitecture; + private final boolean symmetricPutAndActivateReplicaSelection; + private final boolean enforceStrictlyIncreasingClusterStateVersions; + private final boolean launchApplicationAthenzService; public FeatureFlags(FlagSource source, ApplicationId appId, Version version) { this.defaultTermwiseLimit = Flags.DEFAULT_TERM_WISE_LIMIT.bindTo(source).with(appId).with(version).value(); @@ -225,7 +227,6 @@ public class ModelContextImpl implements ModelContext { this.mbus_network_threads = Flags.MBUS_NUM_NETWORK_THREADS.bindTo(source).with(appId).with(version).value(); this.allowedAthenzProxyIdentities = Flags.ALLOWED_ATHENZ_PROXY_IDENTITIES.bindTo(source).with(appId).with(version).value(); this.maxActivationInhibitedOutOfSyncGroups = Flags.MAX_ACTIVATION_INHIBITED_OUT_OF_SYNC_GROUPS.bindTo(source).with(appId).with(version).value(); - this.jvmOmitStackTraceInFastThrow = type -> PermanentFlags.JVM_OMIT_STACK_TRACE_IN_FAST_THROW.bindTo(source).with(appId).with(version).with(type).value(); this.resourceLimitDisk = PermanentFlags.RESOURCE_LIMIT_DISK.bindTo(source).with(appId).with(version).value(); this.resourceLimitMemory = PermanentFlags.RESOURCE_LIMIT_MEMORY.bindTo(source).with(appId).with(version).value(); this.minNodeRatioPerGroup = Flags.MIN_NODE_RATIO_PER_GROUP.bindTo(source).with(appId).with(version).value(); @@ -259,6 +260,9 @@ public class ModelContextImpl implements ModelContext { this.logserverOtelCol = Flags.LOGSERVER_OTELCOL_AGENT.bindTo(source).with(appId).with(version).value(); this.sharedHosts = PermanentFlags.SHARED_HOST.bindTo(source).with( appId).with(version).value(); this.adminClusterArchitecture = Architecture.valueOf(PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(source).with(appId).with(version).value()); + this.symmetricPutAndActivateReplicaSelection = Flags.SYMMETRIC_PUT_AND_ACTIVATE_REPLICA_SELECTION.bindTo(source).with(appId).with(version).value(); + this.enforceStrictlyIncreasingClusterStateVersions = Flags.ENFORCE_STRICTLY_INCREASING_CLUSTER_STATE_VERSIONS.bindTo(source).with(appId).with(version).value(); + this.launchApplicationAthenzService = Flags.LAUNCH_APPLICATION_ATHENZ_SERVICE.bindTo(source).with(appId).with(version).value(); } @Override public int heapSizePercentage() { return heapPercentage; } @@ -275,9 +279,6 @@ public class ModelContextImpl implements ModelContext { @Override public int mbusNetworkThreads() { return mbus_network_threads; } @Override public List<String> allowedAthenzProxyIdentities() { return allowedAthenzProxyIdentities; } @Override public int maxActivationInhibitedOutOfSyncGroups() { return maxActivationInhibitedOutOfSyncGroups; } - @Override public String jvmOmitStackTraceInFastThrowOption(ClusterSpec.Type type) { - return translateJvmOmitStackTraceInFastThrowToString(jvmOmitStackTraceInFastThrow, type); - } @Override public double resourceLimitDisk() { return resourceLimitDisk; } @Override public double resourceLimitMemory() { return resourceLimitMemory; } @Override public double minNodeRatioPerGroup() { return minNodeRatioPerGroup; } @@ -313,12 +314,8 @@ public class ModelContextImpl implements ModelContext { @Override public boolean logserverOtelCol() { return logserverOtelCol; } @Override public SharedHosts sharedHosts() { return sharedHosts; } @Override public Architecture adminClusterArchitecture() { return adminClusterArchitecture; } - - private String translateJvmOmitStackTraceInFastThrowToString(Predicate<ClusterSpec.Type> function, - ClusterSpec.Type clusterType) { - return function.test(clusterType) ? "" : "-XX:-OmitStackTraceInFastThrow"; - } - + @Override public boolean symmetricPutAndActivateReplicaSelection() { return symmetricPutAndActivateReplicaSelection; } + @Override public boolean enforceStrictlyIncreasingClusterStateVersions() { return enforceStrictlyIncreasingClusterStateVersions; } } public static class Properties implements ModelContext.Properties { @@ -350,6 +347,8 @@ public class ModelContextImpl implements ModelContext { private final List<DataplaneToken> dataplaneTokens; private final boolean allowUserFilters; private final Duration endpointConnectionTtl; + private final List<String> requestPrefixForLoggingContent; + private final boolean launchApplicationAthenzService; public Properties(ApplicationId applicationId, Version modelVersion, @@ -396,6 +395,8 @@ public class ModelContextImpl implements ModelContext { this.allowUserFilters = PermanentFlags.ALLOW_USER_FILTERS.bindTo(flagSource).with(applicationId).value(); this.endpointConnectionTtl = Duration.ofSeconds(PermanentFlags.ENDPOINT_CONNECTION_TTL.bindTo(flagSource).with(applicationId).value()); this.dataplaneTokens = dataplaneTokens; + this.requestPrefixForLoggingContent = PermanentFlags.LOG_REQUEST_CONTENT.bindTo(flagSource).with(applicationId).value(); + this.launchApplicationAthenzService = Flags.LAUNCH_APPLICATION_ATHENZ_SERVICE.bindTo(flagSource).with(applicationId).value(); } @Override public ModelContext.FeatureFlags featureFlags() { return featureFlags; } @@ -493,5 +494,10 @@ public class ModelContextImpl implements ModelContext { @Override public boolean allowUserFilters() { return allowUserFilters; } @Override public Duration endpointConnectionTtl() { return endpointConnectionTtl; } + + @Override public List<String> requestPrefixForLoggingContent() { return requestPrefixForLoggingContent; } + + @Override public boolean launchApplicationAthenzService() { return launchApplicationAthenzService; } } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperDeployer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperDeployer.java index a634519dd0a..adfc02e3966 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperDeployer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperDeployer.java @@ -109,9 +109,9 @@ public class ZooKeeperDeployer { curator.create(sessionPath); for (String subPath : List.of(DEFCONFIGS_ZK_SUBPATH, - USER_DEFCONFIGS_ZK_SUBPATH, - USERAPP_ZK_SUBPATH, - ZKApplicationPackage.fileRegistryNode)) { + USER_DEFCONFIGS_ZK_SUBPATH, + USERAPP_ZK_SUBPATH, + ZKApplicationPackage.fileRegistryNode)) { // TODO: The replaceFirst below is hackish. curator.create(getZooKeeperAppPath().append(subPath.replaceFirst("/", ""))); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/LogRetriever.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/LogRetriever.java index acfa8e455c0..89724f9853d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/LogRetriever.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/LogRetriever.java @@ -38,7 +38,7 @@ public class LogRetriever { if (deployTime.isPresent() && Instant.now().isBefore(deployTime.get().plus(Duration.ofMinutes(2)))) return new EmptyResponse(); - return HttpErrorResponse.internalServerError("Failed to get logs: " + Exceptions.toMessageString(e)); + throw new RuntimeException("Failed to get logs from " + logServerUri, e); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/TesterClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/TesterClient.java index a18f96e83bb..e25b0a13f42 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/TesterClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/TesterClient.java @@ -72,7 +72,7 @@ public class TesterClient { } private HttpURL testerUrl(String testerHostname, int port, String... path) { - return HttpURL.create(Scheme.https, DomainName.of(testerHostname), port, Path.empty().append(List.of(path))); + return HttpURL.create(Scheme.https, DomainName.of(testerHostname), port, Path.empty().append(List.of(path)).withoutTrailingSlash()); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java index 4dcb2e44f36..75d94434303 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java @@ -4,8 +4,8 @@ package com.yahoo.vespa.config.server.http.v2; import ai.vespa.http.DomainName; import ai.vespa.http.HttpURL; import ai.vespa.http.HttpURL.Query; -import com.yahoo.component.annotation.Inject; import com.yahoo.component.Version; +import com.yahoo.component.annotation.Inject; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.config.model.api.Model; import com.yahoo.config.model.api.ServiceInfo; @@ -217,7 +217,7 @@ public class ApplicationHandler extends HttpHandler { private HttpResponse logs(ApplicationId applicationId, HttpRequest request) { HttpURL requestURL = HttpURL.from(request.getUri()); Optional<DomainName> hostname = Optional.ofNullable(requestURL.query().lastEntries().get("hostname")).map(DomainName::of); - return applicationRepository.getLogs(applicationId, hostname, requestURL.query().remove("hostname")); + return applicationRepository.getLogs(applicationId, hostname, requestURL.query()); } private HttpResponse searchNodeMetrics(ApplicationId applicationId) { @@ -267,7 +267,7 @@ public class ApplicationHandler extends HttpHandler { private Model getActiveModelOrThrow(ApplicationId id) { - return applicationRepository.getActiveApplicationSet(id) + return applicationRepository.getActiveApplicationVersions(id) .orElseThrow(() -> new NotFoundException("Application '" + id + "' not found")) .getForVersionOrLatest(Optional.empty(), applicationRepository.clock().instant()) .getModel(); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java index 76879ccf8ae..63667598063 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java @@ -3,12 +3,12 @@ package com.yahoo.vespa.config.server.maintenance; import com.yahoo.config.FileReference; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.TenantName; import com.yahoo.config.subscription.ConfigSourceSet; import com.yahoo.jrt.Supervisor; import com.yahoo.jrt.Transport; import com.yahoo.vespa.config.ConnectionPool; import com.yahoo.vespa.config.server.ApplicationRepository; +import com.yahoo.vespa.config.server.session.RemoteSession; import com.yahoo.vespa.config.server.session.Session; import com.yahoo.vespa.config.server.session.SessionRepository; import com.yahoo.vespa.config.server.tenant.Tenant; @@ -21,6 +21,7 @@ import com.yahoo.vespa.filedistribution.FileReferenceDownload; import java.io.File; import java.time.Duration; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.Future; @@ -28,6 +29,8 @@ import java.util.logging.Logger; import static com.yahoo.vespa.config.server.filedistribution.FileDistributionUtil.fileReferenceExistsOnDisk; import static com.yahoo.vespa.config.server.filedistribution.FileDistributionUtil.getOtherConfigServersInCluster; +import static com.yahoo.vespa.config.server.session.Session.Status.ACTIVATE; +import static com.yahoo.vespa.config.server.session.Session.Status.PREPARE; /** * Verifies that all active sessions has an application package on local disk. @@ -57,62 +60,66 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer { int[] failures = new int[1]; List<Runnable> futureDownloads = new ArrayList<>(); - for (TenantName tenantName : applicationRepository.tenantRepository().getAllTenantNames()) { - for (Session session : applicationRepository.tenantRepository().getTenant(tenantName).getSessionRepository().getRemoteSessions()) { - if (shuttingDown()) - break; - - switch (session.getStatus()) { - case PREPARE, ACTIVATE: - break; - default: - continue; - } - - ApplicationId applicationId = session.getOptionalApplicationId().orElse(null); - if (applicationId == null) // dry-run sessions have no application id - continue; - - log.finest(() -> "Verifying application package for " + applicationId); - - Optional<FileReference> appFileReference = session.getApplicationPackageReference(); - if (appFileReference.isPresent()) { - long sessionId = session.getSessionId(); - attempts++; - if (!fileReferenceExistsOnDisk(downloadDirectory, appFileReference.get())) { - log.fine(() -> "Downloading application package with file reference " + appFileReference + - " for " + applicationId + " (session " + sessionId + ")"); - - FileReferenceDownload download = new FileReferenceDownload(appFileReference.get(), - this.getClass().getSimpleName(), - false); - Future<Optional<File>> futureDownload = fileDownloader.getFutureFileOrTimeout(download); - futureDownloads.add(() -> { - try { - if (futureDownload.get().isPresent()) { - createLocalSessionIfMissing(applicationId, sessionId); - return; - } + for (Session session : preparedAndActivatedSessions()) { + if (shuttingDown()) + return asSuccessFactorDeviation(attempts, failures[0]); + + ApplicationId applicationId = session.getOptionalApplicationId().orElse(null); + if (applicationId == null) // dry-run sessions have no application id + continue; + + Optional<FileReference> appFileReference = session.getApplicationPackageReference(); + if (appFileReference.isPresent()) { + long sessionId = session.getSessionId(); + FileReference fileReference = appFileReference.get(); + + attempts++; + if (! fileReferenceExistsOnDisk(downloadDirectory, fileReference)) { + Future<Optional<File>> futureDownload = startDownload(fileReference, sessionId, applicationId); + futureDownloads.add(() -> { + try { + if (futureDownload.get().isPresent()) { + createLocalSessionIfMissing(applicationId, sessionId); + return; } - catch (Exception ignored) { } - failures[0]++; - log.info("Downloading application package (" + appFileReference + ")" + - " for " + applicationId + " (session " + sessionId + ") unsuccessful. " + - "Can be ignored unless it happens many times over a long period of time, retries is expected"); - }); - } - else { - createLocalSessionIfMissing(applicationId, sessionId); - } + } + catch (Exception e) { + log.warning("Exception when downloading application package (" + fileReference + ")" + + " for " + applicationId + " (session " + sessionId + "): " + e.getMessage()); + } + failures[0]++; + log.info("Downloading application package (" + fileReference + ")" + + " for " + applicationId + " (session " + sessionId + ") unsuccessful. " + + "Can be ignored unless it happens many times over a long period of time, retries is expected"); + }); + } + else { + createLocalSessionIfMissing(applicationId, sessionId); } } } - futureDownloads.forEach(Runnable::run); - return asSuccessFactorDeviation(attempts, failures[0]); } + private Future<Optional<File>> startDownload(FileReference fileReference, long sessionId, ApplicationId applicationId) { + log.fine(() -> "Downloading application package with file reference " + fileReference + + " for " + applicationId + " (session " + sessionId + ")"); + return fileDownloader.getFutureFileOrTimeout(new FileReferenceDownload(fileReference, + this.getClass().getSimpleName(), + false)); + } + + private Collection<RemoteSession> preparedAndActivatedSessions() { + var tenantRepository = applicationRepository.tenantRepository(); + return tenantRepository.getAllTenantNames().stream() + .map(tenantRepository::getTenant) + .map(t -> t.getSessionRepository().getRemoteSessions()) + .flatMap(Collection::stream) + .filter(s -> s.getStatus() == PREPARE || s.getStatus() == ACTIVATE) + .toList(); + } + private static FileDownloader createFileDownloader(ApplicationRepository applicationRepository, File downloadDirectory, Supervisor supervisor) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java index 71e6d9e013d..b44fdfb3a9c 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java @@ -32,11 +32,18 @@ public abstract class ConfigServerMaintainer extends Maintainer { /** Creates a maintainer where maintainers on different nodes in this cluster run with even delay. */ ConfigServerMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource, Clock clock, Duration interval, boolean useLock) { + this(applicationRepository, curator, flagSource, clock, interval, useLock, false); + } + + /** Creates a maintainer where maintainers on different nodes in this cluster run with even delay. */ + ConfigServerMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource, + Clock clock, Duration interval, boolean useLock, boolean ignoreCollision) { super(null, interval, clock, new JobControl(new JobControlFlags(curator, flagSource, useLock)), - new ConfigServerJobMetrics(applicationRepository.metric()), cluster(curator), false); + new ConfigServerJobMetrics(applicationRepository.metric()), cluster(curator), ignoreCollision); this.applicationRepository = applicationRepository; } + private static class ConfigServerJobMetrics extends JobMetrics { private final Metric metric; @@ -47,7 +54,7 @@ public abstract class ConfigServerMaintainer extends Maintainer { @Override public void completed(String job, double successFactorDeviation, long durationMs) { - var context = metric.createContext(Map.of("job", job)); + var context = metric.createContext(Map.of("maintainer", job)); metric.set("maintenance.successFactorDeviation", successFactorDeviation, context); metric.set("maintenance.duration", durationMs, context); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/PendingRestartsMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/PendingRestartsMaintainer.java index e228e0edcb6..11a15308768 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/PendingRestartsMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/PendingRestartsMaintainer.java @@ -41,7 +41,7 @@ public class PendingRestartsMaintainer extends ConfigServerMaintainer { for (Tenant tenant : applicationRepository.tenantRepository().getAllTenants()) { ApplicationCuratorDatabase database = tenant.getApplicationRepo().database(); for (ApplicationId id : database.activeApplications()) - applicationRepository.getActiveApplicationSet(id) + applicationRepository.getActiveApplicationVersions(id) .map(application -> application.getForVersionOrLatest(Optional.empty(), clock.instant())) .ifPresent(application -> { try { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java index 0dc6cc004be..6688a0aafdd 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java @@ -16,7 +16,6 @@ import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.Collection; -import java.util.Comparator; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; @@ -61,7 +60,7 @@ public class ReindexingMaintainer extends ConfigServerMaintainer { for (Tenant tenant : applicationRepository.tenantRepository().getAllTenants()) { ApplicationCuratorDatabase database = tenant.getApplicationRepo().database(); for (ApplicationId id : database.activeApplications()) - applicationRepository.getActiveApplicationSet(id) + applicationRepository.getActiveApplicationVersions(id) .map(application -> application.getForVersionOrLatest(Optional.empty(), clock.instant())) .ifPresent(application -> { try { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java index 844b667fd85..d088f42b54d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java @@ -17,14 +17,15 @@ import java.util.logging.Level; public class SessionsMaintainer extends ConfigServerMaintainer { SessionsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval) { - super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), interval, true); + super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), + interval, true, true); } @Override protected double maintain() { applicationRepository.deleteExpiredLocalSessions(); - int deleted = applicationRepository.deleteExpiredRemoteSessions(applicationRepository.clock()); + int deleted = applicationRepository.deleteExpiredRemoteSessions(); log.log(Level.FINE, () -> "Deleted " + deleted + " expired remote sessions"); return 1.0; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetriever.java b/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetriever.java index 907928b1d40..7974159e531 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetriever.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetriever.java @@ -47,10 +47,9 @@ public class ClusterDeploymentMetricsRetriever { private static final Logger log = Logger.getLogger(ClusterDeploymentMetricsRetriever.class.getName()); private static final String VESPA_CONTAINER = "vespa.container"; - private static final String VESPA_QRSERVER = "vespa.qrserver"; private static final String VESPA_DISTRIBUTOR = "vespa.distributor"; private static final String VESPA_CONTAINER_CLUSTERCONTROLLER = "vespa.container-clustercontroller"; - private static final List<String> WANTED_METRIC_SERVICES = List.of(VESPA_CONTAINER, VESPA_QRSERVER, VESPA_DISTRIBUTOR, VESPA_CONTAINER_CLUSTERCONTROLLER); + private static final List<String> WANTED_METRIC_SERVICES = List.of(VESPA_CONTAINER, VESPA_DISTRIBUTOR, VESPA_CONTAINER_CLUSTERCONTROLLER); private static final ExecutorService executor = Executors.newFixedThreadPool(10, new DaemonThreadFactory("cluster-deployment-metrics-retriever-")); @@ -132,8 +131,6 @@ public class ClusterDeploymentMetricsRetriever { optionalDouble(values.field("feed.latency.sum")).ifPresent(flSum -> aggregator.get().addFeedLatency(flSum, values.field("feed.latency.count").asDouble())); } - case VESPA_QRSERVER -> optionalDouble(values.field("query_latency.sum")).ifPresent(qlSum -> - aggregator.get().addQrLatency(qlSum, values.field("query_latency.count").asDouble())); case VESPA_DISTRIBUTOR -> { optionalDouble(values.field("vds.distributor.docsstored.average")) .ifPresent(docCount -> aggregator.get().addDocumentCount(docCount)); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsAggregator.java b/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsAggregator.java index 2e2525fa459..9a68f1d6c37 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsAggregator.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsAggregator.java @@ -11,7 +11,6 @@ public class DeploymentMetricsAggregator { private LatencyMetrics feed; private LatencyMetrics read; - private LatencyMetrics qr; private LatencyMetrics container; private Double documentCount; private ResourceUsage memoryUsage; @@ -27,11 +26,6 @@ public class DeploymentMetricsAggregator { return this; } - public synchronized DeploymentMetricsAggregator addQrLatency(double sum, double count) { - this.qr = combineLatency(this.qr, sum, count); - return this; - } - public synchronized DeploymentMetricsAggregator addContainerLatency(double sum, double count) { this.container = combineLatency(this.container, sum, count); return this; @@ -69,17 +63,15 @@ public class DeploymentMetricsAggregator { } public Optional<Double> aggregateQueryLatency() { - if (container == null && qr == null) return Optional.empty(); - var c = Optional.ofNullable(container).orElseGet(LatencyMetrics::new); - var q = Optional.ofNullable(qr).orElseGet(LatencyMetrics::new); - return Optional.of((c.sum + q.sum) / (c.count + q.count)).filter(num -> !num.isNaN()); + if (container == null) return Optional.empty(); + var c = Optional.of(container).orElseGet(LatencyMetrics::new); + return Optional.of(c.sum / c.count).filter(num -> !num.isNaN()); } public Optional<Double> aggregateQueryRate() { - if (container == null && qr == null) return Optional.empty(); - var c = Optional.ofNullable(container).orElseGet(LatencyMetrics::new); - var q = Optional.ofNullable(qr).orElseGet(LatencyMetrics::new); - return Optional.of((c.count + q.count) / 60); + if (container == null) return Optional.empty(); + var c = Optional.of(container).orElseGet(LatencyMetrics::new); + return Optional.of(c.count / 60); } public Optional<Double> aggregateDocumentCount() { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java index 04b42f0411b..3a2286fdd4d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java @@ -17,10 +17,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER; -import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER; /** * Produces lb-services cfg @@ -32,7 +30,7 @@ public class LbServicesProducer implements LbServicesConfig.Producer { private final Map<TenantName, Set<ApplicationInfo>> models; private final Zone zone; - public LbServicesProducer(Map<TenantName, Set<ApplicationInfo>> models, Zone zone, FlagSource flagSource) { + public LbServicesProducer(Map<TenantName, Set<ApplicationInfo>> models, Zone zone) { this.models = models; this.zone = zone; } @@ -99,10 +97,9 @@ public class LbServicesProducer implements LbServicesConfig.Producer { private boolean getActiveRotation(ApplicationInfo app) { boolean activeRotation = false; for (HostInfo hostInfo : app.getModel().getHosts()) { - Optional<ServiceInfo> container = hostInfo.getServices().stream().filter( - serviceInfo -> serviceInfo.getServiceType().equals(CONTAINER.serviceName) || - serviceInfo.getServiceType().equals(QRSERVER.serviceName)). - findAny(); + Optional<ServiceInfo> container = hostInfo.getServices().stream() + .filter(serviceInfo -> serviceInfo.getServiceType().equals(CONTAINER.serviceName)) + .findAny(); if (container.isPresent()) { activeRotation |= Boolean.parseBoolean(container.get().getProperty("activeRotation").orElse("false")); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/model/SuperModelConfigProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/model/SuperModelConfigProvider.java index 236172dc5fd..3db67d78fe6 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/model/SuperModelConfigProvider.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/model/SuperModelConfigProvider.java @@ -24,9 +24,9 @@ public class SuperModelConfigProvider implements LbServicesConfig.Producer { private final SuperModel superModel; private final LbServicesProducer lbProd; - public SuperModelConfigProvider(SuperModel superModel, Zone zone, FlagSource flagSource) { + public SuperModelConfigProvider(SuperModel superModel, Zone zone) { this.superModel = superModel; - this.lbProd = new LbServicesProducer(Collections.unmodifiableMap(superModel.getModelsPerTenant()), zone, flagSource); + this.lbProd = new LbServicesProducer(Collections.unmodifiableMap(superModel.getModelsPerTenant()), zone); } public SuperModel getSuperModel() { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelFactoryRegistry.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelFactoryRegistry.java index e588da8f1f9..b64b3fb05ab 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelFactoryRegistry.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelFactoryRegistry.java @@ -33,7 +33,7 @@ public class ModelFactoryRegistry { } } - public Set<Version> allVersions() { return factories.keySet(); } + public Set<Version> allVersions() { return Set.copyOf(factories.keySet()); } /** * Returns the factory for the given version diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java index 5105bcbdc28..1bb974a863a 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java @@ -34,11 +34,11 @@ public class RemoteSession extends Session { * @param tenant The name of the tenant creating session * @param sessionId The session id for this session. * @param zooKeeperClient a SessionZooKeeperClient instance - * @param applicationSet current application set for this session + * @param applicationVersions current application versions for this session */ - RemoteSession(TenantName tenant, long sessionId, SessionZooKeeperClient zooKeeperClient, Optional<ApplicationVersions> applicationSet) { + RemoteSession(TenantName tenant, long sessionId, SessionZooKeeperClient zooKeeperClient, Optional<ApplicationVersions> applicationVersions) { super(tenant, sessionId, zooKeeperClient); - this.applicationVersions = applicationSet; + this.applicationVersions = applicationVersions; } @Override diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java index ac483ea20c9..e9fc68ae76e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java @@ -373,7 +373,7 @@ public class SessionRepository { return session; } - public int deleteExpiredRemoteSessions(Clock clock, Predicate<Session> sessionIsActiveForApplication) { + public int deleteExpiredRemoteSessions(Predicate<Session> sessionIsActiveForApplication) { Duration expiryTime = Duration.ofSeconds(expiryTimeFlag.value()); List<Long> remoteSessionsFromZooKeeper = getRemoteSessionsFromZooKeeper(); log.log(Level.FINE, () -> "Remote sessions for tenant " + tenantName + ": " + remoteSessionsFromZooKeeper); @@ -386,7 +386,7 @@ public class SessionRepository { if (session == null) session = new RemoteSession(tenantName, sessionId, createSessionZooKeeperClient(sessionId)); if (session.getStatus() == Session.Status.ACTIVATE && sessionIsActiveForApplication.test(session)) continue; - if (sessionHasExpired(session.getCreateTime(), expiryTime, clock)) { + if (sessionHasExpired(session.getCreateTime(), expiryTime)) { log.log(Level.FINE, () -> "Remote session " + sessionId + " for " + tenantName + " has expired, deleting it"); deleteRemoteSessionFromZooKeeper(session); deleted++; @@ -411,7 +411,7 @@ public class SessionRepository { transaction.close(); } - private boolean sessionHasExpired(Instant created, Duration expiryTime, Clock clock) { + private boolean sessionHasExpired(Instant created, Duration expiryTime) { return created.plus(expiryTime).isBefore(clock.instant()); } @@ -547,13 +547,13 @@ public class SessionRepository { } } - private ApplicationVersions loadApplication(Session session, Optional<ApplicationVersions> previousApplicationSet) { + private ApplicationVersions loadApplication(Session session, Optional<ApplicationVersions> previousApplicationVersions) { log.log(Level.FINE, () -> "Loading application for " + session); SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(session.getSessionId()); ActivatedModelsBuilder builder = new ActivatedModelsBuilder(session.getTenantName(), session.getSessionId(), sessionZooKeeperClient, - previousApplicationSet, + previousApplicationVersions, sessionPreparer.getExecutor(), curator, metrics, diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java index bcffecf28ea..1f000bc5856 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java @@ -24,6 +24,7 @@ import com.yahoo.vespa.config.server.NotFoundException; import com.yahoo.vespa.config.server.UserConfigDefinitionRepo; import com.yahoo.vespa.config.server.filedistribution.AddFileInterface; import com.yahoo.vespa.config.server.filedistribution.MockFileManager; +import com.yahoo.vespa.config.server.session.Session.Status; import com.yahoo.vespa.config.server.tenant.CloudAccountSerializer; import com.yahoo.vespa.config.server.tenant.DataplaneTokenSerializer; import com.yahoo.vespa.config.server.tenant.OperatorCertificateSerializer; @@ -235,7 +236,11 @@ public class SessionZooKeeperClient { public Version readVespaVersion() { Optional<byte[]> data = curator.getData(versionPath()); // TODO: Empty version should not be possible any more - verify and remove - return data.map(d -> new Version(Utf8.toString(d))).orElse(Vtag.currentVersion); + return data.map(d -> new Version(Utf8.toString(d))) + .orElseGet(() -> { + log.log(Level.WARNING, "No Vespa version found for session at " + versionPath().getAbsolute() + "," + "returning current Vtag version"); + return Vtag.currentVersion; + }); } public Optional<DockerImage> readDockerImageRepository() { @@ -248,8 +253,18 @@ public class SessionZooKeeperClient { } public Instant readCreateTime() { + // TODO jonmv: clean up Optional<byte[]> data = curator.getData(getCreateTimePath()); - return data.map(d -> Instant.ofEpochSecond(Long.parseLong(Utf8.toString(d)))).orElse(Instant.EPOCH); + return data.map(d -> Instant.ofEpochSecond(Long.parseLong(Utf8.toString(d)))) + .or(() -> { + RuntimeException stack = Math.random() < 1e-4 ? new RuntimeException("Trace log") : null; + log.log(Level.FINE, stack, () -> "No creation time found for session at " + getCreateTimePath().getAbsolute() + ", returning session path ctime"); + return curator.getStat(sessionPath).map(s -> Instant.ofEpochMilli(s.getCtime())); + }) + .orElseGet(() -> { + log.log(Level.FINE, () -> "No ZK ctime found for session at " + sessionPath.getAbsolute() + ", returning epoch"); + return Instant.EPOCH; + }); } public Instant readActivatedTime() { @@ -305,7 +320,6 @@ public class SessionZooKeeperClient { var bytes = uncheck(() -> SlimeUtils.toJsonBytes(TenantSecretStoreSerializer.toSlime(tenantSecretStores))); curator.set(tenantSecretStorePath(), bytes); } - } public List<TenantSecretStore> readTenantSecretStores() { @@ -361,7 +375,10 @@ public class SessionZooKeeperClient { public ActivationTriggers readActivationTriggers() { return curator.getData(sessionPath.append(ACTIVATION_TRIGGERS_PATH)) .map(ActivationTriggersSerializer::fromJson) - .orElse(ActivationTriggers.empty()); + .orElseGet(() -> { + log.log(Level.WARNING, "No activation triggers found for session at " + sessionPath.append(ACTIVATION_TRIGGERS_PATH).getAbsolute() + ", returning empty"); + return ActivationTriggers.empty(); + }); } /** @@ -370,12 +387,14 @@ public class SessionZooKeeperClient { * @param createTime Time of session creation. */ public void createNewSession(Instant createTime) { + log.log(Level.FINE, () -> "Creating new session at " + sessionPath.getAbsolute()); CuratorTransaction transaction = new CuratorTransaction(curator); transaction.add(CuratorOperations.create(sessionPath.getAbsolute())); transaction.add(CuratorOperations.create(sessionPath.append(UPLOAD_BARRIER).getAbsolute())); - transaction.add(createWriteStatusTransaction(Session.Status.NEW).operations()); + transaction.add(CuratorOperations.create(sessionStatusPath.getAbsolute(), Utf8.toBytes(Status.NEW.name()))); transaction.add(CuratorOperations.create(getCreateTimePath().getAbsolute(), Utf8.toBytes(String.valueOf(createTime.getEpochSecond())))); transaction.commit(); + log.log(Level.FINE, () -> "Done creating new session at " + sessionPath.getAbsolute()); } public static Path getSessionPath(TenantName tenantName, long sessionId) { 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 f9f477c9693..150375dd1c0 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 @@ -194,7 +194,7 @@ public class TenantRepository { this.configserverConfig = configserverConfig; this.curator = curator; this.metrics = metrics; - metricUpdater = metrics.getOrCreateMetricUpdater(Map.of()); + this.metricUpdater = metrics.getOrCreateMetricUpdater(Map.of()); this.zkCacheExecutor = zkCacheExecutor; this.zkApplicationWatcherExecutor = zkApplicationWatcherExecutor; this.zkSessionWatcherExecutor = zkSessionWatcherExecutor; diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java index 9a24dc293ce..b5c1d9779c9 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java @@ -52,7 +52,6 @@ import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.config.server.tenant.TestTenantRepository; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.curator.mock.MockCurator; -import com.yahoo.vespa.flags.Flags; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.flags.PermanentFlags; import com.yahoo.vespa.model.VespaModelFactory; @@ -69,13 +68,16 @@ import java.nio.file.Files; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.IntStream; +import static com.yahoo.vespa.config.server.session.Session.Status.ACTIVATE; +import static com.yahoo.vespa.config.server.session.Session.Status.DEACTIVATE; +import static com.yahoo.vespa.config.server.session.Session.Status.PREPARE; +import static com.yahoo.vespa.config.server.session.Session.Status.UNKNOWN; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -97,7 +99,6 @@ public class ApplicationRepositoryTest { private final static File app2 = new File("src/test/apps/cs2"); private final static TenantName tenant1 = TenantName.from("test1"); - private final static TenantName tenant2 = TenantName.from("test2"); private final static ManualClock clock = new ManualClock(Instant.now()); private ApplicationRepository applicationRepository; @@ -138,7 +139,6 @@ public class ApplicationRepositoryTest { .build(); tenantRepository.addTenant(TenantRepository.HOSTED_VESPA_TENANT); tenantRepository.addTenant(tenant1); - tenantRepository.addTenant(tenant2); orchestrator = new OrchestratorMock(); applicationRepository = new ApplicationRepository.Builder() .withTenantRepository(tenantRepository) @@ -235,7 +235,7 @@ public class ApplicationRepositoryTest { assertApplicationData(firstSessionId, firstSessionId); // Prepare, last deployed session id should be the new one - prepare(testApp, secondSessionId); + prepare(secondSessionId); assertApplicationData(firstSessionId, secondSessionId); // Activate, active session id should be the new one @@ -365,7 +365,7 @@ public class ApplicationRepositoryTest { deployApp(testApp); // Deploy another app (with id fooId) - ApplicationId fooId = applicationId(tenant2); + ApplicationId fooId = applicationId("fooId"); PrepareParams prepareParams2 = new PrepareParams.Builder().applicationId(fooId).build(); deployApp(testAppJdiscOnly, prepareParams2); assertNotNull(applicationRepository.getActiveSession(fooId)); @@ -395,44 +395,47 @@ public class ApplicationRepositoryTest { .flagSource(flagSource) .build(); tester.deployApp("src/test/apps/app"); // session 2 (numbering starts at 2) + var applicationRepo = tester.tenant().getApplicationRepo(); + var applicationRepository = tester.applicationRepository(); + var sessionRepository = tester.tenant().getSessionRepository(); clock.advance(Duration.ofSeconds(10)); Optional<Deployment> deployment2 = tester.redeployFromLocalActive(); - assertTrue(deployment2.isPresent()); deployment2.get().activate(); // session 3 - long activeSessionId = tester.tenant().getApplicationRepo().requireActiveSessionOf(tester.applicationId()); + + long activeSessionId = applicationRepo.requireActiveSessionOf(tester.applicationId()); clock.advance(Duration.ofSeconds(10)); - Optional<com.yahoo.config.provision.Deployment> deployment3 = tester.redeployFromLocalActive(); + var deployment3 = tester.redeployFromLocalActive(); assertTrue(deployment3.isPresent()); deployment3.get().prepare(); // session 4 (not activated) - Session deployment3session = ((com.yahoo.vespa.config.server.deploy.Deployment) deployment3.get()).session(); + var deployment3session = ((com.yahoo.vespa.config.server.deploy.Deployment) deployment3.get()).session(); assertNotEquals(activeSessionId, deployment3session.getSessionId()); // No change to active session id - assertEquals(activeSessionId, tester.tenant().getApplicationRepo().requireActiveSessionOf(tester.applicationId())); - SessionRepository sessionRepository = tester.tenant().getSessionRepository(); + assertEquals(activeSessionId, applicationRepo.requireActiveSessionOf(tester.applicationId())); + assertEquals(3, sessionRepository.getLocalSessions().size()); clock.advance(Duration.ofHours(1)); // longer than session lifetime // All sessions except 3 should be removed after the call to deleteExpiredLocalSessions - tester.applicationRepository().deleteExpiredLocalSessions(); - Collection<LocalSession> sessions = sessionRepository.getLocalSessions(); - assertEquals(1, sessions.size()); - ArrayList<LocalSession> localSessions = new ArrayList<>(sessions); - LocalSession localSession = localSessions.get(0); + applicationRepository.deleteExpiredLocalSessions(); + var localSessions = new ArrayList<>(sessionRepository.getLocalSessions()); + assertEquals(1, localSessions.size()); + var localSession = localSessions.get(0); assertEquals(3, localSession.getSessionId()); // All sessions except 3 should be removed after the call to deleteExpiredRemoteSessions - assertEquals(2, tester.applicationRepository().deleteExpiredRemoteSessions(clock)); - ArrayList<Long> remoteSessions = new ArrayList<>(sessionRepository.getRemoteSessionsFromZooKeeper()); - Session remoteSession = sessionRepository.getRemoteSession(remoteSessions.get(0)); + assertEquals(2, applicationRepository.deleteExpiredRemoteSessions()); + var remoteSessions = new ArrayList<>(sessionRepository.getRemoteSessionsFromZooKeeper()); + assertEquals(1, remoteSessions.size()); + var remoteSession = sessionRepository.getRemoteSession(remoteSessions.get(0)); assertEquals(3, remoteSession.getSessionId()); // Deploy, but do not activate - Optional<com.yahoo.config.provision.Deployment> deployment4 = tester.redeployFromLocalActive(); + var deployment4 = tester.redeployFromLocalActive(); assertTrue(deployment4.isPresent()); deployment4.get().prepare(); // session 5 (not activated) @@ -443,23 +446,25 @@ public class ApplicationRepositoryTest { // Create a local session without any data in zookeeper (corner case seen in production occasionally) // and check that expiring local sessions still works int sessionId = 6; - TenantName tenantName = tester.tenant().getName(); - Instant session6CreateTime = clock.instant(); - TenantFileSystemDirs tenantFileSystemDirs = new TenantFileSystemDirs(serverdb, tenantName); + var tenantName = tester.tenant().getName(); + var session6CreateTime = clock.instant(); + var tenantFileSystemDirs = new TenantFileSystemDirs(serverdb, tenantName); Files.createDirectory(tenantFileSystemDirs.getUserApplicationDir(sessionId).toPath()); - LocalSession localSession2 = new LocalSession(tenantName, - sessionId, - FilesApplicationPackage.fromFile(testApp), - new SessionZooKeeperClient(curator, tenantName, sessionId, configserverConfig)); + var localSession2 = new LocalSession(tenantName, + sessionId, + FilesApplicationPackage.fromFile(testApp), + new SessionZooKeeperClient(curator, tenantName, sessionId, configserverConfig)); sessionRepository.addLocalSession(localSession2); assertEquals(2, sessionRepository.getLocalSessions().size()); // Create a session, set status to UNKNOWN, we don't want to expire those (creation time is then EPOCH, // so will be candidate for expiry) sessionId = 7; - Session session = sessionRepository.createRemoteSession(sessionId); + var session = sessionRepository.createRemoteSession(sessionId); sessionRepository.createSessionZooKeeperClient(sessionId).createNewSession(clock.instant()); - sessionRepository.createSetStatusTransaction(session, Session.Status.UNKNOWN).commit(); + try (var t = sessionRepository.createSetStatusTransaction(session, UNKNOWN)) { + t.commit(); + } assertEquals(2, sessionRepository.getLocalSessions().size()); // Still 2, no new local session // Check that trying to expire local session when there exists a local session without any data in zookeeper @@ -479,10 +484,12 @@ public class ApplicationRepositoryTest { // Create a local session with invalid application package and check that expiring local sessions still works sessionId = 8; - java.nio.file.Path applicationPath = tenantFileSystemDirs.getUserApplicationDir(sessionId).toPath(); + var applicationPath = tenantFileSystemDirs.getUserApplicationDir(sessionId).toPath(); session = sessionRepository.createRemoteSession(sessionId); sessionRepository.createSessionZooKeeperClient(sessionId).createNewSession(clock.instant()); - sessionRepository.createSetStatusTransaction(session, Session.Status.PREPARE).commit(); + try (var t = sessionRepository.createSetStatusTransaction(session, PREPARE)){ + t.commit(); + } Files.createDirectory(applicationPath); Files.writeString(Files.createFile(applicationPath.resolve("services.xml")), "non-legal xml"); assertEquals(0, sessionRepository.getLocalSessions().size()); // Will not show up in local sessions @@ -540,7 +547,10 @@ public class ApplicationRepositoryTest { list.add(new NetworkPorts.Allocation(19100, "container", "container/container.0", "http/1")); list.add(new NetworkPorts.Allocation(19101, "container", "container/container.0", "messaging")); list.add(new NetworkPorts.Allocation(19102, "container", "container/container.0", "rpc/admin")); - list.add(new NetworkPorts.Allocation(19103, "slobrok", "admin/slobrok.0", "http")); + list.add(new NetworkPorts.Allocation(19103, "logserver-container", "admin/logs/0", "http")); + list.add(new NetworkPorts.Allocation(19104, "logserver-container", "admin/logs/0", "http/1")); + list.add(new NetworkPorts.Allocation(19105, "logserver-container", "admin/logs/0", "rpc/admin")); + list.add(new NetworkPorts.Allocation(19106, "slobrok", "admin/slobrok.0", "http")); AllocatedHosts info = session.getAllocatedHosts(); assertNotNull(info); @@ -565,7 +575,7 @@ public class ApplicationRepositoryTest { Session activeSession = applicationRepository.getActiveSession(applicationId()).get(); assertEquals(firstSession, activeSession.getSessionId()); - assertEquals(Session.Status.ACTIVATE, activeSession.getStatus()); + assertEquals(ACTIVATE, activeSession.getStatus()); } @Test @@ -581,7 +591,7 @@ public class ApplicationRepositoryTest { Session activeSession = applicationRepository.getActiveSession(applicationId()).get(); assertEquals(firstSession, activeSession.getSessionId()); - assertEquals(Session.Status.ACTIVATE, activeSession.getStatus()); + assertEquals(ACTIVATE, activeSession.getStatus()); } @Test @@ -621,7 +631,7 @@ public class ApplicationRepositoryTest { deployApp(testAppJdiscOnly); - assertEquals(Session.Status.DEACTIVATE, firstSession.getStatus()); + assertEquals(DEACTIVATE, firstSession.getStatus()); } @Test @@ -705,9 +715,8 @@ public class ApplicationRepositoryTest { return applicationRepository.deploy(application, prepareParams()); } - private long prepare(File application, long sessionId) { + private void prepare(long sessionId) { applicationRepository.prepare(sessionId, prepareParams()); - return sessionId; } private PrepareResult deployApp(File applicationPackage) { @@ -722,10 +731,10 @@ public class ApplicationRepositoryTest { return new PrepareParams.Builder().applicationId(applicationId()).build(); } - private ApplicationId applicationId() { return applicationId(tenant1); } + private ApplicationId applicationId() { return applicationId("testapp"); } - private ApplicationId applicationId(TenantName tenantName) { - return ApplicationId.from(tenantName, ApplicationName.from("testapp"), InstanceName.defaultName()); + private ApplicationId applicationId(String appName) { + return ApplicationId.from(tenant1, ApplicationName.from(appName), InstanceName.defaultName()); } private Tenant tenant() { return applicationRepository.getTenant(applicationId()); } @@ -756,14 +765,10 @@ public class ApplicationRepositoryTest { return new Context(properties); } - private static class Context implements Metric.Context { - - private final Map<String, ?> point; - - public Context(Map<String, ?> point) { + private record Context(Map<String, ?> point) implements Metric.Context { + private Context(Map<String, ?> point) { this.point = Map.copyOf(point); } - } } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java index 39f1cb70112..8add7dac489 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelControllerTest.java @@ -22,7 +22,6 @@ import com.yahoo.vespa.config.protocol.JRTServerConfigRequestV3; import com.yahoo.vespa.config.protocol.Trace; import com.yahoo.vespa.config.server.model.SuperModelConfigProvider; import com.yahoo.vespa.config.server.rpc.UncompressedConfigResponseFactory; -import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.model.VespaModel; import org.junit.Before; import org.junit.Test; @@ -55,7 +54,8 @@ public class SuperModelControllerTest { ApplicationName.from("foo"), InstanceName.defaultName()); models.put(app, new ApplicationInfo(app, 4L, new VespaModel(FilesApplicationPackage.fromFile(testApp)))); SuperModel superModel = new SuperModel(models, true); - handler = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone(), new InMemoryFlagSource()), new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory()); + handler = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone()), + new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory()); } @Test @@ -98,7 +98,8 @@ public class SuperModelControllerTest { models.put(tooAdvanced, createApplicationInfo(testApp3, tooAdvanced, 4L)); SuperModel superModel = new SuperModel(models, true); - SuperModelController han = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone(), new InMemoryFlagSource()), new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory()); + SuperModelController han = new SuperModelController(new SuperModelConfigProvider(superModel, Zone.defaultZone()), + new TestConfigDefinitionRepo(), 2, new UncompressedConfigResponseFactory()); LbServicesConfig.Builder lb = new LbServicesConfig.Builder(); han.getSuperModel().getConfig(lb); LbServicesConfig lbc = new LbServicesConfig(lb); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java index 74b08b83791..889388dd56d 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java @@ -10,7 +10,6 @@ import com.yahoo.vespa.config.server.application.Application; import com.yahoo.vespa.config.server.application.ApplicationVersions; import com.yahoo.vespa.config.server.monitoring.MetricUpdater; import com.yahoo.vespa.curator.mock.MockCurator; -import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.model.VespaModel; import org.junit.Before; import org.junit.Rule; @@ -46,7 +45,7 @@ public class SuperModelRequestHandlerTest { public void setup() { counter = new SuperModelGenerationCounter(new MockCurator()); ConfigserverConfig configserverConfig = new ConfigserverConfig(new ConfigserverConfig.Builder()); - manager = new SuperModelManager(configserverConfig, Zone.defaultZone(), counter, new InMemoryFlagSource()); + manager = new SuperModelManager(configserverConfig, Zone.defaultZone(), counter); controller = new SuperModelRequestHandler(new TestConfigDefinitionRepo(), configserverConfig, manager); } @@ -96,7 +95,7 @@ public class SuperModelRequestHandlerTest { ApplicationId foo = applicationId("a", "foo"); long masterGen = 10; ConfigserverConfig configserverConfig = new ConfigserverConfig(new ConfigserverConfig.Builder().masterGeneration(masterGen)); - manager = new SuperModelManager(configserverConfig, Zone.defaultZone(), counter, new InMemoryFlagSource()); + manager = new SuperModelManager(configserverConfig, Zone.defaultZone(), counter); controller = new SuperModelRequestHandler(new TestConfigDefinitionRepo(), configserverConfig, manager); long gen = counter.get(); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationVersionsTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationVersionsTest.java index 23a425b99e2..81e32c6a7ba 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationVersionsTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationVersionsTest.java @@ -53,7 +53,7 @@ public class ApplicationVersionsTest { public void testGetAllVersions() { applicationVersions = ApplicationVersions.fromList(applications); assertEquals(List.of(Version.fromString("1.2.3"), Version.fromString("1.2.4"), Version.fromString("1.2.5")), - applicationVersions.versions(ApplicationId.defaultId())); + applicationVersions.versions()); } private Application createApplication(Version version) { diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java index 68add64ddd9..ec000951684 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java @@ -139,6 +139,13 @@ public class DeployTester { * Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet. */ public PrepareResult deployApp(String applicationPath, String vespaVersion) { + return deployApp(applicationPath, new PrepareParams.Builder().vespaVersion(vespaVersion)); + } + + /** + * Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet. + */ + public PrepareResult deployApp(String applicationPath, PrepareParams.Builder paramsBuilder) { String endpoints = """ [ { @@ -151,15 +158,9 @@ public class DeployTester { } ] """; - return deployApp(applicationPath, new PrepareParams.Builder().containerEndpoints(endpoints).vespaVersion(vespaVersion)); - } - - /** - * Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet. - */ - public PrepareResult deployApp(String applicationPath, PrepareParams.Builder paramsBuilder) { - paramsBuilder.applicationId(applicationId) - .timeoutBudget(new TimeoutBudget(clock, Duration.ofSeconds(60))); + paramsBuilder.applicationId(applicationId) + .timeoutBudget(new TimeoutBudget(clock, Duration.ofSeconds(60))) + .containerEndpoints(endpoints); return applicationRepository.deploy(new File(applicationPath), paramsBuilder.build()); } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java index 512f4dff6b7..a82052b6356 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java @@ -22,7 +22,6 @@ import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.Zone; -import com.yahoo.container.ComponentsConfig; import com.yahoo.slime.SlimeUtils; import com.yahoo.test.ManualClock; import com.yahoo.vespa.config.server.MockConfigConvergenceChecker; @@ -35,7 +34,6 @@ import com.yahoo.vespa.config.server.http.v2.PrepareResult; import com.yahoo.vespa.config.server.maintenance.PendingRestartsMaintainer; import com.yahoo.vespa.config.server.model.TestModelFactory; import com.yahoo.vespa.config.server.session.PrepareParams; -import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.application.validation.change.VespaReindexAction; import com.yahoo.vespa.model.application.validation.change.VespaRestartAction; import org.junit.Rule; @@ -77,6 +75,7 @@ public class HostedDeployTest { @Test public void testRedeployWithVersion() { DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactory(createHostedModelFactory(Version.fromString("4.5.6"), Clock.systemUTC())) .build(); tester.deployApp("src/test/apps/hosted/", "4.5.6"); @@ -90,6 +89,7 @@ public class HostedDeployTest { @Test public void testRedeploy() { DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactory(createHostedModelFactory()) .build(); ApplicationId appId = tester.applicationId(); @@ -105,6 +105,7 @@ public class HostedDeployTest { @Test public void testReDeployWithWantedDockerImageRepositoryAndAthenzDomain() { DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactory(createHostedModelFactory(Version.fromString("4.5.6"), Clock.systemUTC())) .build(); String dockerImageRepository = "docker.foo.com:4443/bar/baz"; @@ -125,6 +126,7 @@ public class HostedDeployTest { public void testRedeployWithTenantSecretStores() { List<TenantSecretStore> tenantSecretStores = List.of(new TenantSecretStore("foo", "123", "role")); DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactory(createHostedModelFactory(Version.fromString("4.5.6"), Clock.systemUTC())) .build(); tester.deployApp("src/test/apps/hosted/", new PrepareParams.Builder() @@ -141,6 +143,7 @@ public class HostedDeployTest { public void testDeployOnUnknownVersion() { List<ModelFactory> modelFactories = List.of(createHostedModelFactory(Version.fromString("1.0.0"))); DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactories(modelFactories) .build(); @@ -561,6 +564,7 @@ public class HostedDeployTest { public void testRedeployWithCloudAccount() { CloudAccount cloudAccount = CloudAccount.from("012345678912"); DeployTester tester = new DeployTester.Builder(temporaryFolder) + .hostedConfigserverConfig(Zone.defaultZone()) .modelFactory(createHostedModelFactory(Version.fromString("4.5.6"), Clock.systemUTC())) .build(); tester.deployApp("src/test/apps/hosted/", new PrepareParams.Builder() diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java index d4aa0676c4f..25e4e004a61 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java @@ -86,7 +86,7 @@ class ApplicationApiHandlerTest { public Path dbDir, defsDir, refsDir; @BeforeEach - public void setupRepo() throws IOException { + public void setupRepo() { configserverConfig = new ConfigserverConfig.Builder() .hostedVespa(true) .configServerDBDir(dbDir.toString()) @@ -113,7 +113,7 @@ class ApplicationApiHandlerTest { Zone.defaultZone()); } - private HttpResponse put(long sessionId, Map<String, String> parameters) throws IOException { + private HttpResponse put(long sessionId, Map<String, String> parameters) { var request = com.yahoo.container.jdisc.HttpRequest.createTestRequest("http://host:123/application/v2/tenant/" + tenant + "/prepareandactivate/" + sessionId, Method.PUT, InputStream.nullInputStream(), diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HostHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HostHandlerTest.java index a2739196b78..0d674b7c1c2 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HostHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HostHandlerTest.java @@ -66,7 +66,7 @@ public class HostHandlerTest { public void require_correct_tenant_and_application_for_hostname() throws Exception { ApplicationId applicationId = applicationId(); applicationRepository.deploy(testApp, new PrepareParams.Builder().applicationId(applicationId).build()); - String hostname = applicationRepository.getActiveApplicationSet(applicationId).get().allHosts().iterator().next(); + String hostname = applicationRepository.getActiveApplicationVersions(applicationId).get().allHosts().iterator().next(); assertApplicationForHost(hostname, applicationId); } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetrieverTest.java index 96456a898a8..b761e5b8165 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetrieverTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ClusterDeploymentMetricsRetrieverTest.java @@ -79,7 +79,6 @@ public class ClusterDeploymentMetricsRetrieverTest { new DeploymentMetricsAggregator() .addContainerLatency(3000, 43) .addContainerLatency(2000, 0) - .addQrLatency(3000, 43) .addFeedLatency(3000, 43), aggregatorMap.get(expectedContainerCluster) diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java index e1ad6bf51f0..57f1e22262e 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java @@ -19,7 +19,6 @@ import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.config.ConfigPayload; -import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.model.VespaModel; import org.junit.Test; import org.xml.sax.SAXException; @@ -56,8 +55,6 @@ public class LbServicesProducerTest { new ContainerEndpoint("mydisc", ApplicationClusterEndpoint.Scope.application, List.of("app-endpoint")) ); - private final InMemoryFlagSource flagSource = new InMemoryFlagSource(); - @Test public void testDeterministicGetConfig() { Map<TenantName, Set<ApplicationInfo>> testModel = createTestModel(new DeployState.Builder().endpoints(endpoints)); @@ -86,7 +83,7 @@ public class LbServicesProducerTest { } private LbServicesConfig getLbServicesConfig(Zone zone, Map<TenantName, Set<ApplicationInfo>> testModel) { - LbServicesProducer producer = new LbServicesProducer(testModel, zone, flagSource); + LbServicesProducer producer = new LbServicesProducer(testModel, zone); LbServicesConfig.Builder builder = new LbServicesConfig.Builder(); producer.getConfig(builder); return new LbServicesConfig(builder); @@ -134,7 +131,9 @@ public class LbServicesProducerTest { .applications("baz:prod:default:custom-t")); } - private void assertContainsEndpoint(List<Endpoints> endpoints, String dnsName, String clusterId, Endpoints.Scope.Enum scope, Endpoints.RoutingMethod.Enum routingMethod, int weight, List<String> hosts) { + private void assertContainsEndpoint(List<Endpoints> endpoints, String dnsName, String clusterId, + Endpoints.Scope.Enum scope, Endpoints.RoutingMethod.Enum routingMethod, + int weight, List<String> hosts) { assertTrue(endpoints.contains(new Endpoints.Builder() .dnsName(dnsName) .clusterId(clusterId) diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcTester.java index 48380d32b94..44d7687d37a 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcTester.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcTester.java @@ -24,8 +24,6 @@ import com.yahoo.vespa.config.server.monitoring.Metrics; import com.yahoo.vespa.config.server.rpc.security.NoopRpcAuthorizer; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.config.server.tenant.TestTenantRepository; -import com.yahoo.vespa.flags.InMemoryFlagSource; -import org.junit.After; import org.junit.rules.TemporaryFolder; import java.io.IOException; @@ -122,15 +120,13 @@ public class RpcTester implements AutoCloseable { } RpcServer createRpcServer(ConfigserverConfig config) throws IOException { - InMemoryFlagSource flagSource = new InMemoryFlagSource(); RpcServer rpcServer = new RpcServer(config, new SuperModelRequestHandler(new TestConfigDefinitionRepo(), config, new SuperModelManager( config, Zone.defaultZone(), - new MemoryGenerationCounter(), - flagSource)), + new MemoryGenerationCounter())), Metrics.createTestMetrics(), hostRegistry, new FileServer(config, new FileDirectory(temporaryFolder.newFolder())), diff --git a/configserver/src/test/resources/metrics/container_metrics.json b/configserver/src/test/resources/metrics/container_metrics.json index f8ea5591c24..4d6fbf55d29 100644 --- a/configserver/src/test/resources/metrics/container_metrics.json +++ b/configserver/src/test/resources/metrics/container_metrics.json @@ -30,22 +30,6 @@ } } ] - }, - { - "name": "vespa.qrserver", - "timestamp": 1557306075, - "metrics": [ - { - "values": { - "query_latency.count": 43.0, - "query_latency.sum": 3000 - }, - "dimensions": { - "clustertype": "container", - "clusterid": "container_cluster_id" - } - } - ] } ] }
\ No newline at end of file |