summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-08-16 09:11:28 +0200
committerGitHub <noreply@github.com>2019-08-16 09:11:28 +0200
commitf9ab8f501a1b476d0f2f3aafec12093ca2929617 (patch)
tree4ded82f30ed6aeb6b75f6d0039cfc79625e60d07 /controller-server
parent3aff728a748cf3f3cd7d7bb07eca0c3c469a89f9 (diff)
parent5db2b10259a4011d6f6d722f94188fc8f93b9c47 (diff)
Merge pull request #10298 from vespa-engine/mpolden/controller-version
Use and store commit details from Vtag
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java61
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/AuditLogSerializer.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializer.java48
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializer.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/Serializers.java27
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionSerializer.java37
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/ControllerVersion.java70
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java65
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializerTest.java38
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/jobs.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java15
19 files changed, 273 insertions, 163 deletions
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 ff27a92de9a..621c25df914 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
@@ -19,7 +19,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServ
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud;
-import com.yahoo.vespa.hosted.controller.api.integration.github.GitHub;
import com.yahoo.vespa.hosted.controller.api.integration.maven.MavenRepository;
import com.yahoo.vespa.hosted.controller.api.integration.organization.Mailer;
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
@@ -33,6 +32,7 @@ import com.yahoo.vespa.hosted.controller.deployment.JobController;
import com.yahoo.vespa.hosted.controller.dns.NameServiceForwarder;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
import com.yahoo.vespa.hosted.controller.security.AccessControl;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.OsVersion;
import com.yahoo.vespa.hosted.controller.versions.OsVersionStatus;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
@@ -74,7 +74,6 @@ public class Controller extends AbstractComponent {
private final TenantController tenantController;
private final JobController jobController;
private final Clock clock;
- private final GitHub gitHub;
private final ZoneRegistry zoneRegistry;
private final ConfigServer configServer;
private final MetricsService metricsService;
@@ -91,21 +90,21 @@ public class Controller extends AbstractComponent {
* @param curator the curator instance storing the persistent state of the controller.
*/
@Inject
- public Controller(CuratorDb curator, RotationsConfig rotationsConfig, GitHub gitHub,
+ public Controller(CuratorDb curator, RotationsConfig rotationsConfig,
ZoneRegistry zoneRegistry, ConfigServer configServer, MetricsService metricsService,
RoutingGenerator routingGenerator,
AccessControl accessControl,
ArtifactRepository artifactRepository, ApplicationStore applicationStore, TesterCloud testerCloud,
BuildService buildService, RunDataStore runDataStore, Mailer mailer, FlagSource flagSource,
MavenRepository mavenRepository, ApplicationCertificateProvider applicationCertificateProvider) {
- this(curator, rotationsConfig, gitHub, zoneRegistry,
+ this(curator, rotationsConfig, zoneRegistry,
configServer, metricsService, routingGenerator,
Clock.systemUTC(), accessControl, artifactRepository, applicationStore, testerCloud,
buildService, runDataStore, com.yahoo.net.HostName::getLocalhost, mailer, flagSource,
mavenRepository, applicationCertificateProvider);
}
- public Controller(CuratorDb curator, RotationsConfig rotationsConfig, GitHub gitHub,
+ public Controller(CuratorDb curator, RotationsConfig rotationsConfig,
ZoneRegistry zoneRegistry, ConfigServer configServer,
MetricsService metricsService,
RoutingGenerator routingGenerator, Clock clock,
@@ -116,7 +115,6 @@ public class Controller extends AbstractComponent {
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.zoneRegistry = Objects.requireNonNull(zoneRegistry, "ZoneRegistry cannot be null");
this.configServer = Objects.requireNonNull(configServer, "ConfigServer cannot be null");
this.metricsService = Objects.requireNonNull(metricsService, "MetricsService cannot be null");
@@ -141,7 +139,7 @@ public class Controller extends AbstractComponent {
auditLogger = new AuditLogger(curator, clock);
// Record the version of this controller
- curator().writeControllerVersion(this.hostname(), Vtag.currentVersion);
+ curator().writeControllerVersion(this.hostname(), ControllerVersion.CURRENT);
jobController.updateStorage();
}
@@ -275,10 +273,6 @@ public class Controller extends AbstractComponent {
return HostName.from(hostnameSupplier.get());
}
- public GitHub gitHub() {
- return gitHub;
- }
-
public MetricsService metricsService() {
return metricsService;
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
index 28474b1181a..74478f1ab0e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
@@ -7,21 +7,20 @@ import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Slime;
-import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
-import com.yahoo.vespa.hosted.controller.api.integration.metrics.MetricsService.ApplicationMetrics;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificate;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
+import com.yahoo.vespa.hosted.controller.api.integration.metrics.MetricsService.ApplicationMetrics;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.AssignedRotation;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.ClusterInfo;
@@ -45,7 +44,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.TreeMap;
@@ -355,15 +353,15 @@ public class ApplicationSerializer {
DeploymentJobs deploymentJobs = deploymentJobsFromSlime(root.field(deploymentJobsField));
Change deploying = changeFromSlime(root.field(deployingField));
Change outstandingChange = changeFromSlime(root.field(outstandingChangeField));
- Optional<IssueId> ownershipIssueId = optionalString(root.field(ownershipIssueIdField)).map(IssueId::from);
- Optional<User> owner = optionalString(root.field(ownerField)).map(User::from);
- OptionalInt majorVersion = optionalInteger(root.field(majorVersionField));
+ Optional<IssueId> ownershipIssueId = Serializers.optionalString(root.field(ownershipIssueIdField)).map(IssueId::from);
+ Optional<User> owner = Serializers.optionalString(root.field(ownerField)).map(User::from);
+ OptionalInt majorVersion = Serializers.optionalInteger(root.field(majorVersionField));
ApplicationMetrics metrics = new ApplicationMetrics(root.field(queryQualityField).asDouble(),
root.field(writeQualityField).asDouble());
- Optional<String> pemDeployKey = optionalString(root.field(pemDeployKeyField));
+ Optional<String> pemDeployKey = Serializers.optionalString(root.field(pemDeployKeyField));
List<AssignedRotation> assignedRotations = assignedRotationsFromSlime(deploymentSpec, root);
Map<HostName, RotationStatus> rotationStatus = rotationStatusFromSlime(root.field(rotationStatusField));
- Optional<ApplicationCertificate> applicationCertificate = optionalString(root.field(applicationCertificateField)).map(ApplicationCertificate::new);
+ Optional<ApplicationCertificate> applicationCertificate = Serializers.optionalString(root.field(applicationCertificateField)).map(ApplicationCertificate::new);
return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs,
deploying, outstandingChange, ownershipIssueId, owner, majorVersion, metrics,
@@ -384,10 +382,10 @@ public class ApplicationSerializer {
clusterUtilsMapFromSlime(deploymentObject.field(clusterUtilsField)),
clusterInfoMapFromSlime(deploymentObject.field(clusterInfoField)),
deploymentMetricsFromSlime(deploymentObject.field(deploymentMetricsField)),
- DeploymentActivity.create(optionalInstant(deploymentObject.field(lastQueriedField)),
- optionalInstant(deploymentObject.field(lastWrittenField)),
- optionalDouble(deploymentObject.field(lastQueriesPerSecondField)),
- optionalDouble(deploymentObject.field(lastWritesPerSecondField))));
+ DeploymentActivity.create(Serializers.optionalInstant(deploymentObject.field(lastQueriedField)),
+ Serializers.optionalInstant(deploymentObject.field(lastWrittenField)),
+ Serializers.optionalDouble(deploymentObject.field(lastQueriesPerSecondField)),
+ Serializers.optionalDouble(deploymentObject.field(lastWritesPerSecondField))));
}
private DeploymentMetrics deploymentMetricsFromSlime(Inspector object) {
@@ -463,14 +461,14 @@ public class ApplicationSerializer {
private ApplicationVersion applicationVersionFromSlime(Inspector object) {
if ( ! object.valid()) return ApplicationVersion.unknown;
- OptionalLong applicationBuildNumber = optionalLong(object.field(applicationBuildNumberField));
+ OptionalLong applicationBuildNumber = Serializers.optionalLong(object.field(applicationBuildNumberField));
Optional<SourceRevision> sourceRevision = sourceRevisionFromSlime(object.field(sourceRevisionField));
if (sourceRevision.isEmpty() || applicationBuildNumber.isEmpty()) {
return ApplicationVersion.unknown;
}
- Optional<String> authorEmail = optionalString(object.field(authorEmailField));
- Optional<Version> compileVersion = optionalString(object.field(compileVersionField)).map(Version::fromString);
- Optional<Instant> buildTime = optionalInstant(object.field(buildTimeField));
+ Optional<String> authorEmail = Serializers.optionalString(object.field(authorEmailField));
+ Optional<Version> compileVersion = Serializers.optionalString(object.field(compileVersionField)).map(Version::fromString);
+ Optional<Instant> buildTime = Serializers.optionalInstant(object.field(buildTimeField));
if (authorEmail.isEmpty())
return ApplicationVersion.from(sourceRevision.get(), applicationBuildNumber.getAsLong());
@@ -490,9 +488,9 @@ public class ApplicationSerializer {
}
private DeploymentJobs deploymentJobsFromSlime(Inspector object) {
- OptionalLong projectId = optionalLong(object.field(projectIdField));
+ OptionalLong projectId = Serializers.optionalLong(object.field(projectIdField));
List<JobStatus> jobStatusList = jobStatusListFromSlime(object.field(jobStatusField));
- Optional<IssueId> issueId = optionalString(object.field(issueIdField)).map(IssueId::from);
+ Optional<IssueId> issueId = Serializers.optionalString(object.field(issueIdField)).map(IssueId::from);
boolean builtInternally = object.field(builtInternallyField).asBool();
return new DeploymentJobs(projectId, jobStatusList, issueId, builtInternally);
@@ -533,7 +531,7 @@ public class ApplicationSerializer {
jobRunFromSlime(object.field(lastCompletedField)),
jobRunFromSlime(object.field(firstFailingField)),
jobRunFromSlime(object.field(lastSuccessField)),
- optionalLong(object.field(pausedUntilField))));
+ Serializers.optionalLong(object.field(pausedUntilField))));
}
private Optional<JobStatus.JobRun> jobRunFromSlime(Inspector object) {
@@ -541,7 +539,7 @@ public class ApplicationSerializer {
return Optional.of(new JobStatus.JobRun(object.field(jobRunIdField).asLong(),
new Version(object.field(versionField).asString()),
applicationVersionFromSlime(object.field(revisionField)),
- optionalString(object.field(sourceVersionField)).map(Version::fromString),
+ Serializers.optionalString(object.field(sourceVersionField)).map(Version::fromString),
Optional.of(object.field(sourceApplicationField)).filter(Inspector::valid).map(this::applicationVersionFromSlime),
object.field(reasonField).asString(),
Instant.ofEpochMilli(object.field(atField).asLong())));
@@ -564,25 +562,4 @@ public class ApplicationSerializer {
return List.copyOf(assignedRotations.values());
}
- private OptionalLong optionalLong(Inspector field) {
- return field.valid() ? OptionalLong.of(field.asLong()) : OptionalLong.empty();
- }
-
- private OptionalInt optionalInteger(Inspector field) {
- return field.valid() ? OptionalInt.of((int) field.asLong()) : OptionalInt.empty();
- }
-
- private OptionalDouble optionalDouble(Inspector field) {
- return field.valid() ? OptionalDouble.of(field.asDouble()) : OptionalDouble.empty();
- }
-
- private Optional<String> optionalString(Inspector field) {
- return SlimeUtils.optionalString(field);
- }
-
- private Optional<Instant> optionalInstant(Inspector field) {
- OptionalLong value = optionalLong(field);
- return value.isPresent() ? Optional.of(Instant.ofEpochMilli(value.getAsLong())) : Optional.empty();
- }
-
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/AuditLogSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/AuditLogSerializer.java
index d18e561ce5d..b411f460568 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/AuditLogSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/AuditLogSerializer.java
@@ -10,7 +10,6 @@ import com.yahoo.vespa.hosted.controller.auditlog.AuditLog;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Function;
/**
* Slime serializer for {@link AuditLog}.
@@ -57,7 +56,7 @@ public class AuditLogSerializer {
entryObject.field(principalField).asString(),
methodFrom(entryObject.field(methodField)),
entryObject.field(resourceField).asString(),
- Serializers.optionalField(entryObject.field(dataField), Function.identity())
+ Serializers.optionalString(entryObject.field(dataField))
));
});
return new AuditLog(entries);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializer.java
new file mode 100644
index 00000000000..58902619cf2
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializer.java
@@ -0,0 +1,48 @@
+// 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.Slime;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
+
+import java.time.Instant;
+
+/**
+ * Serializer for {@link com.yahoo.vespa.hosted.controller.versions.ControllerVersion}.
+ *
+ * @author mpolden
+ */
+public class ControllerVersionSerializer {
+
+ // WARNING: Since there are multiple servers in a ZooKeeper cluster and they upgrade one by one
+ // (and rewrite all nodes on startup), changes to the serialized format must be made
+ // such that what is serialized on version N+1 can be read by version N:
+ // - ADDING FIELDS: Always ok
+ // - REMOVING FIELDS: Stop reading the field first. Stop writing it on a later version.
+ // - CHANGING THE FORMAT OF A FIELD: Don't do it bro.
+
+ private static final String VERSION_FIELD = "version";
+ private static final String COMMIT_SHA_FIELD = "commitSha";
+ private static final String COMMIT_DATE_FIELD = "commitDate";
+
+ public Slime toSlime(ControllerVersion controllerVersion) {
+ var slime = new Slime();
+ var root = slime.setObject();
+ root.setString(VERSION_FIELD, controllerVersion.version().toFullString());
+ root.setString(COMMIT_SHA_FIELD, controllerVersion.commitSha());
+ root.setLong(COMMIT_DATE_FIELD, controllerVersion.commitDate().toEpochMilli());
+ return slime;
+ }
+
+ public ControllerVersion fromSlime(Slime slime) {
+ var root = slime.get();
+ var version = Version.fromString(root.field(VERSION_FIELD).asString());
+ // TODO(mpolden): Make the following two fields non-optional after August 2019
+ var commitSha = Serializers.optionalString(root.field(COMMIT_SHA_FIELD))
+ .orElse("badc0ffee");
+ var commitDate = Serializers.optionalInstant(root.field(COMMIT_DATE_FIELD))
+ .orElse(Instant.EPOCH);
+ return new ControllerVersion(version, commitSha, commitDate);
+ }
+
+}
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 b7b64b9cda2..91bd486a18a 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
@@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.controller.persistence;
import com.google.common.util.concurrent.UncheckedTimeoutException;
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;
@@ -23,6 +22,7 @@ import com.yahoo.vespa.hosted.controller.deployment.Run;
import com.yahoo.vespa.hosted.controller.deployment.Step;
import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.OsVersion;
import com.yahoo.vespa.hosted.controller.versions.OsVersionStatus;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
@@ -78,7 +78,7 @@ public class CuratorDb {
private final StringSetSerializer stringSetSerializer = new StringSetSerializer();
private final VersionStatusSerializer versionStatusSerializer = new VersionStatusSerializer();
- private final VersionSerializer versionSerializer = new VersionSerializer();
+ private final ControllerVersionSerializer controllerVersionSerializer = new ControllerVersionSerializer();
private final ConfidenceOverrideSerializer confidenceOverrideSerializer = new ConfidenceOverrideSerializer();
private final TenantSerializer tenantSerializer = new TenantSerializer();
private final ApplicationSerializer applicationSerializer = new ApplicationSerializer();
@@ -272,14 +272,14 @@ public class CuratorDb {
.orElseGet(Collections::emptyMap);
}
- public void writeControllerVersion(HostName hostname, Version version) {
- curator.set(controllerPath(hostname.value()), asJson(versionSerializer.toSlime(version)));
+ public void writeControllerVersion(HostName hostname, ControllerVersion version) {
+ curator.set(controllerPath(hostname.value()), asJson(controllerVersionSerializer.toSlime(version)));
}
- public Version readControllerVersion(HostName hostname) {
+ public ControllerVersion readControllerVersion(HostName hostname) {
return readSlime(controllerPath(hostname.value()))
- .map(versionSerializer::fromSlime)
- .orElse(Vtag.currentVersion);
+ .map(controllerVersionSerializer::fromSlime)
+ .orElse(ControllerVersion.CURRENT);
}
// Infrastructure upgrades
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializer.java
index e3dedd65e68..ff1dd4d95c6 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NameServiceQueueSerializer.java
@@ -113,8 +113,8 @@ public class NameServiceQueueSerializer {
private RemoveRecords removeRecordsFromSlime(Inspector object) {
var type = Record.Type.valueOf(object.field(typeField).asString());
- var name = Serializers.optionalField(object.field(nameField), RecordName::from);
- var data = Serializers.optionalField(object.field(dataField), RecordData::from);
+ var name = Serializers.optionalString(object.field(nameField)).map(RecordName::from);
+ var data = Serializers.optionalString(object.field(dataField)).map(RecordData::from);
return new RemoveRecords(type, name, data);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java
index 80858e713c2..890fa31bc4d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java
@@ -13,7 +13,6 @@ import com.yahoo.vespa.hosted.controller.application.RoutingPolicy;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
-import java.util.function.Function;
/**
* Serializer and deserializer for a {@link RoutingPolicy}.
@@ -66,7 +65,7 @@ public class RoutingPolicySerializer {
ClusterSpec.Id.from(inspect.field(clusterField).asString()),
ZoneId.from(inspect.field(zoneField).asString()),
HostName.from(inspect.field(canonicalNameField).asString()),
- Serializers.optionalField(inspect.field(dnsZoneField), Function.identity()),
+ Serializers.optionalString(inspect.field(dnsZoneField)),
endpointIds));
});
return Collections.unmodifiableSet(policies);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/Serializers.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/Serializers.java
index ef4e8bf80d7..841cb387e54 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/Serializers.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/Serializers.java
@@ -2,9 +2,13 @@
package com.yahoo.vespa.hosted.controller.persistence;
import com.yahoo.slime.Inspector;
+import com.yahoo.vespa.config.SlimeUtils;
+import java.time.Instant;
import java.util.Optional;
-import java.util.function.Function;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
/**
* Reusable serialization logic.
@@ -15,8 +19,25 @@ public class Serializers {
private Serializers() {}
- public static <T> Optional<T> optionalField(Inspector field, Function<String, T> fieldMapper) {
- return Optional.of(field).filter(Inspector::valid).map(Inspector::asString).map(fieldMapper);
+ public static OptionalLong optionalLong(Inspector field) {
+ return field.valid() ? OptionalLong.of(field.asLong()) : OptionalLong.empty();
+ }
+
+ public static OptionalInt optionalInteger(Inspector field) {
+ return field.valid() ? OptionalInt.of((int) field.asLong()) : OptionalInt.empty();
+ }
+
+ public static OptionalDouble optionalDouble(Inspector field) {
+ return field.valid() ? OptionalDouble.of(field.asDouble()) : OptionalDouble.empty();
+ }
+
+ public static Optional<String> optionalString(Inspector field) {
+ return SlimeUtils.optionalString(field);
+ }
+
+ public static Optional<Instant> optionalInstant(Inspector field) {
+ var value = optionalLong(field);
+ return value.isPresent() ? Optional.of(Instant.ofEpochMilli(value.getAsLong())) : Optional.empty();
}
}
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
deleted file mode 100644
index e5897963254..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionSerializer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 {@link Version}.
- *
- * @author mpolden
- */
-public class VersionSerializer {
-
- // WARNING: Since there are multiple servers in a ZooKeeper cluster and they upgrade one by one
- // (and rewrite all nodes on startup), changes to the serialized format must be made
- // such that what is serialized on version N+1 can be read by version N:
- // - ADDING FIELDS: Always ok
- // - REMOVING FIELDS: Stop reading the field first. Stop writing it on a later version.
- // - CHANGING THE FORMAT OF A FIELD: Don't do it bro.
-
- 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/versions/ControllerVersion.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/ControllerVersion.java
new file mode 100644
index 00000000000..a8bfd1ebf68
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/ControllerVersion.java
@@ -0,0 +1,70 @@
+// Copyright 2019 Oath Inc. 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.yahoo.component.Version;
+import com.yahoo.component.Vtag;
+import org.jetbrains.annotations.NotNull;
+
+import java.time.Instant;
+import java.util.Objects;
+
+/**
+ * A controller's Vespa version and commit details.
+ *
+ * @author mpolden
+ */
+public class ControllerVersion implements Comparable<ControllerVersion> {
+
+ /** The current version of this controller */
+ public static final ControllerVersion CURRENT = new ControllerVersion(Vtag.currentVersion, Vtag.commitSha,
+ Vtag.commitDate);
+
+ private final Version version;
+ private final String commitSha;
+ private final Instant commitDate;
+
+ public ControllerVersion(Version version, String commitSha, Instant commitDate) {
+ this.version = Objects.requireNonNull(version);
+ this.commitSha = Objects.requireNonNull(commitSha);
+ this.commitDate = Objects.requireNonNull(commitDate);
+ }
+
+ /** Vespa version */
+ public Version version() {
+ return version;
+ }
+
+ /** Commit SHA of this */
+ public String commitSha() {
+ return commitSha;
+ }
+
+ /** The time this was committed */
+ public Instant commitDate() {
+ return commitDate;
+ }
+
+ @Override
+ public String toString() {
+ return version + ", commit " + commitSha + " @ " + commitDate;
+ }
+
+ @Override
+ public int compareTo(@NotNull ControllerVersion o) {
+ return version.compareTo(o.version);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ControllerVersion that = (ControllerVersion) o;
+ return version.equals(that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(version);
+ }
+
+}
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 82838c8de32..965cc1a9b16 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,30 +1,27 @@
// 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.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
-import com.yahoo.collections.ListMap;
+import com.google.common.collect.ListMultimap;
import com.yahoo.component.Version;
-import com.yahoo.component.Vtag;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-import com.yahoo.vespa.hosted.controller.api.integration.github.GitSha;
import com.yahoo.vespa.hosted.controller.application.ApplicationList;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.JobList;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.maintenance.SystemUpgrader;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -32,7 +29,6 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError.outOfCapacity;
@@ -49,9 +45,6 @@ public class VersionStatus {
private static final Logger log = Logger.getLogger(VersionStatus.class.getName());
- private static final String VESPA_REPO = "vespa-yahoo";
- private static final String VESPA_REPO_OWNER = "vespa";
-
private final ImmutableList<VespaVersion> versions;
/** Create a version status. DO NOT USE: Public for testing and serialization only */
@@ -96,19 +89,23 @@ public class VersionStatus {
/** Create a full, updated version status. This is expensive and should be done infrequently */
public static VersionStatus compute(Controller controller) {
- ListMap<Version, HostName> systemApplicationVersions = findSystemApplicationVersions(controller);
- ListMap<Version, HostName> controllerVersions = findControllerVersions(controller);
+ ListMultimap<Version, HostName> systemApplicationVersions = findSystemApplicationVersions(controller);
+ ListMultimap<ControllerVersion, HostName> controllerVersions = findControllerVersions(controller);
- Set<Version> infrastructureVersions = new HashSet<>();
- infrastructureVersions.addAll(controllerVersions.keySet());
- infrastructureVersions.addAll(systemApplicationVersions.keySet());
+ ListMultimap<Version, HostName> infrastructureVersions = ArrayListMultimap.create();
+ for (var kv : controllerVersions.asMap().entrySet()) {
+ infrastructureVersions.putAll(kv.getKey().version(), kv.getValue());
+ }
+ infrastructureVersions.putAll(systemApplicationVersions);
// The controller version is the lowest controller version of all controllers
- Version controllerVersion = controllerVersions.keySet().stream().min(Comparator.naturalOrder()).get();
+ ControllerVersion controllerVersion = controllerVersions.keySet().stream()
+ .min(Comparator.naturalOrder())
+ .get();
// The system version is the oldest infrastructure version, if that version is newer than the current system
// version
- Version newSystemVersion = infrastructureVersions.stream().min(Comparator.naturalOrder()).get();
+ Version newSystemVersion = infrastructureVersions.keySet().stream().min(Comparator.naturalOrder()).get();
Version systemVersion = controller.versionStatus().systemVersion()
.map(VespaVersion::versionNumber)
.orElse(newSystemVersion);
@@ -118,15 +115,14 @@ public class VersionStatus {
" to " +
newSystemVersion +
", nodes on " + newSystemVersion + ": " +
- Stream.concat(systemApplicationVersions.get(newSystemVersion).stream(),
- controllerVersions.get(newSystemVersion).stream())
- .map(HostName::value)
- .collect(Collectors.joining(", ")));
+ infrastructureVersions.get(newSystemVersion).stream()
+ .map(HostName::value)
+ .collect(Collectors.joining(", ")));
} else {
systemVersion = newSystemVersion;
}
- Collection<DeploymentStatistics> deploymentStatistics = computeDeploymentStatistics(infrastructureVersions,
+ Collection<DeploymentStatistics> deploymentStatistics = computeDeploymentStatistics(infrastructureVersions.keySet(),
controller.applications().asList());
List<VespaVersion> versions = new ArrayList<>();
List<Version> releasedVersions = controller.mavenRepository().metadata().versions();
@@ -137,10 +133,10 @@ public class VersionStatus {
try {
boolean isReleased = Collections.binarySearch(releasedVersions, statistics.version()) >= 0;
VespaVersion vespaVersion = createVersion(statistics,
- statistics.version().equals(controllerVersion),
- statistics.version().equals(systemVersion),
+ controllerVersion,
+ systemVersion,
isReleased,
- systemApplicationVersions.getList(statistics.version()),
+ systemApplicationVersions.get(statistics.version()),
controller);
versions.add(vespaVersion);
} catch (IllegalArgumentException e) {
@@ -154,8 +150,8 @@ public class VersionStatus {
return new VersionStatus(versions);
}
- private static ListMap<Version, HostName> findSystemApplicationVersions(Controller controller) {
- ListMap<Version, HostName> versions = new ListMap<>();
+ private static ListMultimap<Version, HostName> findSystemApplicationVersions(Controller controller) {
+ ListMultimap<Version, HostName> versions = ArrayListMultimap.create();
for (ZoneApi zone : controller.zoneRegistry().zones().controllerUpgraded().zones()) {
for (SystemApplication application : SystemApplication.all()) {
List<Node> eligibleForUpgradeApplicationNodes = controller.configServer().nodeRepository()
@@ -179,10 +175,10 @@ public class VersionStatus {
return versions;
}
- private static ListMap<Version, HostName> findControllerVersions(Controller controller) {
- ListMap<Version, HostName> versions = new ListMap<>();
+ private static ListMultimap<ControllerVersion, HostName> findControllerVersions(Controller controller) {
+ ListMultimap<ControllerVersion, HostName> versions = ArrayListMultimap.create();
if (controller.curator().cluster().isEmpty()) { // Use vtag if we do not have cluster
- versions.put(Vtag.currentVersion, controller.hostname());
+ versions.put(ControllerVersion.CURRENT, controller.hostname());
} else {
for (HostName hostname : controller.curator().cluster()) {
versions.put(controller.curator().readControllerVersion(hostname), hostname);
@@ -241,13 +237,13 @@ public class VersionStatus {
}
private static VespaVersion createVersion(DeploymentStatistics statistics,
- boolean isControllerVersion,
- boolean isSystemVersion,
+ ControllerVersion controllerVersion,
+ Version systemVersion,
boolean isReleased,
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());
+ boolean isSystemVersion = statistics.version().equals(systemVersion);
+ boolean isControllerVersion = statistics.version().equals(controllerVersion.version());
VespaVersion.Confidence confidence = controller.curator().readConfidenceOverrides().get(statistics.version());
// Compute confidence if there's no override
if (confidence == null) {
@@ -259,7 +255,8 @@ public class VersionStatus {
}
}
return new VespaVersion(statistics,
- gitSha.sha, committedAt,
+ controllerVersion.commitSha(),
+ controllerVersion.commitDate(),
isControllerVersion,
isSystemVersion,
isReleased,
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 40936dd8a68..d178bf08592 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
@@ -25,7 +25,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService;
import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
-import com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock;
import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
@@ -80,7 +79,6 @@ public final class ControllerTester {
private final ManualClock clock;
private final ConfigServerMock configServer;
private final ZoneRegistryMock zoneRegistry;
- private final GitHubMock gitHub;
private final CuratorDb curator;
private final MemoryNameService nameService;
private final RotationsConfig rotationsConfig;
@@ -96,7 +94,7 @@ public final class ControllerTester {
public ControllerTester(ManualClock clock, RotationsConfig rotationsConfig, MockCuratorDb curatorDb,
MetricsServiceMock metricsService) {
this(new AthenzDbMock(), clock, new ConfigServerMock(new ZoneRegistryMock()),
- new ZoneRegistryMock(), new GitHubMock(), curatorDb, rotationsConfig,
+ new ZoneRegistryMock(), curatorDb, rotationsConfig,
new MemoryNameService(), new ArtifactRepositoryMock(), new ApplicationStoreMock(), new MockBuildService(),
metricsService, new RoutingGeneratorMock(), new MockContactRetriever());
}
@@ -119,7 +117,7 @@ public final class ControllerTester {
private ControllerTester(AthenzDbMock athenzDb, ManualClock clock,
ConfigServerMock configServer, ZoneRegistryMock zoneRegistry,
- GitHubMock gitHub, CuratorDb curator, RotationsConfig rotationsConfig,
+ CuratorDb curator, RotationsConfig rotationsConfig,
MemoryNameService nameService, ArtifactRepositoryMock artifactRepository,
ApplicationStoreMock appStoreMock, MockBuildService buildService,
MetricsServiceMock metricsService, RoutingGeneratorMock routingGenerator,
@@ -128,7 +126,6 @@ public final class ControllerTester {
this.clock = clock;
this.configServer = configServer;
this.zoneRegistry = zoneRegistry;
- this.gitHub = gitHub;
this.curator = curator;
this.nameService = nameService;
this.rotationsConfig = rotationsConfig;
@@ -138,7 +135,7 @@ public final class ControllerTester {
this.metricsService = metricsService;
this.routingGenerator = routingGenerator;
this.contactRetriever = contactRetriever;
- this.controller = createController(curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry,
+ this.controller = createController(curator, rotationsConfig, configServer, clock, zoneRegistry,
athenzDb, artifactRepository, appStoreMock, buildService,
metricsService, routingGenerator);
@@ -196,7 +193,7 @@ public final class ControllerTester {
/** Create a new controller instance. Useful to verify that controller state is rebuilt from persistence */
public final void createNewController() {
- controller = createController(curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry, athenzDb,
+ controller = createController(curator, rotationsConfig, configServer, clock, zoneRegistry, athenzDb,
artifactRepository, applicationStore, buildService, metricsService,
routingGenerator);
}
@@ -328,14 +325,13 @@ public final class ControllerTester {
private static Controller createController(CuratorDb curator, RotationsConfig rotationsConfig,
ConfigServerMock configServer, ManualClock clock,
- GitHubMock gitHub, ZoneRegistryMock zoneRegistryMock,
+ ZoneRegistryMock zoneRegistryMock,
AthenzDbMock athensDb,
ArtifactRepository artifactRepository, ApplicationStore applicationStore,
BuildService buildService, MetricsServiceMock metricsService,
RoutingGenerator routingGenerator) {
Controller controller = new Controller(curator,
rotationsConfig,
- gitHub,
zoneRegistryMock,
configServer,
metricsService,
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 887406ecba8..11ed95c3f15 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
@@ -6,7 +6,6 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneApi;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.ApplicationController;
@@ -27,9 +26,11 @@ import com.yahoo.vespa.hosted.controller.maintenance.NameServiceDispatcher;
import com.yahoo.vespa.hosted.controller.maintenance.OutstandingChangeDeployer;
import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import com.yahoo.vespa.hosted.controller.maintenance.Upgrader;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -118,7 +119,7 @@ public class DeploymentTester {
/** Upgrade controller to given version */
public void upgradeController(Version version) {
- controller().curator().writeControllerVersion(controller().hostname(), version);
+ controller().curator().writeControllerVersion(controller().hostname(), new ControllerVersion(version, "badc0ffee", Instant.EPOCH));
computeVersionStatus();
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializerTest.java
new file mode 100644
index 00000000000..4d2627f50c2
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ControllerVersionSerializerTest.java
@@ -0,0 +1,38 @@
+// Copyright 2019 Oath Inc. 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.vespa.config.SlimeUtils;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
+import org.junit.Test;
+
+import java.time.Instant;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author mpolden
+ */
+public class ControllerVersionSerializerTest {
+
+ private final ControllerVersionSerializer serializer = new ControllerVersionSerializer();
+
+ @Test
+ public void serialization() {
+ var version = new ControllerVersion(Version.fromString("7.42.1"), "badc0ffee", Instant.ofEpochSecond(1565876112));
+ var serialized = serializer.fromSlime(serializer.toSlime(version));
+ assertEquals(version.version(), serialized.version());
+ assertEquals(version.commitSha(), serialized.commitSha());
+ assertEquals(version.commitDate(), serialized.commitDate());
+ }
+
+ @Test // TODO(mpolden): Remove after August 2019
+ public void legacy_serialization() {
+ var slime = SlimeUtils.jsonToSlime("{\"version\":\"7.42.1\"}");
+ var serialized = serializer.fromSlime(slime);
+ assertEquals(Version.fromString("7.42.1"), serialized.version());
+ assertEquals("badc0ffee", serialized.commitSha());
+ assertEquals(Instant.EPOCH, serialized.commitDate());
+ }
+
+}
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 b32cbbcb926..d920b5d5769 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
@@ -13,6 +13,7 @@ import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock;
+import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import org.junit.ComparisonFailure;
@@ -22,6 +23,7 @@ import java.io.UncheckedIOException;
import java.nio.charset.CharacterCodingException;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.time.Instant;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
@@ -58,10 +60,11 @@ public class ContainerTester {
}
public void upgradeSystem(Version version) {
- controller().curator().writeControllerVersion(controller().hostname(), version);
+ var controllerVersion = new ControllerVersion(version, "badc0ffee", Instant.EPOCH);
+ controller().curator().writeControllerVersion(controller().hostname(), controllerVersion);
for (ZoneApi zone : controller().zoneRegistry().zones().all().zones()) {
for (SystemApplication application : SystemApplication.all()) {
- configServer().setVersion(application.id(), zone.getId(), version);
+ configServer().setVersion(application.id(), zone.getId(), controllerVersion.version());
configServer().convergeServices(application.id(), zone.getId());
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
index af6684002a5..1a838f41220 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
@@ -66,7 +66,6 @@ public class ControllerContainerTest {
" <component id='com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService'/>\n" +
- " <component id='com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.restapi.cost.NoopCostReportConsumer'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues'/>\n" +
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/jobs.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/jobs.json
index c5cfd5981c0..5b2e529fa6d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/jobs.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/jobs.json
@@ -2,7 +2,7 @@
"lastVersions": {
"platform": {
"platform": "6.1",
- "at": 0,
+ "at": "(ignore)",
"pending": "Waiting for current deployment to complete"
},
"application": {
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 772e41dda42..845fa4631b6 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
@@ -4,7 +4,7 @@
"version": "5",
"confidence": "high",
"commit": "(ignore)",
- "date": 0,
+ "date": "(ignore)",
"controllerVersion": false,
"systemVersion": false,
"configServers": [ ],
@@ -26,7 +26,7 @@
"version":"5.1",
"confidence":"normal",
"commit":"(ignore)",
- "date":0,
+ "date": "(ignore)",
"controllerVersion":false,
"systemVersion":true,
"configServers":[
@@ -73,7 +73,7 @@
"version": "(ignore)",
"confidence": "normal",
"commit": "(ignore)",
- "date": 0,
+ "date": "(ignore)",
"controllerVersion": true,
"systemVersion": false,
"configServers": [ ],
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 655c16ccceb..a9fdaac6ee7 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
@@ -11,15 +11,16 @@ import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester;
+import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence;
import org.junit.Test;
+import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -82,16 +83,16 @@ public class VersionStatusTest {
.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"));
+ writeControllerVersion(controller1, Version.fromString("6.2"), db);
+ writeControllerVersion(controller2, Version.fromString("6.1"), db);
+ writeControllerVersion(controller3, Version.fromString("6.2"), db);
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"));
+ writeControllerVersion(controller2, Version.fromString("6.2"), db);
versionStatus = VersionStatus.compute(tester.controller());
assertEquals(Version.fromString("6.2"), versionStatus.controllerVersion().get().versionNumber());
}
@@ -330,6 +331,10 @@ public class VersionStatusTest {
.keySet().contains(version0));
}
+ private static void writeControllerVersion(HostName hostname, Version version, CuratorDb db) {
+ db.writeControllerVersion(hostname, new ControllerVersion(version, "badc0ffee", Instant.EPOCH));
+ }
+
private Confidence confidence(Controller controller, Version version) {
return controller.versionStatus().versions().stream()
.filter(v -> v.statistics().version().equals(version))