summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2019-06-28 10:25:30 +0200
committerØyvind Grønnesby <oyving@verizonmedia.com>2019-06-28 10:25:30 +0200
commitb166e913b92136044ddc5d3f05f8d5b22eb2bb18 (patch)
treee542c260f0d8585dfde6cea61b4a9b98e59868d5 /controller-server
parentc81bd8b7310f618985db8c4106521d79eb77ea3f (diff)
parente8d94725ce3698a764b4710f486f4358e1360df7 (diff)
Merge remote-tracking branch 'origin/master' into ogronnesby/assign-multiple-rotations
Conflicts: controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java34
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java54
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationCertificateMock.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java1
10 files changed, 114 insertions, 40 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 b5bf5a7cc98..1b6b5a6fb5b 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
@@ -12,6 +12,7 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.api.integration.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.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
@@ -62,6 +63,7 @@ public class Application {
private final Optional<String> pemDeployKey;
private final List<AssignedRotation> rotations;
private final Map<HostName, RotationStatus> rotationStatus;
+ private final Optional<ApplicationCertificate> applicationCertificate;
/** Creates an empty application */
public Application(ApplicationId id, Instant now) {
@@ -69,7 +71,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(), Collections.emptyMap());
+ Optional.empty(), Collections.emptyList(), Collections.emptyMap(), Optional.empty());
}
/** Used from persistence layer: Do not use */
@@ -77,18 +79,19 @@ 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, Map<HostName, RotationStatus> rotationStatus) {
+ List<AssignedRotation> rotations, Map<HostName, RotationStatus> rotationStatus,
+ Optional<ApplicationCertificate> applicationCertificate) {
this(id, createdAt, deploymentSpec, validationOverrides,
deployments.stream().collect(Collectors.toMap(Deployment::zone, Function.identity())),
deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion,
- metrics, pemDeployKey, rotations, rotationStatus);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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, Map<HostName, RotationStatus> rotationStatus) {
+ List<AssignedRotation> rotations, Map<HostName, RotationStatus> rotationStatus, Optional<ApplicationCertificate> applicationCertificate) {
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");
@@ -104,6 +107,7 @@ public class Application {
this.pemDeployKey = pemDeployKey;
this.rotations = List.copyOf(Objects.requireNonNull(rotations, "rotations cannot be null"));
this.rotationStatus = ImmutableMap.copyOf(Objects.requireNonNull(rotationStatus, "rotationStatus cannot be null"));
+ this.applicationCertificate = Objects.requireNonNull(applicationCertificate, "applicationCertificate cannot be null");
}
public ApplicationId id() { return id; }
@@ -250,6 +254,10 @@ public class Application {
.orElse(RotationStatus.unknown);
}
+ 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 61a4e1e8656..0756d3006ea 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
@@ -26,6 +26,8 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Hostname;
import com.yahoo.vespa.hosted.controller.api.identifiers.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.BuildService;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificate;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificateProvider;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint;
@@ -128,6 +130,8 @@ public class ApplicationController {
private final Clock clock;
private final BooleanFlag redirectLegacyDnsFlag;
private final DeploymentTrigger deploymentTrigger;
+ private final BooleanFlag provisionApplicationCertificate;
+ private final ApplicationCertificateProvider applicationCertificateProvider;
ApplicationController(Controller controller, CuratorDb curator,
AccessControl accessControl, RotationsConfig rotationsConfig,
@@ -148,6 +152,9 @@ public class ApplicationController {
this.rotationRepository = new RotationRepository(rotationsConfig, this, curator);
this.deploymentTrigger = new DeploymentTrigger(controller, buildService, clock);
+ this.provisionApplicationCertificate = Flags.PROVISION_APPLICATION_CERTIFICATE.bindTo(controller.flagSource());
+ this.applicationCertificateProvider = controller.applicationCertificateProvider();
+
// Update serialization format of all applications
Once.after(Duration.ofMinutes(1), () -> {
Instant start = clock.instant();
@@ -290,6 +297,7 @@ public class ApplicationController {
ApplicationVersion applicationVersion;
ApplicationPackage applicationPackage;
Set<ContainerEndpoint> endpoints = new LinkedHashSet<>();
+ ApplicationCertificate applicationCertificate;
try (Lock lock = lock(applicationId)) {
LockedApplication application = new LockedApplication(require(applicationId), lock);
@@ -344,6 +352,10 @@ public class ApplicationController {
})
.forEach(endpoints::add);
+ // Get application certificate (provisions a new certificate if missing)
+ application = withApplicationCertificate(application);
+ applicationCertificate = application.get().applicationCertificate().orElse(null);
+
// Update application with information from application package
if ( ! preferOldestVersion
&& ! application.get().deploymentJobs().deployedInternally()
@@ -354,7 +366,7 @@ public class ApplicationController {
// Carry out deployment without holding the application lock.
options = withVersion(platformVersion, options);
- ActivateResult result = deploy(applicationId, applicationPackage, zone, options, endpoints);
+ ActivateResult result = deploy(applicationId, applicationPackage, zone, options, endpoints, applicationCertificate);
lockOrThrow(applicationId, application ->
store(application.withNewDeployment(zone, applicationVersion, platformVersion, clock.instant(),
@@ -421,7 +433,7 @@ public class ApplicationController {
artifactRepository.getSystemApplicationPackage(application.id(), zone, version)
);
DeployOptions options = withVersion(version, DeployOptions.none());
- return deploy(application.id(), applicationPackage, zone, options, Set.of());
+ return deploy(application.id(), applicationPackage, zone, options, Set.of(), /* No application cert */ null);
} else {
throw new RuntimeException("This system application does not have an application package: " + application.id().toShortString());
}
@@ -429,16 +441,16 @@ public class ApplicationController {
/** Deploys the given tester application to the given zone. */
public ActivateResult deployTester(TesterId tester, ApplicationPackage applicationPackage, ZoneId zone, DeployOptions options) {
- return deploy(tester.id(), applicationPackage, zone, options, Set.of());
+ return deploy(tester.id(), applicationPackage, zone, options, Set.of(), /* No application cert for tester*/ null);
}
private ActivateResult deploy(ApplicationId application, ApplicationPackage applicationPackage,
ZoneId zone, DeployOptions deployOptions,
- Set<ContainerEndpoint> endpoints) {
+ Set<ContainerEndpoint> endpoints, ApplicationCertificate applicationCertificate) {
DeploymentId deploymentId = new DeploymentId(application, zone);
try {
ConfigServer.PreparedApplication preparedApplication =
- configServer.deploy(deploymentId, deployOptions, Set.of(), endpoints, applicationPackage.zippedContent());
+ configServer.deploy(deploymentId, deployOptions, Set.of(), endpoints, applicationCertificate, applicationPackage.zippedContent());
return new ActivateResult(new RevisionId(applicationPackage.hash()), preparedApplication.prepareResponse(),
applicationPackage.zippedContent().length);
} finally {
@@ -481,6 +493,18 @@ public class ApplicationController {
});
}
+ private LockedApplication withApplicationCertificate(LockedApplication application) {
+ ApplicationId applicationId = application.get().id();
+
+ // TODO: Verify that the application is deploying to a zone where certificate provisioning is enabled
+ boolean provisionCertificate = provisionApplicationCertificate.with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
+ if (provisionCertificate) {
+ application = application.withApplicationCertificate(
+ Optional.of(applicationCertificateProvider.requestCaSignedCertificate(applicationId)));
+ }
+ return application;
+ }
+
private ActivateResult unexpectedDeployment(ApplicationId application, ZoneId zone) {
Log logEntry = new Log();
logEntry.level = "WARNING";
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 d87d52f2c12..ed81d08c533 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
@@ -9,12 +9,12 @@ import com.yahoo.config.provision.CloudName;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneApi;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.hosted.controller.api.integration.BuildService;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService;
import com.yahoo.vespa.hosted.controller.api.integration.RunDataStore;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificateProvider;
import com.yahoo.vespa.hosted.controller.api.integration.chef.Chef;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore;
@@ -84,6 +84,7 @@ public class Controller extends AbstractComponent {
private final AuditLogger auditLogger;
private final FlagSource flagSource;
private final NameServiceForwarder nameServiceForwarder;
+ private final ApplicationCertificateProvider applicationCertificateProvider;
private final MavenRepository mavenRepository;
/**
@@ -98,12 +99,12 @@ public class Controller extends AbstractComponent {
AccessControl accessControl,
ArtifactRepository artifactRepository, ApplicationStore applicationStore, TesterCloud testerCloud,
BuildService buildService, RunDataStore runDataStore, Mailer mailer, FlagSource flagSource,
- MavenRepository mavenRepository) {
+ MavenRepository mavenRepository, ApplicationCertificateProvider applicationCertificateProvider) {
this(curator, rotationsConfig, gitHub, zoneRegistry,
configServer, metricsService, routingGenerator, chef,
Clock.systemUTC(), accessControl, artifactRepository, applicationStore, testerCloud,
buildService, runDataStore, com.yahoo.net.HostName::getLocalhost, mailer, flagSource,
- mavenRepository);
+ mavenRepository, applicationCertificateProvider);
}
public Controller(CuratorDb curator, RotationsConfig rotationsConfig, GitHub gitHub,
@@ -113,7 +114,7 @@ public class Controller extends AbstractComponent {
AccessControl accessControl,
ArtifactRepository artifactRepository, ApplicationStore applicationStore, TesterCloud testerCloud,
BuildService buildService, RunDataStore runDataStore, Supplier<String> hostnameSupplier,
- Mailer mailer, FlagSource flagSource, MavenRepository mavenRepository) {
+ Mailer mailer, FlagSource flagSource, MavenRepository mavenRepository, ApplicationCertificateProvider applicationCertificateProvider) {
this.hostnameSupplier = Objects.requireNonNull(hostnameSupplier, "HostnameSupplier cannot be null");
this.curator = Objects.requireNonNull(curator, "Curator cannot be null");
@@ -126,6 +127,7 @@ public class Controller extends AbstractComponent {
this.mailer = Objects.requireNonNull(mailer, "Mailer cannot be null");
this.flagSource = Objects.requireNonNull(flagSource, "FlagSource cannot be null");
this.nameServiceForwarder = new NameServiceForwarder(curator);
+ this.applicationCertificateProvider = Objects.requireNonNull(applicationCertificateProvider);
this.mavenRepository = Objects.requireNonNull(mavenRepository, "MavenRepository cannot be null");
jobController = new JobController(this, runDataStore, Objects.requireNonNull(testerCloud));
@@ -304,6 +306,10 @@ public class Controller extends AbstractComponent {
return auditLogger;
}
+ public ApplicationCertificateProvider applicationCertificateProvider() {
+ return applicationCertificateProvider;
+ }
+
/** Returns all other roles the given tenant role implies. */
public Set<Role> impliedRoles(TenantRole role) {
return Stream.concat(Roles.tenantRoles(role.tenant()).stream(),
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 02b0afdd48f..294dc10d0bd 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
@@ -10,6 +10,7 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService;
import com.yahoo.vespa.hosted.controller.api.integration.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.organization.IssueId;
@@ -59,6 +60,7 @@ public class LockedApplication {
private final Optional<String> pemDeployKey;
private final List<AssignedRotation> rotations;
private final Map<HostName, RotationStatus> rotationStatus;
+ private final Optional<ApplicationCertificate> applicationCertificate;
/**
* Used to create a locked application
@@ -72,7 +74,7 @@ public class LockedApplication {
application.deployments(),
application.deploymentJobs(), application.change(), application.outstandingChange(),
application.ownershipIssueId(), application.owner(), application.majorVersion(), application.metrics(),
- application.pemDeployKey(), application.assignedRotations(), application.rotationStatus());
+ application.pemDeployKey(), application.assignedRotations(), application.rotationStatus(), application.applicationCertificate());
}
private LockedApplication(Lock lock, ApplicationId id, Instant createdAt,
@@ -80,7 +82,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, Map<HostName, RotationStatus> rotationStatus) {
+ List<AssignedRotation> rotations, Map<HostName, RotationStatus> rotationStatus, Optional<ApplicationCertificate> applicationCertificate) {
this.lock = lock;
this.id = id;
this.createdAt = createdAt;
@@ -97,41 +99,42 @@ 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);
+ rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
public LockedApplication withJobCompletion(long projectId, JobType jobType, JobStatus.JobRun completion,
@@ -139,14 +142,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);
+ pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
public LockedApplication withNewDeployment(ZoneId zone, ApplicationVersion applicationVersion, Version version,
@@ -197,45 +200,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);
+ rotations, rotationStatus, applicationCertificate);
}
public LockedApplication with(DeploymentSpec deploymentSpec) {
return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, owner, majorVersion, metrics, pemDeployKey,
- rotations, rotationStatus);
+ rotations, rotationStatus, applicationCertificate);
}
public LockedApplication with(ValidationOverrides validationOverrides) {
return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion,
- metrics, pemDeployKey, rotations, rotationStatus);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
public LockedApplication withChange(Change change) {
return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion,
- metrics, pemDeployKey, rotations, rotationStatus);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
public LockedApplication withOutstandingChange(Change outstandingChange) {
return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion,
- metrics, pemDeployKey, rotations, rotationStatus);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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);
+ majorVersion, metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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);
+ rotations, rotationStatus, applicationCertificate);
}
/** Set a major version for this, or set to null to remove any major version override */
@@ -243,33 +246,40 @@ 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);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
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);
+ metrics, Optional.ofNullable(pemDeployKey), rotations, rotationStatus, applicationCertificate);
}
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);
+ metrics, pemDeployKey, assignedRotations, rotationStatus, applicationCertificate);
}
public LockedApplication withRotationStatus(Map<HostName, RotationStatus> rotationStatus) {
return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange, ownershipIssueId, owner, majorVersion,
- metrics, pemDeployKey, rotations, rotationStatus);
+ 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);
+ }
+
+
/** Don't expose non-leaf sub-objects. */
private LockedApplication with(Deployment deployment) {
Map<ZoneId, Deployment> deployments = new LinkedHashMap<>(this.deployments);
@@ -280,7 +290,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);
+ metrics, pemDeployKey, rotations, rotationStatus, applicationCertificate);
}
@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 23c76b95950..0c045eb7253 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
@@ -15,6 +15,7 @@ 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.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;
@@ -89,6 +90,7 @@ public class ApplicationSerializer {
private final String rotationsField = "endpoints";
private final String deprecatedRotationField = "rotation";
private final String rotationStatusField = "rotationStatus";
+ private final String applicationCertificateField = "applicationCertificate";
// Deployment fields
private final String zoneField = "zone";
@@ -183,6 +185,7 @@ public class ApplicationSerializer {
rotationsToSlime(application.assignedRotations(), root, rotationsField);
assignedRotationsToSlime(application.assignedRotations(), root, assignedRotationsField);
toSlime(application.rotationStatus(), root.setArray(rotationStatusField));
+ application.applicationCertificate().ifPresent(cert -> root.setString(applicationCertificateField, cert.secretsKeyNamePrefix()));
return slime;
}
@@ -365,10 +368,11 @@ public class ApplicationSerializer {
Optional<String> pemDeployKey = 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);
return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs,
deploying, outstandingChange, ownershipIssueId, owner, majorVersion, metrics,
- pemDeployKey, assignedRotations, rotationStatus);
+ pemDeployKey, assignedRotations, rotationStatus, applicationCertificate);
}
private List<Deployment> deploymentsFromSlime(Inspector array) {
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 5748ad4f55c..dbf983a5bab 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
@@ -5,6 +5,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.Slime;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.athenz.api.AthenzDomain;
@@ -35,11 +36,11 @@ import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMailer;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMavenRepository;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockRunDataStore;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock;
import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzDbMock;
+import com.yahoo.vespa.hosted.controller.integration.ApplicationCertificateMock;
import com.yahoo.vespa.hosted.controller.integration.ApplicationStoreMock;
import com.yahoo.vespa.hosted.controller.integration.ArtifactRepositoryMock;
import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock;
@@ -353,7 +354,8 @@ public final class ControllerTester {
() -> "test-controller",
new MockMailer(),
new InMemoryFlagSource(),
- new MockMavenRepository());
+ new MockMavenRepository(),
+ new ApplicationCertificateMock());
// Calculate initial versions
controller.updateVersionStatus(VersionStatus.compute(controller));
return controller;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationCertificateMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationCertificateMock.java
new file mode 100644
index 00000000000..3246a260217
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationCertificateMock.java
@@ -0,0 +1,14 @@
+// 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.integration;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificate;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificateProvider;
+
+public class ApplicationCertificateMock implements ApplicationCertificateProvider {
+
+ @Override
+ public ApplicationCertificate requestCaSignedCertificate(ApplicationId applicationId) {
+ return new ApplicationCertificate(String.format("vespa.tls.%s.%s", applicationId.tenant(),applicationId.application()));
+ }
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
index 946cb1c67c0..4841b6c0c12 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
@@ -15,6 +15,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Hostname;
import com.yahoo.vespa.hosted.controller.api.identifiers.Identifier;
import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId;
+import com.yahoo.vespa.hosted.controller.api.integration.certificates.ApplicationCertificate;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer;
@@ -225,7 +226,7 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
@Override
public PreparedApplication deploy(DeploymentId deployment, DeployOptions deployOptions, Set<String> rotationNames,
- Set<ContainerEndpoint> containerEndpoints, byte[] content) {
+ Set<ContainerEndpoint> containerEndpoints, ApplicationCertificate applicationCertificate, byte[] content) {
lastPrepareVersion = deployOptions.vespaVersion.map(Version::fromString).orElse(null);
if (prepareException != null) {
RuntimeException prepareException = this.prepareException;
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 f9725715ce5..7390e0b2068 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
@@ -11,6 +11,7 @@ import com.yahoo.config.provision.RegionName;
import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService;
+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;
@@ -121,7 +122,8 @@ public class ApplicationSerializerTest {
new MetricsService.ApplicationMetrics(0.5, 0.9),
Optional.of("-----BEGIN PUBLIC KEY-----\n∠( ᐛ 」∠)_\n-----END PUBLIC KEY-----"),
List.of(new AssignedRotation(new ClusterSpec.Id("foo"), EndpointId.default_(), new RotationId("my-rotation"), Set.of())),
- rotationStatus);
+ rotationStatus,
+ Optional.of(new ApplicationCertificate("vespa.certificate")));
Application serialized = applicationSerializer.fromSlime(applicationSerializer.toSlime(original));
@@ -159,6 +161,8 @@ 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());
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 6f612005524..53476a2e42f 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
@@ -92,6 +92,7 @@ public class ControllerContainerTest {
" <component id='com.yahoo.vespa.hosted.controller.integration.ApplicationStoreMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMailer'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.integration.ApplicationCertificateMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMavenRepository'/>\n" +
" <handler id='com.yahoo.vespa.hosted.controller.restapi.deployment.DeploymentApiHandler'>\n" +
" <binding>http://*/deployment/v1/*</binding>\n" +