diff options
author | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-09-24 15:28:18 +0200 |
---|---|---|
committer | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-09-24 15:28:18 +0200 |
commit | 60c19684890949c64dbaaa0d67706b7216f513b1 (patch) | |
tree | fb54718df52367e9c7dd0233088573375e41c635 /controller-server | |
parent | 13af00d9970476ed82233cf6592f76e0f163264e (diff) |
Create application on deploy in public systems
Diffstat (limited to 'controller-server')
2 files changed, 63 insertions, 0 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 1a2acb82348..04a50ccef84 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -1,6 +1,7 @@ // Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.application; +import ai.vespa.hosted.api.MultiPartStreamer; import ai.vespa.hosted.api.Signatures; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -1967,6 +1968,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { .flatMap(options -> optional("vespaVersion", options)) .map(Version::fromString); + ensureInstanceExistsForPublic(id, request); + controller.jobController().deploy(id, type, version, applicationPackage); RunId runId = controller.jobController().last(id, type).get().id(); Slime slime = new Slime(); @@ -2617,6 +2620,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { applicationPackage, Optional.of(requireUserPrincipal(request))); + ensureApplicationExistsForPublic(TenantAndApplicationId.from(tenant, application), request); + return JobControllerApiHandlerHelper.submitResponse(controller.jobController(), tenant, application, @@ -2718,5 +2723,21 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { .anyMatch(definition -> definition == RoleDefinition.hostedOperator); } + private void ensureApplicationExistsForPublic(TenantAndApplicationId id, HttpRequest request) { + if (controller.system().isPublic() && controller.applications().getApplication(id).isEmpty()) { + log.fine("Application does not exist in public, creating: " + id); + var credentials = accessControlRequests.credentials(id.tenant(), null /* not used on public */ , request.getJDiscRequest()); + controller.applications().createApplication(id, credentials); + } + } + + private void ensureInstanceExistsForPublic(ApplicationId id, HttpRequest request) { + ensureApplicationExistsForPublic(TenantAndApplicationId.from(id), request); + if (controller.system().isPublic() && controller.applications().getInstance(id).isEmpty()) { + log.fine("Instance does not exist in public, creating: " + id); + controller.applications().createInstance(id); + } + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java index 5f76a30bf45..527eacba245 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java @@ -1,6 +1,7 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.restapi.application; +import ai.vespa.hosted.api.MultiPartStreamer; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.InstanceName; @@ -10,10 +11,12 @@ import com.yahoo.vespa.flags.PermanentFlags; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.LockedTenant; import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId; +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.secrets.TenantSecretStore; import com.yahoo.vespa.hosted.controller.api.role.Role; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; +import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.restapi.ContainerTester; @@ -232,6 +235,22 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { 200); } + @Test + public void create_application_on_deploy() { + var application = ApplicationName.from("unique"); + var applicationPackage = new ApplicationPackageBuilder().build(); + + assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isEmpty()); + + tester.assertResponse( + request("/application/v4/tenant/scoober/application/unique/instance/default/deploy/dev-aws-us-east-1c", POST) + .data(createApplicationDeployData(Optional.of(applicationPackage), Optional.empty(), true)) + .roles(Set.of(Role.developer(tenantName))), + "{\"message\":\"Deployment started in run 1 of dev-aws-us-east-1c for scoober.unique. This may take about 15 minutes the first time.\",\"run\":1}"); + + assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isPresent()); + } + private ApplicationPackageBuilder prodBuilder() { return new ApplicationPackageBuilder() .instances("default") @@ -264,8 +283,31 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { JobType.productionAwsUsEast1c, Optional.empty(), applicationPackage); + } + private MultiPartStreamer createApplicationDeployData(Optional<ApplicationPackage> applicationPackage, + Optional<ApplicationVersion> applicationVersion, boolean deployDirectly) { + MultiPartStreamer streamer = new MultiPartStreamer(); + streamer.addJson("deployOptions", deployOptions(deployDirectly, applicationVersion)); + applicationPackage.ifPresent(ap -> streamer.addBytes("applicationZip", ap.zippedContent())); + return streamer; + } + + private String deployOptions(boolean deployDirectly, Optional<ApplicationVersion> applicationVersion) { + return "{\"vespaVersion\":null," + + "\"ignoreValidationErrors\":false," + + "\"deployDirectly\":" + deployDirectly + + applicationVersion.map(version -> + "," + + "\"buildNumber\":" + version.buildNumber().getAsLong() + "," + + "\"sourceRevision\":{" + + "\"repository\":\"" + version.source().get().repository() + "\"," + + "\"branch\":\"" + version.source().get().branch() + "\"," + + "\"commit\":\"" + version.source().get().commit() + "\"" + + "}" + ).orElse("") + + "}"; } } |