diff options
author | andreer <andreer@verizonmedia.com> | 2019-08-23 14:20:42 +0200 |
---|---|---|
committer | andreer <andreer@verizonmedia.com> | 2019-08-23 14:20:42 +0200 |
commit | cb3a1a5442d3156b1b05547a7426ac4c774edfd3 (patch) | |
tree | bf0b70bb3f2be59260a60dd4ab230442ccd10f81 /controller-server | |
parent | 5e6a6f708ea01f05b27795ca77fa79dc5d57a6aa (diff) |
separate zk path for application certificates
Diffstat (limited to 'controller-server')
7 files changed, 54 insertions, 56 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java index 48dc343ca8f..c29e64c4cd7 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java @@ -59,7 +59,6 @@ public class Application { private final Optional<String> pemDeployKey; private final List<AssignedRotation> rotations; private final RotationStatus rotationStatus; - private final Optional<ApplicationCertificate> applicationCertificate; /** Creates an empty application */ public Application(ApplicationId id, Instant now) { @@ -67,7 +66,7 @@ public class Application { new DeploymentJobs(OptionalLong.empty(), Collections.emptyList(), Optional.empty(), false), Change.empty(), Change.empty(), Optional.empty(), Optional.empty(), OptionalInt.empty(), new ApplicationMetrics(0, 0), - Optional.empty(), Collections.emptyList(), RotationStatus.EMPTY, Optional.empty()); + Optional.empty(), Collections.emptyList(), RotationStatus.EMPTY); } /** Used from persistence layer: Do not use */ @@ -75,19 +74,18 @@ public class Application { List<Deployment> deployments, DeploymentJobs deploymentJobs, Change change, Change outstandingChange, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Optional<String> pemDeployKey, - List<AssignedRotation> rotations, RotationStatus rotationStatus, - Optional<ApplicationCertificate> applicationCertificate) { + List<AssignedRotation> rotations, RotationStatus rotationStatus) { this(id, createdAt, deploymentSpec, validationOverrides, deployments.stream().collect(Collectors.toMap(Deployment::zone, Function.identity())), deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } Application(ApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides, Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Change change, Change outstandingChange, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Optional<String> pemDeployKey, - List<AssignedRotation> rotations, RotationStatus rotationStatus, Optional<ApplicationCertificate> applicationCertificate) { + List<AssignedRotation> rotations, RotationStatus rotationStatus) { this.id = Objects.requireNonNull(id, "id cannot be null"); this.createdAt = Objects.requireNonNull(createdAt, "instant of creation cannot be null"); this.deploymentSpec = Objects.requireNonNull(deploymentSpec, "deploymentSpec cannot be null"); @@ -103,7 +101,6 @@ public class Application { this.pemDeployKey = pemDeployKey; this.rotations = List.copyOf(Objects.requireNonNull(rotations, "rotations cannot be null")); this.rotationStatus = Objects.requireNonNull(rotationStatus, "rotationStatus cannot be null"); - this.applicationCertificate = Objects.requireNonNull(applicationCertificate, "applicationCertificate cannot be null"); } public ApplicationId id() { return id; } @@ -224,10 +221,6 @@ public class Application { return rotationStatus; } - public Optional<ApplicationCertificate> applicationCertificate() { - return applicationCertificate; - } - @Override public boolean equals(Object o) { if (this == o) return true; 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 f9315812123..64f9d042121 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 @@ -388,8 +388,7 @@ public class ApplicationController { lockOrThrow(applicationId, application -> store(application.withNewDeployment(zone, applicationVersion, platformVersion, clock.instant(), - warningsFrom(result)) - .withApplicationCertificate(applicationCertificate))); + warningsFrom(result)))); return result; } } @@ -541,16 +540,20 @@ public class ApplicationController { private Optional<ApplicationCertificate> getApplicationCertificate(Application application) { // Re-use certificate if already provisioned - if (application.applicationCertificate().isPresent()) { - return application.applicationCertificate(); - } + Optional<ApplicationCertificate> applicationCertificate = curator.readApplicationCertificate(application.id()); + if(applicationCertificate.isPresent()) + return applicationCertificate; + // TODO(tokle): Verify that the application is deploying to a zone where certificate provisioning is enabled boolean provisionCertificate = provisionApplicationCertificate.with(FetchVector.Dimension.APPLICATION_ID, application.id().serializedForm()).value(); if (!provisionCertificate) { return Optional.empty(); } - return Optional.of(applicationCertificateProvider.requestCaSignedCertificate(application.id())); + ApplicationCertificate newCertificate = applicationCertificateProvider.requestCaSignedCertificate(application.id()); + curator.writeApplicationCertificate(application.id(), newCertificate); + + return Optional.of(newCertificate); } private ActivateResult unexpectedDeployment(ApplicationId application, ZoneId zone) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java index d76f120dddd..634731f48dc 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java @@ -58,7 +58,6 @@ public class LockedApplication { private final Optional<String> pemDeployKey; private final List<AssignedRotation> rotations; private final RotationStatus rotationStatus; - private final Optional<ApplicationCertificate> applicationCertificate; /** * Used to create a locked application @@ -72,7 +71,7 @@ public class LockedApplication { application.deployments(), application.deploymentJobs(), application.change(), application.outstandingChange(), application.ownershipIssueId(), application.owner(), application.majorVersion(), application.metrics(), - application.pemDeployKey(), application.rotations(), application.rotationStatus(), application.applicationCertificate()); + application.pemDeployKey(), application.rotations(), application.rotationStatus()); } private LockedApplication(Lock lock, ApplicationId id, Instant createdAt, @@ -80,7 +79,7 @@ public class LockedApplication { Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Change change, Change outstandingChange, Optional<IssueId> ownershipIssueId, Optional<User> owner, OptionalInt majorVersion, ApplicationMetrics metrics, Optional<String> pemDeployKey, - List<AssignedRotation> rotations, RotationStatus rotationStatus, Optional<ApplicationCertificate> applicationCertificate) { + List<AssignedRotation> rotations, RotationStatus rotationStatus) { this.lock = lock; this.id = id; this.createdAt = createdAt; @@ -97,42 +96,41 @@ public class LockedApplication { this.pemDeployKey = pemDeployKey; this.rotations = rotations; this.rotationStatus = rotationStatus; - this.applicationCertificate = applicationCertificate; } /** Returns a read-only copy of this */ public Application get() { return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withBuiltInternally(boolean builtInternally) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.withBuiltInternally(builtInternally), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withProjectId(OptionalLong projectId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.withProjectId(projectId), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withDeploymentIssueId(IssueId issueId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.with(issueId), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withJobPause(JobType jobType, OptionalLong pausedUntil) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.withPause(jobType, pausedUntil), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withJobCompletion(long projectId, JobType jobType, JobStatus.JobRun completion, @@ -140,14 +138,14 @@ public class LockedApplication { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.withCompletion(projectId, jobType, completion, jobError), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, - pemDeployKey, rotations, rotationStatus, applicationCertificate); + pemDeployKey, rotations, rotationStatus); } public LockedApplication withJobTriggering(JobType jobType, JobStatus.JobRun job) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.withTriggering(jobType, job), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication withNewDeployment(ZoneId zone, ApplicationVersion applicationVersion, Version version, @@ -198,45 +196,45 @@ public class LockedApplication { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs.without(jobType), change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication with(DeploymentSpec deploymentSpec) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } public LockedApplication with(ValidationOverrides validationOverrides) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication withChange(Change change) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication withOutstandingChange(Change outstandingChange) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication withOwnershipIssueId(IssueId issueId) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, Optional.ofNullable(issueId), owner, - majorVersion, metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + majorVersion, metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication withOwner(User owner) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, Optional.ofNullable(owner), majorVersion, metrics, pemDeployKey, - rotations, rotationStatus, applicationCertificate); + rotations, rotationStatus); } /** Set a major version for this, or set to null to remove any major version override */ @@ -244,37 +242,31 @@ public class LockedApplication { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion == null ? OptionalInt.empty() : OptionalInt.of(majorVersion), - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication with(MetricsService.ApplicationMetrics metrics) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } public LockedApplication withPemDeployKey(String pemDeployKey) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, Optional.ofNullable(pemDeployKey), rotations, rotationStatus, applicationCertificate); + metrics, Optional.ofNullable(pemDeployKey), rotations, rotationStatus); } public LockedApplication with(List<AssignedRotation> assignedRotations) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, assignedRotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, assignedRotations, rotationStatus); } public LockedApplication withRotationStatus(RotationStatus rotationStatus) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); - } - - public LockedApplication withApplicationCertificate(Optional<ApplicationCertificate> applicationCertificate) { - return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, - deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } /** Don't expose non-leaf sub-objects. */ @@ -287,7 +279,7 @@ public class LockedApplication { private LockedApplication with(Map<ZoneId, Deployment> deployments) { return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion, - metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate); + metrics, pemDeployKey, rotations, rotationStatus); } @Override 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 ad7ef2148cd..cc021f4e095 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 @@ -14,7 +14,6 @@ import com.yahoo.slime.Inspector; import com.yahoo.slime.ObjectTraverser; import com.yahoo.slime.Slime; import com.yahoo.vespa.hosted.controller.Application; -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; @@ -195,7 +194,6 @@ public class ApplicationSerializer { .orElse(Map.of()); legacyToSlime(firstRotationStatus, root.setArray(legacyRotationStatusField)); } - application.applicationCertificate().ifPresent(cert -> root.setString(applicationCertificateField, cert.secretsKeyNamePrefix())); return slime; } @@ -386,11 +384,10 @@ public class ApplicationSerializer { Optional<String> pemDeployKey = Serializers.optionalString(root.field(pemDeployKeyField)); List<AssignedRotation> assignedRotations = assignedRotationsFromSlime(deploymentSpec, root); RotationStatus rotationStatus = rotationStatusFromSlime(root, assignedRotations.stream().findFirst()); - 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, - pemDeployKey, assignedRotations, rotationStatus, applicationCertificate); + pemDeployKey, assignedRotations, rotationStatus); } private List<Deployment> deploymentsFromSlime(Inspector array) { 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 91bd486a18a..2536e406d2e 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 @@ -14,6 +14,7 @@ import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificate; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.application.RoutingPolicy; @@ -75,6 +76,7 @@ public class CuratorDb { private static final Path jobRoot = root.append("jobs"); private static final Path controllerRoot = root.append("controllers"); private static final Path routingPoliciesRoot = root.append("routingPolicies"); + private static final Path applicationCertificateRoot = root.append("applicationCertificates"); private final StringSetSerializer stringSetSerializer = new StringSetSerializer(); private final VersionStatusSerializer versionStatusSerializer = new VersionStatusSerializer(); @@ -476,6 +478,16 @@ public class CuratorDb { .orElseGet(Collections::emptySet); } + // -------------- Application web certificates ---------------------------- + + public void writeApplicationCertificate(ApplicationId applicationId, ApplicationCertificate applicationCertificate) { + curator.set(applicationCertificatePath(applicationId), applicationCertificate.secretsKeyNamePrefix().getBytes()); + } + + public Optional<ApplicationCertificate> readApplicationCertificate(ApplicationId applicationId) { + return curator.getData(applicationCertificatePath(applicationId)).map(String::new).map(ApplicationCertificate::new); + } + // -------------- Paths --------------------------------------------------- private Path lockPath(TenantName tenant) { @@ -587,4 +599,8 @@ public class CuratorDb { return controllerRoot.append(hostname); } + private static Path applicationCertificatePath(ApplicationId id) { + return applicationCertificateRoot.append(id.serializedForm()); + } + } 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 a8e51f7622a..6f8a10543e7 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 @@ -708,7 +708,7 @@ public class ControllerTest { @Test public void testDeployProvisionsCertificate() { ((InMemoryFlagSource) tester.controller().flagSource()).withBooleanFlag(Flags.PROVISION_APPLICATION_CERTIFICATE.id(), true); - Function<Application, Optional<ApplicationCertificate>> certificate = (application) -> tester.application(application.id()).applicationCertificate(); + Function<Application, Optional<ApplicationCertificate>> certificate = (application) -> tester.controller().curator().readApplicationCertificate(application.id()); // Create app1 var app1 = tester.createApplication("app1", "tenant1", 1, 2L); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java index 1f39840dc3a..50ef0f5a7d3 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java @@ -122,8 +122,7 @@ public class ApplicationSerializerTest { new MetricsService.ApplicationMetrics(0.5, 0.9), Optional.of("-----BEGIN PUBLIC KEY-----\n∠( ᐛ 」∠)_\n-----END PUBLIC KEY-----"), List.of(AssignedRotation.fromStrings("foo", "default", "my-rotation", Set.of())), - rotationStatus, - Optional.of(new ApplicationCertificate("vespa.certificate"))); + rotationStatus); Application serialized = applicationSerializer.fromSlime(applicationSerializer.toSlime(original)); @@ -161,8 +160,6 @@ public class ApplicationSerializerTest { assertEquals(original.rotations(), serialized.rotations()); assertEquals(original.rotationStatus(), serialized.rotationStatus()); - assertEquals(original.applicationCertificate(), serialized.applicationCertificate()); - // Test cluster utilization assertEquals(0, serialized.deployments().get(zone1).clusterUtils().size()); assertEquals(3, serialized.deployments().get(zone2).clusterUtils().size()); |