summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java9
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java19
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java8
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java2
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java14
8 files changed, 40 insertions, 25 deletions
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 5e9e1e8bf33..02b48c9d626 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
@@ -3,6 +3,7 @@ package com.yahoo.vespa.config.server.application;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.component.Version;
+import com.yahoo.component.VersionCompatibility;
import com.yahoo.concurrent.StripedExecutor;
import com.yahoo.config.FileReference;
import com.yahoo.config.provision.ApplicationId;
@@ -74,7 +75,7 @@ public class TenantApplications implements RequestHandler, HostValidator<Applica
private final Clock clock;
private final TenantFileSystemDirs tenantFileSystemDirs;
private final ConfigserverConfig configserverConfig;
- private final ListFlag<Integer> incompatibleMajorVersions;
+ private final ListFlag<String> incompatibleVersions;
public TenantApplications(TenantName tenant, Curator curator, StripedExecutor<TenantName> zkWatcherExecutor,
ExecutorService zkCacheExecutor, Metrics metrics, ReloadListener reloadListener,
@@ -95,7 +96,7 @@ public class TenantApplications implements RequestHandler, HostValidator<Applica
this.tenantFileSystemDirs = tenantFileSystemDirs;
this.clock = clock;
this.configserverConfig = configserverConfig;
- this.incompatibleMajorVersions = PermanentFlags.INCOMPATIBLE_MAJOR_VERSIONS.bindTo(flagSource);
+ this.incompatibleVersions = PermanentFlags.INCOMPATIBLE_VERSIONS.bindTo(flagSource);
}
/** The curator backed ZK storage of this. */
@@ -392,8 +393,8 @@ public class TenantApplications implements RequestHandler, HostValidator<Applica
if (vespaVersion.isEmpty()) return true;
Version wantedVersion = applicationMapper.getForVersion(application, Optional.empty(), clock.instant())
.getModel().wantedNodeVersion();
- boolean compatibleMajor = ! incompatibleMajorVersions.value().contains(wantedVersion.getMajor());
- return compatibleMajor || vespaVersion.get().getMajor() == wantedVersion.getMajor();
+ return VersionCompatibility.fromVersionList(incompatibleVersions.value())
+ .accept(vespaVersion.get(), wantedVersion);
}
@Override
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
index c95c95750a1..93637536182 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
@@ -186,7 +186,7 @@ public class TenantApplicationsTest {
applications.activateApplication(createSet(app1, deployedVersion1), 1);
assertTrue("New major is compatible", applications.compatibleWith(Optional.of(nodeVersion0), app1));
- flagSource.withListFlag(PermanentFlags.INCOMPATIBLE_MAJOR_VERSIONS.id(), List.of(8), Integer.class);
+ flagSource.withListFlag(PermanentFlags.INCOMPATIBLE_VERSIONS.id(), List.of("8"), String.class);
Version deployedVersion2 = Version.fromString("8.1");
applications.activateApplication(createSet(app1, deployedVersion2), 1);
assertFalse("New major is incompatible", applications.compatibleWith(Optional.of(nodeVersion0), app1));
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index 9b64e27e3da..a4aac26b973 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller;
import com.yahoo.component.Version;
+import com.yahoo.component.VersionCompatibility;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
@@ -124,7 +125,7 @@ public class ApplicationController {
private final ApplicationPackageValidator applicationPackageValidator;
private final EndpointCertificates endpointCertificates;
private final StringFlag dockerImageRepoFlag;
- private final ListFlag<Integer> incompatibleMajorVersions;
+ private final ListFlag<String> incompatibleVersions;
private final BillingController billingController;
ApplicationController(Controller controller, CuratorDb curator, AccessControl accessControl, Clock clock,
@@ -139,7 +140,7 @@ public class ApplicationController {
artifactRepository = controller.serviceRegistry().artifactRepository();
applicationStore = controller.serviceRegistry().applicationStore();
dockerImageRepoFlag = PermanentFlags.DOCKER_IMAGE_REPO.bindTo(flagSource);
- incompatibleMajorVersions = PermanentFlags.INCOMPATIBLE_MAJOR_VERSIONS.bindTo(flagSource);
+ incompatibleVersions = PermanentFlags.INCOMPATIBLE_VERSIONS.bindTo(flagSource);
deploymentTrigger = new DeploymentTrigger(controller, clock);
applicationPackageValidator = new ApplicationPackageValidator(controller);
endpointCertificates = new EndpointCertificates(controller,
@@ -754,8 +755,8 @@ public class ApplicationController {
return curator.lockForDeployment(application, zone);
}
- public List<Integer> incompatibleMajorVersions() {
- return incompatibleMajorVersions.value();
+ public VersionCompatibility versionCompatibility() {
+ return VersionCompatibility.fromVersionList(incompatibleVersions.value());
}
/**
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
index 5d2d0454d8e..87ca088f3dc 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.deployment;
import com.google.common.collect.ImmutableMap;
import com.yahoo.component.Version;
+import com.yahoo.component.VersionCompatibility;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.DeploymentSpec.DeclaredTest;
@@ -87,18 +88,18 @@ public class DeploymentStatus {
private final JobList allJobs;
private final SystemName system;
private final Version systemVersion;
- private final List<Integer> incompatibleMajorVersions;
+ private final VersionCompatibility versionCompatibility;
private final Instant now;
private final Map<JobId, StepStatus> jobSteps;
private final List<StepStatus> allSteps;
public DeploymentStatus(Application application, Map<JobId, JobStatus> allJobs, SystemName system,
- Version systemVersion, List<Integer> incompatibleMajorVersions, Instant now) {
+ Version systemVersion, VersionCompatibility versionCompatibility, Instant now) {
this.application = requireNonNull(application);
this.allJobs = JobList.from(allJobs.values());
this.system = requireNonNull(system);
this.systemVersion = requireNonNull(systemVersion);
- this.incompatibleMajorVersions = List.copyOf(incompatibleMajorVersions);
+ this.versionCompatibility = versionCompatibility;
this.now = requireNonNull(now);
List<StepStatus> allSteps = new ArrayList<>();
this.jobSteps = jobDependencies(application.deploymentSpec(), allSteps);
@@ -347,14 +348,10 @@ public class DeploymentStatus {
return jobs;
}
- public boolean isIncompatible(Version platform, Optional<Version> compileVersion) {
- return compileVersion.map(version -> incompatibleMajorVersions.stream().anyMatch(major -> major >= platform.getMajor() != major >= version.getMajor()))
- .orElse(false);
- }
-
- public boolean isIncompatible(Optional<Version> platform, Optional<ApplicationVersion> application) {
- return platform.map(version -> isIncompatible(version, application.flatMap(ApplicationVersion::compileVersion)))
- .orElse(false);
+ private boolean isIncompatible(Optional<Version> platform, Optional<ApplicationVersion> application) {
+ return platform.isPresent()
+ && application.flatMap(ApplicationVersion::compileVersion).isPresent()
+ && versionCompatibility.refuse(platform.get(), application.get().compileVersion().get());
}
/** Changes to deploy with the given job, possibly split in two steps. */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
index 992c9cacc0f..b0e51c8fe9d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller.deployment;
import com.yahoo.component.Version;
+import com.yahoo.component.VersionCompatibility;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.provision.ApplicationId;
@@ -118,12 +119,13 @@ public class DeploymentTrigger {
Optional<Version> compileVersion = outstanding.application().flatMap(ApplicationVersion::compileVersion);
// If the outstanding revision requires a certain platform for compatibility, add that here.
+ VersionCompatibility compatibility = applications().versionCompatibility();
+ Predicate<Version> compatibleWithCompileVersion = version -> compileVersion.map(compiled -> compatibility.accept(version, compiled)).orElse(true);
if (status.application().productionDeployments().getOrDefault(instance, List.of()).stream()
- .anyMatch(deployment -> status.isIncompatible(deployment.version(), compileVersion))) {
+ .anyMatch(deployment -> ! compatibleWithCompileVersion.test(deployment.version()))) {
return targetsForPolicy(controller.readVersionStatus(), status.application().deploymentSpec().requireInstance(instance).upgradePolicy())
.stream() // Pick the latest platform which is compatible with the compile version, and is ready for this instance.
- .filter(platform -> controller.applications().incompatibleMajorVersions().stream()
- .noneMatch(boundary -> platform.getMajor() >= boundary != compileVersion.get().getMajor() >= boundary))
+ .filter(compatibleWithCompileVersion)
.map(outstanding::with)
.filter(change -> status.instanceSteps().get(instance).readyAt(change)
.map(readyAt -> ! readyAt.isAfter(controller.clock().instant()))
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 009e594af65..3cc08fb9f52 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -340,7 +340,7 @@ public class JobController {
LinkedHashMap::new)),
controller.system(),
systemVersion,
- controller.applications().incompatibleMajorVersions(),
+ controller.applications().versionCompatibility(),
controller.clock().instant());
}
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 4b46d7777e7..bca4e2b09df 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
@@ -138,7 +138,7 @@ public final class ControllerTester {
this.curator = curator;
this.rotationsConfig = rotationsConfig;
this.flagSource = flagSource.withBooleanFlag(PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true)
- .withListFlag(PermanentFlags.INCOMPATIBLE_MAJOR_VERSIONS.id(), List.of(), Integer.class);
+ .withListFlag(PermanentFlags.INCOMPATIBLE_VERSIONS.id(), List.of(), String.class);
this.controller = controller;
// Make root logger use time from manual clock
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
index 225c45fbfdb..72a16a37a8f 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
@@ -240,6 +240,20 @@ public class PermanentFlags {
"Takes effect immediately.",
ZONE_ID, APPLICATION_ID);
+ public static final UnboundListFlag<String> INCOMPATIBLE_VERSIONS = defineListFlag(
+ "incompatible-versions", List.of("8"), String.class,
+ "A list of versions which are binary-incompatible with earlier versions. " +
+ "A platform version A and an application package compiled against version B are thus incompatible if this " +
+ "list contains a version X such that (A >= X) != (B >= X). " +
+ "A version specifying only major, or major and minor, imply 0s for the unspecified parts." +
+ "This list may also contain '*' wildcards for any suffix of its version number; see the VersionCompatibility " +
+ "class for further details. " +
+ "The controller will attempt to couple platform upgrades to application changes if their compile versions are " +
+ "incompatible with any current deployments. " +
+ "The config server will refuse to serve config to nodes running a version which is incompatible with their " +
+ "current wanted node version, i.e., nodes about to upgrade to a version which is incompatible with the current.",
+ "Takes effect immediately");
+
public static final UnboundListFlag<Integer> INCOMPATIBLE_MAJOR_VERSIONS = defineListFlag(
"incompatible-major-versions", List.of(8), Integer.class,
"A list of major versions which are binary-incompatible and requires an application package to " +