diff options
author | Martin Polden <mpolden@mpolden.no> | 2018-04-19 10:47:52 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2018-04-19 15:05:00 +0200 |
commit | 5dc7c835d796f32bb2c9e0079693dd5da833635f (patch) | |
tree | 07161759a2973c43641500b2e38c8879dfcef126 | |
parent | 3991eda2b969053748350b3a745b31d391f6917b (diff) |
Decide controller version across all controllers
22 files changed, 272 insertions, 109 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerClient.java index da3e32df5c9..77203f445d2 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerClient.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerClient.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.configserver; import com.fasterxml.jackson.databind.JsonNode; @@ -47,7 +47,7 @@ public interface ConfigServerClient { Map<?,?> getServiceApiResponse(String tenantName, String applicationName, String instanceName, String environment, String region, String serviceName, String restPath); /** Returns the version this particular config server is running */ - Version version(URI configserverUri); + Version version(URI configServerUri); /** * Set new status on en endpoint in one zone. diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java index 7b9f27d8a96..f7757d2a335 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller; import com.fasterxml.jackson.databind.JsonNode; @@ -6,6 +6,7 @@ import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; import com.yahoo.component.Version; import com.yahoo.component.Vtag; +import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.SystemName; import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; @@ -40,6 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.logging.Logger; /** @@ -57,6 +59,7 @@ public class Controller extends AbstractComponent { private static final Logger log = Logger.getLogger(Controller.class.getName()); + private final Supplier<String> hostnameSupplier; private final CuratorDb curator; private final ApplicationController applicationController; private final TenantController tenantController; @@ -88,7 +91,8 @@ public class Controller extends AbstractComponent { this(curator, rotationsConfig, gitHub, entityService, organization, globalRoutingService, zoneRegistry, configServer, nodeRepository, metricsService, nameService, routingGenerator, chef, - Clock.systemUTC(), athenzClientFactory, artifactRepository, buildService); + Clock.systemUTC(), athenzClientFactory, artifactRepository, buildService, + com.yahoo.net.HostName::getLocalhost); } public Controller(CuratorDb curator, RotationsConfig rotationsConfig, @@ -98,8 +102,9 @@ public class Controller extends AbstractComponent { MetricsService metricsService, NameService nameService, RoutingGenerator routingGenerator, Chef chef, Clock clock, AthenzClientFactory athenzClientFactory, ArtifactRepository artifactRepository, - BuildService buildService) { + BuildService buildService, Supplier<String> hostnameSupplier) { + this.hostnameSupplier = Objects.requireNonNull(hostnameSupplier, "HostnameSupplier cannot be null"); this.curator = Objects.requireNonNull(curator, "Curator cannot be null"); this.gitHub = Objects.requireNonNull(gitHub, "GitHub cannot be null"); this.entityService = Objects.requireNonNull(entityService, "EntityService cannot be null");; @@ -122,6 +127,9 @@ public class Controller extends AbstractComponent { Objects.requireNonNull(buildService, "BuildService cannot be null"), clock); tenantController = new TenantController(this, curator, athenzClientFactory); + + // Record the version of this controller + curator().writeControllerVersion(this.hostname(), Vtag.currentVersion); } /** Returns the instance controlling tenants */ @@ -204,6 +212,11 @@ public class Controller extends AbstractComponent { .orElse(Vtag.currentVersion); } + /** Returns the hostname of this controller */ + public HostName hostname() { + return HostName.from(hostnameSupplier.get()); + } + public MetricsService metricsService() { return metricsService; } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java index 535e5a71fb6..843a3e8d97a 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.component.Version; @@ -72,6 +72,8 @@ public class Upgrader extends Maintainer { private Optional<Version> newestVersionWithConfidence(Confidence confidence) { return reversed(controller().versionStatus().versions()).stream() + // Ensure we never pick a version newer than the system + .filter(v -> !v.versionNumber().isAfter(controller().systemVersion())) .filter(v -> v.confidence().equalOrHigherThan(confidence)) .findFirst() .map(VespaVersion::versionNumber); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index 5a5a8263b3f..4224609f1e2 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -1,9 +1,11 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.persistence; import com.google.inject.Inject; import com.yahoo.component.Version; +import com.yahoo.component.Vtag; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.TenantName; import com.yahoo.path.Path; import com.yahoo.slime.Slime; @@ -21,6 +23,7 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.time.Duration; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -50,9 +53,11 @@ public class CuratorDb { private static final Path lockRoot = root.append("locks"); private static final Path tenantRoot = root.append("tenants"); private static final Path applicationRoot = root.append("applications"); + private static final Path controllerRoot = root.append("controllers"); private final StringSetSerializer stringSetSerializer = new StringSetSerializer(); private final VersionStatusSerializer versionStatusSerializer = new VersionStatusSerializer(); + private final VersionSerializer versionSerializer = new VersionSerializer(); private final ConfidenceOverrideSerializer confidenceOverrideSerializer = new ConfidenceOverrideSerializer(); private final TenantSerializer tenantSerializer = new TenantSerializer(); private final ApplicationSerializer applicationSerializer = new ApplicationSerializer(); @@ -70,6 +75,15 @@ public class CuratorDb { this.curator = curator; } + /** Returns all hosts configured to be part of this ZooKeeper cluster */ + public List<HostName> cluster() { + return Arrays.stream(curator.zooKeeperEnsembleConnectionSpec().split(",")) + .filter(hostAndPort -> !hostAndPort.isEmpty()) + .map(hostAndPort -> hostAndPort.split(":")[0]) + .map(HostName::from) + .collect(Collectors.toList()); + } + // -------------- Locks --------------------------------------------------- public Lock lock(TenantName name, Duration timeout) { @@ -180,6 +194,16 @@ public class CuratorDb { .orElseGet(Collections::emptyMap); } + public void writeControllerVersion(HostName hostname, Version version) { + curator.set(controllerPath(hostname.value()), asJson(versionSerializer.toSlime(version))); + } + + public Version readControllerVersion(HostName hostname) { + return readSlime(controllerPath(hostname.value())) + .map(versionSerializer::fromSlime) + .orElse(Vtag.currentVersion); + } + // -------------- Tenant -------------------------------------------------- public void writeTenant(UserTenant tenant) { @@ -353,4 +377,8 @@ public class CuratorDb { return applicationRoot.append(application.serializedForm()); } + private static Path controllerPath(String hostname) { + return controllerRoot.append(hostname); + } + } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java index 5dc8ca0e545..57364cee049 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/MockCuratorDb.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.persistence; import com.yahoo.vespa.curator.mock.MockCurator; @@ -12,7 +12,16 @@ import com.yahoo.vespa.curator.mock.MockCurator; public class MockCuratorDb extends CuratorDb { public MockCuratorDb() { - super(new MockCurator()); + this("test-controller:2222"); + } + + public MockCuratorDb(String zooKeeperEnsembleConnectionSpec) { + super(new MockCurator() { + @Override + public String zooKeeperEnsembleConnectionSpec() { + return zooKeeperEnsembleConnectionSpec; + } + }); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionSerializer.java new file mode 100644 index 00000000000..78045a15e9c --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionSerializer.java @@ -0,0 +1,30 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.persistence; + +import com.yahoo.component.Version; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.Slime; + +/** + * Serializer for version numbers. + * + * @author mpolden + */ +public class VersionSerializer { + + private static final String versionField = "version"; + + public Slime toSlime(Version version) { + Slime slime = new Slime(); + Cursor root = slime.setObject(); + root.setString(versionField, version.toFullString()); + return slime; + } + + public Version fromSlime(Slime slime) { + Inspector root = slime.get(); + return Version.fromString(root.field(versionField).asString()); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java index 18648d4a488..e0c443f2110 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java @@ -1,8 +1,9 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.persistence; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; import com.yahoo.slime.ArrayTraverser; import com.yahoo.slime.Cursor; import com.yahoo.slime.Inspector; @@ -32,7 +33,8 @@ public class VersionStatusSerializer { // VespaVersion fields private static final String releaseCommitField = "releaseCommit"; private static final String committedAtField = "releasedAt"; - private static final String isCurrentSystemVersionField = "isCurrentSystemVersion"; + private static final String isControllerVersionField = "isCurrentControllerVersion"; + private static final String isSystemVersionField = "isCurrentSystemVersion"; private static final String deploymentStatisticsField = "deploymentStatistics"; private static final String confidenceField = "confidence"; private static final String configServersField = "configServerHostnames"; @@ -62,14 +64,15 @@ public class VersionStatusSerializer { private void vespaVersionToSlime(VespaVersion version, Cursor object) { object.setString(releaseCommitField, version.releaseCommit()); object.setLong(committedAtField, version.committedAt().toEpochMilli()); - object.setBool(isCurrentSystemVersionField, version.isCurrentSystemVersion()); + object.setBool(isControllerVersionField, version.isControllerVersion()); + object.setBool(isSystemVersionField, version.isSystemVersion()); deploymentStatisticsToSlime(version.statistics(), object.setObject(deploymentStatisticsField)); object.setString(confidenceField, version.confidence().name()); configServersToSlime(version.configServerHostnames(), object.setArray(configServersField)); } - private void configServersToSlime(Set<String> configServerHostnames, Cursor array) { - configServerHostnames.forEach(array::addString); + private void configServersToSlime(Set<HostName> configServerHostnames, Cursor array) { + configServerHostnames.stream().map(HostName::value).forEach(array::addString); } private void deploymentStatisticsToSlime(DeploymentStatistics statistics, Cursor object) { @@ -93,15 +96,16 @@ public class VersionStatusSerializer { return new VespaVersion(deploymentStatisticsFromSlime(object.field(deploymentStatisticsField)), object.field(releaseCommitField).asString(), Instant.ofEpochMilli(object.field(committedAtField).asLong()), - object.field(isCurrentSystemVersionField).asBool(), + object.field(isControllerVersionField).asBool(), + object.field(isSystemVersionField).asBool(), configServersFromSlime(object.field(configServersField)), VespaVersion.Confidence.valueOf(object.field(confidenceField).asString()) ); } - private Set<String> configServersFromSlime(Inspector array) { - Set<String> configServerHostnames = new LinkedHashSet<>(); - array.traverse((ArrayTraverser) (i, entry) -> configServerHostnames.add(entry.asString())); + private Set<HostName> configServersFromSlime(Inspector array) { + Set<HostName> configServerHostnames = new LinkedHashSet<>(); + array.traverse((ArrayTraverser) (i, entry) -> configServerHostnames.add(HostName.from(entry.asString()))); return Collections.unmodifiableSet(configServerHostnames); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java index f9d3901765f..8e981884f47 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiHandler.java @@ -1,9 +1,10 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.deployment; import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.LoggingRequestHandler; @@ -85,13 +86,13 @@ public class DeploymentApiHandler extends LoggingRequestHandler { versionObject.setString("confidence", version.confidence().name()); versionObject.setString("commit", version.releaseCommit()); versionObject.setLong("date", version.committedAt().toEpochMilli()); - versionObject.setBool("controllerVersion", version.isSelfVersion()); - versionObject.setBool("systemVersion", version.isCurrentSystemVersion()); + versionObject.setBool("controllerVersion", version.isControllerVersion()); + versionObject.setBool("systemVersion", version.isSystemVersion()); Cursor configServerArray = versionObject.setArray("configServers"); - for (String configServerHostnames : version.configServerHostnames()) { + for (HostName hostname : version.configServerHostnames()) { Cursor configServerObject = configServerArray.addObject(); - configServerObject.setString("hostname", configServerHostnames); + configServerObject.setString("hostname", hostname.value()); } Cursor failingArray = versionObject.setArray("failingApplications"); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java index 0d9bd25257f..1f72edf9538 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java @@ -1,10 +1,11 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.versions; import com.google.common.collect.ImmutableList; import com.yahoo.collections.ListMap; import com.yahoo.component.Version; import com.yahoo.component.Vtag; +import com.yahoo.config.provision.HostName; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.api.integration.github.GitSha; @@ -52,13 +53,18 @@ public class VersionStatus { public VersionStatus(List<VespaVersion> versions) { this.versions = ImmutableList.copyOf(versions); } + + /** Returns the current version of controllers in this system */ + public Optional<VespaVersion> controllerVersion() { + return versions().stream().filter(VespaVersion::isControllerVersion).findFirst(); + } /** * Returns the current Vespa version of the system controlled by this, * or empty if we have not currently determined what the system version is in this status. */ public Optional<VespaVersion> systemVersion() { - return versions().stream().filter(VespaVersion::isCurrentSystemVersion).findAny(); + return versions().stream().filter(VespaVersion::isSystemVersion).findFirst(); } /** @@ -79,17 +85,16 @@ public class VersionStatus { /** Create a full, updated version status. This is expensive and should be done infrequently */ public static VersionStatus compute(Controller controller) { - return compute(controller, Vtag.currentVersion); - } - - /** Compute version status using the given current version. This is useful for testing. */ - public static VersionStatus compute(Controller controller, Version currentVersion) { - ListMap<Version, String> configServerVersions = findConfigServerVersions(controller); + ListMap<Version, HostName> configServerVersions = findConfigServerVersions(controller); + ListMap<Version, HostName> controllerVersions = findControllerVersions(controller); Set<Version> infrastructureVersions = new HashSet<>(); - infrastructureVersions.add(currentVersion); + infrastructureVersions.addAll(controllerVersions.keySet()); infrastructureVersions.addAll(configServerVersions.keySet()); + // The controller version is the lowest controller version of all controllers + Version controllerVersion = controllerVersions.keySet().stream().sorted().findFirst().get(); + // The system version is the oldest infrastructure version Version systemVersion = infrastructureVersions.stream().sorted().findFirst().get(); @@ -102,6 +107,7 @@ public class VersionStatus { try { VespaVersion vespaVersion = createVersion(statistics, + statistics.version().equals(controllerVersion), statistics.version().equals(systemVersion), configServerVersions.getList(statistics.version()), controller); @@ -116,7 +122,7 @@ public class VersionStatus { return new VersionStatus(versions); } - private static ListMap<Version, String> findConfigServerVersions(Controller controller) { + private static ListMap<Version, HostName> findConfigServerVersions(Controller controller) { List<URI> configServers = controller.zoneRegistry().zones() .controllerManaged() // TODO jvenstad: Remove this when AWS is automatically upgraded. @@ -125,9 +131,22 @@ public class VersionStatus { .flatMap(zoneId -> controller.zoneRegistry().getConfigServerUris(zoneId).stream()) .collect(Collectors.toList()); - ListMap<Version, String> versions = new ListMap<>(); + ListMap<Version, HostName> versions = new ListMap<>(); for (URI configServer : configServers) - versions.put(controller.applications().configServer().version(configServer), configServer.getHost()); + versions.put(controller.applications().configServer().version(configServer), + HostName.from(configServer.getHost())); + return versions; + } + + private static ListMap<Version, HostName> findControllerVersions(Controller controller) { + ListMap<Version, HostName> versions = new ListMap<>(); + if (controller.curator().cluster().isEmpty()) { // Use vtag if we do not have cluster + versions.put(Vtag.currentVersion, controller.hostname()); + } else { + for (HostName hostname : controller.curator().cluster()) { + versions.put(controller.curator().readControllerVersion(hostname), hostname); + } + } return versions; } @@ -176,15 +195,16 @@ public class VersionStatus { } private static VespaVersion createVersion(DeploymentStatistics statistics, + boolean isControllerVersion, boolean isSystemVersion, - Collection<String> configServerHostnames, + Collection<HostName> configServerHostnames, Controller controller) { GitSha gitSha = controller.gitHub().getCommit(VESPA_REPO_OWNER, VESPA_REPO, statistics.version().toFullString()); Instant committedAt = Instant.ofEpochMilli(gitSha.commit.author.date.getTime()); VespaVersion.Confidence confidence = controller.curator().readConfidenceOverrides().get(statistics.version()); // Compute confidence if there's no override if (confidence == null) { - if (isSystemVersion) { // Always compute confidence for system version + if (isSystemVersion || isControllerVersion) { // Always compute confidence for system and controller confidence = VespaVersion.confidenceFrom(statistics, controller); } else { // Keep existing confidence for non-system versions if already computed confidence = confidenceFor(statistics.version(), controller) @@ -193,6 +213,7 @@ public class VersionStatus { } return new VespaVersion(statistics, gitSha.sha, committedAt, + isControllerVersion, isSystemVersion, configServerHostnames, confidence diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java index 1aa94507b61..5fecb5de79f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java @@ -1,9 +1,9 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.versions; import com.google.common.collect.ImmutableSet; import com.yahoo.component.Version; -import com.yahoo.component.Vtag; +import com.yahoo.config.provision.HostName; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.application.ApplicationList; @@ -25,18 +25,21 @@ public class VespaVersion implements Comparable<VespaVersion> { private final String releaseCommit; private final Instant committedAt; - private final boolean isCurrentSystemVersion; + private final boolean isControllerVersion; + private final boolean isSystemVersion; private final DeploymentStatistics statistics; - private final ImmutableSet<String> configServerHostnames; + private final ImmutableSet<HostName> configServerHostnames; private final Confidence confidence; public VespaVersion(DeploymentStatistics statistics, String releaseCommit, Instant committedAt, - boolean isCurrentSystemVersion, Collection<String> configServerHostnames, + boolean isControllerVersion, boolean isSystemVersion, + Collection<HostName> configServerHostnames, Confidence confidence) { this.statistics = statistics; this.releaseCommit = releaseCommit; this.committedAt = committedAt; - this.isCurrentSystemVersion = isCurrentSystemVersion; + this.isControllerVersion = isControllerVersion; + this.isSystemVersion = isSystemVersion; this.configServerHostnames = ImmutableSet.copyOf(configServerHostnames); this.confidence = confidence; } @@ -83,22 +86,25 @@ public class VespaVersion implements Comparable<VespaVersion> { /** Statistics about deployment of this version */ public DeploymentStatistics statistics() { return statistics; } - /** Returns whether this is the version currently running on this controller */ - public boolean isSelfVersion() { return versionNumber().equals(Vtag.currentVersion); } + /** Returns whether this is the current version of controllers in this system (the lowest version across all + * controllers) */ + public boolean isControllerVersion() { + return isControllerVersion; + } /** * Returns whether this is the current version of the infrastructure of the system - * (i.e the lowest version across this controller and all config servers in all zones). - * A goal of the controller is to eventually (limited by safety and upgrade capacity) drive + * (i.e the lowest version across all controllers and all config servers in all zones). + * A goal of the controllers is to eventually (limited by safety and upgrade capacity) drive * all applications to this version. * * Note that the self version may be higher than the current system version if - * all config servers are not yet upgraded to the version of this controller. + * all config servers are not yet upgraded to the version of the controllers. */ - public boolean isCurrentSystemVersion() { return isCurrentSystemVersion; } + public boolean isSystemVersion() { return isSystemVersion; } /** Returns the host names of the config servers (across all zones) which are currently of this version */ - public Set<String> configServerHostnames() { return configServerHostnames; } + public Set<HostName> configServerHostnames() { return configServerHostnames; } /** Returns the confidence we have in this versions suitability for production */ public Confidence confidence() { return confidence; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ConfigServerClientMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ConfigServerClientMock.java index 068f7b21933..4e3783b6569 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ConfigServerClientMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ConfigServerClientMock.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller; import com.fasterxml.jackson.databind.JsonNode; @@ -183,8 +183,8 @@ public class ConfigServerClientMock extends AbstractComponent implements ConfigS } @Override - public Version version(URI configServerURI) { - return versions.getOrDefault(configServerURI, defaultVersion); + public Version version(URI configServerUri) { + return versions.getOrDefault(configServerUri, defaultVersion); } @Override diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java index 8e5f09346b1..ee426557596 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller; import com.yahoo.component.Version; @@ -77,12 +77,6 @@ public class ControllerTest { .region("corp-us-east-1") .build(); - private static final ApplicationPackage applicationPackage2 = new ApplicationPackageBuilder() - .environment(Environment.prod) - .region("corp-us-east-1") - .region("us-west-1") - .build(); - @Test public void testDeployment() { // Setup system @@ -296,15 +290,18 @@ public class ControllerTest { "commit1", Instant.now(), true, + true, Collections.emptyList(), VespaVersion.Confidence.low ); List<VespaVersion> versions = new ArrayList<>(controller.versionStatus().versions()); for (int i = 0; i < versions.size(); i++) { VespaVersion c = versions.get(i); - if (c.isCurrentSystemVersion()) + if (c.isSystemVersion()) versions.set(i, new VespaVersion(c.statistics(), c.releaseCommit(), c.committedAt(), - false, c.configServerHostnames(), + false, + false, + c.configServerHostnames(), c.confidence())); } versions.add(newSystemVespaVersion); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java index 110455dac35..c098e49dbcb 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller; import com.yahoo.config.provision.ApplicationId; @@ -89,6 +89,12 @@ public final class ControllerTester { new ArtifactRepositoryMock(), new MemoryEntityService(), new MockBuildService()); } + public ControllerTester(MockCuratorDb curatorDb) { + this(new AthenzDbMock(), new ManualClock(), new ConfigServerClientMock(), + new ZoneRegistryMock(), new GitHubMock(), curatorDb, defaultRotationsConfig(), + new MemoryNameService(), new ArtifactRepositoryMock(), new MemoryEntityService(), new MockBuildService()); + } + private ControllerTester(AthenzDbMock athenzDb, ManualClock clock, ConfigServerClientMock configServer, ZoneRegistryMock zoneRegistry, GitHubMock gitHub, CuratorDb curator, RotationsConfig rotationsConfig, @@ -270,7 +276,8 @@ public final class ControllerTester { clock, new AthenzClientFactoryMock(athensDb), artifactRepository, - buildService); + buildService, + () -> "test-controller"); controller.updateVersionStatus(VersionStatus.compute(controller)); return controller; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java index f752cfd4f7a..ac1e5e7c677 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.deployment; import com.yahoo.component.Version; @@ -90,12 +90,13 @@ public class DeploymentTester { } public void updateVersionStatus() { - controller().updateVersionStatus(VersionStatus.compute(controller(), tester.controller().systemVersion())); + updateVersionStatus(tester.controller().systemVersion()); } - public void updateVersionStatus(Version currentVersion) { - configServer().setDefaultVersion(currentVersion); - controller().updateVersionStatus(VersionStatus.compute(controller(), currentVersion)); + public void updateVersionStatus(Version newVersion) { + controller().curator().writeControllerVersion(controller().hostname(), newVersion); + configServer().setDefaultVersion(newVersion); + controller().updateVersionStatus(VersionStatus.compute(controller())); } public void upgradeSystem(Version version) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VersionStatusUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VersionStatusUpdaterTest.java index a7cecda3695..33284457e78 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VersionStatusUpdaterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VersionStatusUpdaterTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.vespa.hosted.controller.ControllerTester; @@ -17,7 +17,8 @@ import static org.junit.Assert.assertTrue; */ public class VersionStatusUpdaterTest { - /** Test that this job updates the status. Test of the content of the update is in VersionStatusTest */ + /** Test that this job updates the status. Test of the content of the update is in + * {@link com.yahoo.vespa.hosted.controller.versions.VersionStatusTest} */ @Test public void testVersionUpdating() { ControllerTester tester = new ControllerTester(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializerTest.java index 05b671baea0..b0306178ae3 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializerTest.java @@ -1,8 +1,9 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.persistence; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; import com.yahoo.vespa.hosted.controller.versions.DeploymentStatistics; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; @@ -12,6 +13,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; @@ -31,10 +33,10 @@ public class VersionStatusSerializerTest { Arrays.asList(ApplicationId.from("tenant1", "failing1", "default"), ApplicationId.from("tenant2", "success2", "default")) ); - vespaVersions.add(new VespaVersion(statistics, "dead", Instant.now(), false, - Arrays.asList("cfg1", "cfg2", "cfg3"), VespaVersion.Confidence.normal)); - vespaVersions.add(new VespaVersion(statistics, "cafe", Instant.now(), true, - Arrays.asList("cfg1", "cfg2", "cfg3"), VespaVersion.Confidence.normal)); + vespaVersions.add(new VespaVersion(statistics, "dead", Instant.now(), false, false, + asHostnames("cfg1", "cfg2", "cfg3"), VespaVersion.Confidence.normal)); + vespaVersions.add(new VespaVersion(statistics, "cafe", Instant.now(), true, true, + asHostnames("cfg1", "cfg2", "cfg3"), VespaVersion.Confidence.normal)); VersionStatus status = new VersionStatus(vespaVersions); VersionStatusSerializer serializer = new VersionStatusSerializer(); VersionStatus deserialized = serializer.fromSlime(serializer.toSlime(status)); @@ -45,7 +47,8 @@ public class VersionStatusSerializerTest { VespaVersion b = deserialized.versions().get(i); assertEquals(a.releaseCommit(), b.releaseCommit()); assertEquals(a.committedAt(), b.committedAt()); - assertEquals(a.isCurrentSystemVersion(), b.isCurrentSystemVersion()); + assertEquals(a.isControllerVersion(), b.isControllerVersion()); + assertEquals(a.isSystemVersion(), b.isSystemVersion()); assertEquals(a.statistics(), b.statistics()); assertEquals(a.configServerHostnames(), b.configServerHostnames()); assertEquals(a.confidence(), b.confidence()); @@ -53,4 +56,8 @@ public class VersionStatusSerializerTest { } + private static List<HostName> asHostnames(String... hostname) { + return Arrays.stream(hostname).map(HostName::from).collect(Collectors.toList()); + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java index 1a876e6b246..243cf7276bd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi; import com.yahoo.application.container.JDisc; @@ -10,6 +10,7 @@ import com.yahoo.container.http.filter.FilterChainRepository; import com.yahoo.io.IOUtils; import com.yahoo.jdisc.http.filter.SecurityRequestFilter; import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; +import com.yahoo.vespa.hosted.controller.ConfigServerClientMock; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import org.junit.ComparisonFailure; @@ -43,12 +44,18 @@ public class ContainerTester { return (Controller) container.components().getComponent(Controller.class.getName()); } - public void updateSystemVersion() { + public ConfigServerClientMock configServer() { + return (ConfigServerClientMock) container.components().getComponent(ConfigServerClientMock.class.getName()); + } + + public void updateVersionStatus() { controller().updateVersionStatus(VersionStatus.compute(controller())); } - public void updateSystemVersion(Version version) { - controller().updateVersionStatus(VersionStatus.compute(controller(), version)); + public void updateVersionStatus(Version version) { + controller().curator().writeControllerVersion(controller().hostname(), version); + configServer().setDefaultVersion(version); + controller().updateVersionStatus(VersionStatus.compute(controller())); } public void assertResponse(Supplier<Request> request, File responseFile) throws IOException { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index e4c4df279b8..704e9fa1a07 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.application; import com.yahoo.application.container.handler.Request; @@ -106,7 +106,7 @@ public class ApplicationApiTest extends ControllerContainerTest { public void testApplicationApi() throws Exception { ContainerControllerTester controllerTester = new ContainerControllerTester(container, responseFiles); ContainerTester tester = controllerTester.containerTester(); - tester.updateSystemVersion(); + tester.updateVersionStatus(); createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); // (Necessary but not provided in this API) @@ -397,7 +397,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // Setup ContainerControllerTester controllerTester = new ContainerControllerTester(container, responseFiles); ContainerTester tester = controllerTester.containerTester(); - tester.updateSystemVersion(); + tester.updateVersionStatus(); createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); // Create tenant @@ -433,7 +433,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // Setup ContainerControllerTester controllerTester = new ContainerControllerTester(container, responseFiles); ContainerTester tester = controllerTester.containerTester(); - tester.updateSystemVersion(); + tester.updateVersionStatus(); UserId userId = new UserId("new_user"); createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, userId); @@ -458,7 +458,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // Setup ContainerControllerTester controllerTester = new ContainerControllerTester(container, responseFiles); ContainerTester tester = controllerTester.containerTester(); - tester.updateSystemVersion(); + tester.updateVersionStatus(); createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); // Create tenant @@ -533,7 +533,7 @@ public class ApplicationApiTest extends ControllerContainerTest { @Test public void testErrorResponses() throws Exception { ContainerTester tester = new ContainerTester(container, responseFiles); - tester.updateSystemVersion(); + tester.updateVersionStatus(); createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); // PUT (update) non-existing tenant @@ -844,7 +844,7 @@ public class ApplicationApiTest extends ControllerContainerTest { public void testJobStatusReporting() throws Exception { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); addUserToHostedOperatorRole(HostedAthenzIdentities.from(HOSTED_VESPA_OPERATOR)); - tester.containerTester().updateSystemVersion(); + tester.containerTester().updateVersionStatus(); long projectId = 1; Application app = tester.createApplication(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() @@ -892,7 +892,7 @@ public class ApplicationApiTest extends ControllerContainerTest { @Test public void testJobStatusReportingOutOfCapacity() { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); - tester.containerTester().updateSystemVersion(); + tester.containerTester().updateVersionStatus(); long projectId = 1; Application app = tester.createApplication(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java index f52cc9e9e11..fef6fd209e8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java @@ -1,9 +1,10 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.deployment; import com.google.common.collect.ImmutableSet; import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.RegionName; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; @@ -22,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * @author bratseth @@ -41,7 +43,7 @@ public class DeploymentApiTest extends ControllerContainerTest { public void testDeploymentApi() throws IOException { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); Version version = Version.fromString("5.0"); - tester.containerTester().updateSystemVersion(version); + tester.containerTester().updateVersionStatus(version); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("corp-us-east-1") @@ -64,7 +66,7 @@ public class DeploymentApiTest extends ControllerContainerTest { // New version released version = Version.fromString("5.1"); - tester.containerTester().updateSystemVersion(version); + tester.containerTester().updateVersionStatus(version); // Applications upgrade, 1/2 succeed tester.upgrader().maintain(); @@ -82,11 +84,14 @@ public class DeploymentApiTest extends ControllerContainerTest { List<VespaVersion> censored = new ArrayList<>(); for (VespaVersion version : versionStatus.versions()) { if ( ! version.configServerHostnames().isEmpty()) - version = new VespaVersion(version.statistics(), - version.releaseCommit(), + version = new VespaVersion(version.statistics(), + version.releaseCommit(), version.committedAt(), - version.isCurrentSystemVersion(), - ImmutableSet.of("config1.test", "config2.test"), + version.isControllerVersion(), + version.isSystemVersion(), + ImmutableSet.of("config1.test", "config2.test").stream() + .map(HostName::from) + .collect(Collectors.toSet()), VespaVersion.confidenceFrom(version.statistics(), controller) ); censored.add(version); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json index 5f7fedfd75f..772e41dda42 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json @@ -1,7 +1,7 @@ { "versions":[ { - "version": "(ignore)", + "version": "5", "confidence": "high", "commit": "(ignore)", "date": 0, @@ -23,7 +23,7 @@ "deployingApplications": [ ] }, { - "version":"(ignore)", + "version":"5.1", "confidence":"normal", "commit":"(ignore)", "date":0, @@ -82,4 +82,4 @@ "deployingApplications": [ ] } ] -}
\ No newline at end of file +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/screwdriver/ScrewdriverApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/screwdriver/ScrewdriverApiTest.java index a8e4c970cf7..6e79f53cae6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/screwdriver/ScrewdriverApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/screwdriver/ScrewdriverApiTest.java @@ -1,9 +1,8 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.screwdriver; import com.yahoo.application.container.handler.Request; import com.yahoo.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester; import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; @@ -11,7 +10,6 @@ import org.junit.Test; import java.io.File; import java.nio.charset.StandardCharsets; -import java.util.Optional; import java.util.OptionalLong; /** @@ -37,7 +35,7 @@ public class ScrewdriverApiTest extends ControllerContainerTest { @Test public void testTriggerJobForApplication() { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); - tester.containerTester().updateSystemVersion(); + tester.containerTester().updateVersionStatus(); Application app = tester.createApplication(); tester.controller().applications().lockOrThrow(app.id(), application -> diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java index 7f3cfe665cc..b11c826d645 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java @@ -1,10 +1,11 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.versions; import com.google.common.collect.ImmutableSet; import com.yahoo.component.Version; import com.yahoo.component.Vtag; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.TenantName; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; @@ -12,13 +13,14 @@ import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; +import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence; import org.junit.Test; import java.net.URI; -import java.net.URISyntaxException; -import java.time.Duration; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType.productionUsEast3; import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType.productionUsWest1; @@ -43,7 +45,7 @@ public class VersionStatusTest { } @Test - public void testSystemVersionIsControllerVersionIfConfigserversAreNewer() { + public void testSystemVersionIsControllerVersionIfConfigServersAreNewer() { ControllerTester tester = new ControllerTester(); Version largerThanCurrent = new Version(Vtag.currentVersion.getMajor() + 1); tester.configServer().setDefaultVersion(largerThanCurrent); @@ -52,15 +54,39 @@ public class VersionStatusTest { } @Test - public void testSystemVersionIsVersionOfOldestConfigServer() throws URISyntaxException { + public void testSystemVersionIsVersionOfOldestConfigServer() { ControllerTester tester = new ControllerTester(); Version oldest = new Version(5); - tester.configServer().versions().put(new URI("https://cfg.prod.corp-us-east-1.test:4443"), oldest); + tester.configServer().versions().put(URI.create("https://cfg.prod.corp-us-east-1.test:4443"), oldest); VersionStatus versionStatus = VersionStatus.compute(tester.controller()); assertEquals(oldest, versionStatus.systemVersion().get().versionNumber()); } @Test + public void testControllerVersionIsVersionOfOldestController() { + HostName controller1 = HostName.from("controller-1"); + HostName controller2 = HostName.from("controller-2"); + HostName controller3 = HostName.from("controller-3"); + MockCuratorDb db = new MockCuratorDb(Stream.of(controller1, controller2, controller3) + .map(hostName -> hostName.value() + ":2222") + .collect(Collectors.joining(","))); + ControllerTester tester = new ControllerTester(db); + + db.writeControllerVersion(controller1, Version.fromString("6.2")); + db.writeControllerVersion(controller2, Version.fromString("6.1")); + db.writeControllerVersion(controller3, Version.fromString("6.2")); + + VersionStatus versionStatus = VersionStatus.compute(tester.controller()); + assertEquals("Controller version is oldest version", Version.fromString("6.1"), + versionStatus.controllerVersion().get().versionNumber()); + + // Last controller upgrades + db.writeControllerVersion(controller2, Version.fromString("6.2")); + versionStatus = VersionStatus.compute(tester.controller()); + assertEquals(Version.fromString("6.2"), versionStatus.controllerVersion().get().versionNumber()); + } + + @Test public void testVersionStatusAfterApplicationUpdates() { DeploymentTester tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() |