summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2018-10-18 12:45:33 +0200
committerJon Bratseth <bratseth@oath.com>2018-10-18 12:45:33 +0200
commitff5425a5ced4134efcf8682c04d546e89bbe770e (patch)
tree493b20ea1082cd23f74195bb5b0aa4c2866ec72a
parent0a5aeca4ccd596256bb1ee9265857499440de0a4 (diff)
Don't upgrade if major version i pinned
Add major-version to deployment as that makes it available to deployment orchestration.
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java15
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java23
-rw-r--r--config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java15
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java34
7 files changed, 100 insertions, 3 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
index 64e986abf9b..6fc6d2257e2 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
@@ -39,6 +39,7 @@ public class DeploymentSpec {
/** The empty deployment spec, specifying no zones or rotation, and defaults for all settings */
public static final DeploymentSpec empty = new DeploymentSpec(Optional.empty(),
UpgradePolicy.defaultPolicy,
+ Optional.empty(),
Collections.emptyList(),
Collections.emptyList(),
"<deployment version='1.0'/>",
@@ -47,6 +48,7 @@ public class DeploymentSpec {
private final Optional<String> globalServiceId;
private final UpgradePolicy upgradePolicy;
+ private final Optional<Integer> majorVersion;
private final List<ChangeBlocker> changeBlockers;
private final List<Step> steps;
private final String xmlForm;
@@ -55,15 +57,21 @@ public class DeploymentSpec {
public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy,
List<ChangeBlocker> changeBlockers, List<Step> steps) {
- this(globalServiceId, upgradePolicy, changeBlockers, steps, null, Optional.empty(), Optional.empty());
+ this(globalServiceId, upgradePolicy, Optional.empty(), changeBlockers, steps, null, Optional.empty(), Optional.empty());
}
- public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy,
+ public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy, Optional<Integer> majorVersion,
+ List<ChangeBlocker> changeBlockers, List<Step> steps) {
+ this(globalServiceId, upgradePolicy, majorVersion, changeBlockers, steps, null, Optional.empty(), Optional.empty());
+ }
+
+ public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy, Optional<Integer> majorVersion,
List<ChangeBlocker> changeBlockers, List<Step> steps, String xmlForm,
Optional<AthenzDomain> athenzDomain, Optional<AthenzService> athenzService) {
validateTotalDelay(steps);
this.globalServiceId = globalServiceId;
this.upgradePolicy = upgradePolicy;
+ this.majorVersion = majorVersion;
this.changeBlockers = changeBlockers;
this.steps = ImmutableList.copyOf(completeSteps(new ArrayList<>(steps)));
this.xmlForm = xmlForm;
@@ -166,6 +174,9 @@ public class DeploymentSpec {
/** Returns the upgrade policy of this, which is defaultPolicy if none is specified */
public UpgradePolicy upgradePolicy() { return upgradePolicy; }
+ /** Returns the major version this application is pinned to, or empty (default) to allow all major versions */
+ public Optional<Integer> majorVersion() { return majorVersion; }
+
/** Returns whether upgrade can occur at the given instant */
public boolean canUpgradeAt(Instant instant) {
return changeBlockers.stream().filter(block -> block.blocksVersions())
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
index 8bc4e0026a6..1900e2139cd 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
*/
public class DeploymentSpecXmlReader {
+ private static final String majorVersionTag = "major-version";
private static final String testTag = "test";
private static final String stagingTag = "staging";
private static final String blockChangeTag = "block-change";
@@ -101,7 +102,14 @@ public class DeploymentSpecXmlReader {
}
Optional<AthenzDomain> athenzDomain = stringAttribute("athenz-domain", root).map(AthenzDomain::from);
Optional<AthenzService> athenzService = stringAttribute("athenz-service", root).map(AthenzService::from);
- return new DeploymentSpec(globalServiceId, readUpgradePolicy(root), readChangeBlockers(root), steps, xmlForm, athenzDomain, athenzService);
+ return new DeploymentSpec(globalServiceId,
+ readUpgradePolicy(root),
+ optionalIntegerAttribute(majorVersionTag, root),
+ readChangeBlockers(root),
+ steps,
+ xmlForm,
+ athenzDomain,
+ athenzService);
}
/** Imposes some constraints on tag order which are not expressible in the schema */
@@ -138,6 +146,19 @@ public class DeploymentSpecXmlReader {
}
}
+ /** Returns the given attribute as an integer, or 0 if it is not present */
+ private Optional<Integer> optionalIntegerAttribute(String attributeName, Element tag) {
+ String value = tag.getAttribute(attributeName);
+ if (value == null || value.isEmpty()) return Optional.empty();
+ try {
+ return Optional.of(Integer.parseInt(value));
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Expected an integer for attribute '" + attributeName +
+ "' but got '" + value + "'");
+ }
+ }
+
/** Returns the given attribute as a string, or Optional.empty if it is not present or empty */
private Optional<String> stringAttribute(String attributeName, Element tag) {
String value = tag.getAttribute(attributeName);
diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
index 103724744de..a0423293d1d 100644
--- a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
+++ b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
@@ -30,6 +30,7 @@ public class DeploymentSpecTest {
DeploymentSpec spec = DeploymentSpec.fromXml(r);
assertEquals(specXml, spec.xmlForm());
assertEquals(1, spec.steps().size());
+ assertFalse(spec.majorVersion().isPresent());
assertTrue(spec.steps().get(0).deploysTo(Environment.test));
assertTrue(spec.includes(Environment.test, Optional.empty()));
assertFalse(spec.includes(Environment.test, Optional.of(RegionName.from("region1"))));
@@ -39,6 +40,20 @@ public class DeploymentSpecTest {
}
@Test
+ public void testSpecPinningMajorVersion() {
+ String specXml = "<deployment version='1.0' major-version='6'>" +
+ " <test/>" +
+ "</deployment>";
+
+ StringReader r = new StringReader(specXml);
+ DeploymentSpec spec = DeploymentSpec.fromXml(r);
+ assertEquals(specXml, spec.xmlForm());
+ assertEquals(1, spec.steps().size());
+ assertTrue(spec.majorVersion().isPresent());
+ assertEquals(6, (int)spec.majorVersion().get());
+ }
+
+ @Test
public void stagingSpec() {
StringReader r = new StringReader(
"<deployment version='1.0'>" +
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
index ca642d0fb2c..e46df3c5a4a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
@@ -162,6 +162,12 @@ public class ApplicationList {
return listOf(list.stream().filter(a -> a.deploymentSpec().canUpgradeAt(instant)));
}
+ /** Returns the subset of applications that hasn't pinned to another major version than the given one */
+ public ApplicationList allowMajorVersion(int majorVersion) {
+ return listOf(list.stream().filter(a -> ! a.deploymentSpec().majorVersion().isPresent() ||
+ a.deploymentSpec().majorVersion().get().equals(majorVersion)));
+ }
+
/** Returns the first n application in this (or all, if there are less than n). */
public ApplicationList first(int n) {
if (list.size() < n) return this;
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 506b9b4642b..676fe808bfe 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
@@ -66,6 +66,7 @@ public class Upgrader extends Maintainer {
cancelUpgradesOf(applications().with(UpgradePolicy.conservative).upgrading().failing().notUpgradingTo(conservativeTarget), reason);
// Schedule the right upgrades
+
canaryTarget.ifPresent(target -> upgrade(applications().with(UpgradePolicy.canary), target));
defaultTarget.ifPresent(target -> upgrade(applications().with(UpgradePolicy.defaultPolicy), target));
conservativeTarget.ifPresent(target -> upgrade(applications().with(UpgradePolicy.conservative), target));
@@ -94,6 +95,7 @@ public class Upgrader extends Maintainer {
applications = applications.notPullRequest(); // Pull requests are deployed as separate applications to test then deleted; No need to upgrade
applications = applications.hasProductionDeployment();
applications = applications.onLowerVersionThan(version);
+ applications = applications.allowMajorVersion(version.getMajor());
applications = applications.notDeployingAt(controller().clock().instant()); // wait with applications deploying an application change or already upgrading
applications = applications.notFailingOn(version); // try to upgrade only if it hasn't failed on this version
applications = applications.canUpgradeAt(controller().clock().instant()); // wait with applications that are currently blocking upgrades
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
index 2f9703b91e1..b7539166c33 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
@@ -16,6 +16,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
+import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -30,12 +31,18 @@ public class ApplicationPackageBuilder {
private final StringBuilder validationOverridesBody = new StringBuilder();
private final StringBuilder blockChange = new StringBuilder();
+ private Optional<Integer> majorVersion = Optional.empty();
private String upgradePolicy = null;
private Environment environment = Environment.prod;
private String globalServiceId = null;
private String athenzIdentityAttributes = null;
private String searchDefinition = "search test { }";
+ public ApplicationPackageBuilder majorVersion(int majorVersion) {
+ this.majorVersion = Optional.of(majorVersion);
+ return this;
+ }
+
public ApplicationPackageBuilder upgradePolicy(String upgradePolicy) {
this.upgradePolicy = upgradePolicy;
return this;
@@ -108,6 +115,7 @@ public class ApplicationPackageBuilder {
private byte[] deploymentSpec() {
StringBuilder xml = new StringBuilder();
xml.append("<deployment version='1.0' ");
+ majorVersion.ifPresent(v -> xml.append("major-version='").append(v).append("' "));
if(athenzIdentityAttributes != null) {
xml.append(athenzIdentityAttributes);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
index a6e31a4a34b..04c0e7e9a6f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
@@ -890,6 +890,40 @@ public class UpgraderTest {
}
@Test
+ public void testPinningMajorVersion() {
+ Version version = Version.fromString("6.2");
+ tester.upgradeSystem(version);
+
+ ApplicationPackage version6ApplicationPackage = new ApplicationPackageBuilder()
+ .majorVersion(6)
+ .upgradePolicy("default")
+ .environment(Environment.prod)
+ .region("us-west-1")
+ .build();
+
+ // Setup applications
+ Application canary0 = tester.createAndDeploy("canary0", 1, "canary");
+ Application default0 = tester.createAndDeploy("default0", 2, version6ApplicationPackage);
+
+ // New major version is released
+ version = Version.fromString("7.0");
+ tester.upgradeSystem(version);
+ assertEquals(version, tester.controller().versionStatus().systemVersion().get().versionNumber());
+ tester.triggerUntilQuiescence();
+
+ // ... canary upgrade to it
+ assertEquals(2, tester.buildService().jobs().size());
+ tester.completeUpgrade(canary0, version, "canary");
+ assertEquals(0, tester.buildService().jobs().size());
+ tester.computeVersionStatus();
+
+ // The other application does not because it has pinned to major version 6
+ tester.upgrader().maintain();
+ tester.triggerUntilQuiescence();
+ assertEquals(0, tester.buildService().jobs().size());
+ }
+
+ @Test
public void testAllowApplicationChangeDuringFailingUpgrade() {
Version version = Version.fromString("6.2");
tester.upgradeSystem(version);