summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <freva@users.noreply.github.com>2021-09-27 15:17:06 +0200
committerGitHub <noreply@github.com>2021-09-27 15:17:06 +0200
commit1654f886aa22dadab66a0d0b30024bbc46743ee1 (patch)
tree36b61fcbe2d3d8ca2a6770b9a4c79463acc769e1
parentc0cdd0f9a79a56a51d59da9398c4f13292404746 (diff)
parentecdb50a1446922301a6c4e013e09e068c8f48739 (diff)
Merge pull request #19289 from vespa-engine/ogronnesby/create-application-on-deploy
Create application on deploy in all systems
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java62
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java30
3 files changed, 104 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..98ac789de04 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
@@ -1967,6 +1967,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.flatMap(options -> optional("vespaVersion", options))
.map(Version::fromString);
+ ensureApplicationExists(TenantAndApplicationId.from(id), request);
+
controller.jobController().deploy(id, type, version, applicationPackage);
RunId runId = controller.jobController().last(id, type).get().id();
Slime slime = new Slime();
@@ -2617,6 +2619,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
applicationPackage,
Optional.of(requireUserPrincipal(request)));
+ ensureApplicationExists(TenantAndApplicationId.from(tenant, application), request);
+
return JobControllerApiHandlerHelper.submitResponse(controller.jobController(),
tenant,
application,
@@ -2718,5 +2722,13 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.anyMatch(definition -> definition == RoleDefinition.hostedOperator);
}
+ private void ensureApplicationExists(TenantAndApplicationId id, HttpRequest request) {
+ if (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);
+ }
+ }
+
}
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..8c6d368d93a 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,42 @@ 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());
+ }
+
+ @Test
+ public void create_application_on_submit() {
+ var application = ApplicationName.from("unique");
+ var applicationPackage = new ApplicationPackageBuilder()
+ .trustDefaultCertificate()
+ .build();
+
+ assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isEmpty());
+
+ var data = ApplicationApiTest.createApplicationSubmissionData(applicationPackage, 123);
+
+ tester.assertResponse(
+ request("/application/v4/tenant/scoober/application/unique/submit", POST)
+ .data(data)
+ .roles(Set.of(Role.developer(tenantName))),
+ "{\"message\":\"Application package version: 1.0.1-commit1, source revision of repository 'repository1', branch 'master' with commit 'commit1', by a@b, built against 6.1 at 1970-01-01T00:00:01Z\"}");
+
+ assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isPresent());
+ }
+
private ApplicationPackageBuilder prodBuilder() {
return new ApplicationPackageBuilder()
.instances("default")
@@ -264,8 +303,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("") +
+ "}";
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index 5bd7afcb917..596a0b186db 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -1657,6 +1657,36 @@ public class ApplicationApiTest extends ControllerContainerTest {
403);
}
+ @Test
+ public void create_application_on_deploy() {
+ // Setup
+ createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID);
+ addUserToHostedOperatorRole(HostedAthenzIdentities.from(HOSTED_VESPA_OPERATOR));
+
+ // Create tenant
+ tester.assertResponse(request("/application/v4/tenant/tenant1", POST).userIdentity(USER_ID)
+ .data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
+ .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
+ new File("tenant-without-applications.json"));
+
+ // Deploy application
+ var id = ApplicationId.from("tenant1", "application1", "instance1");
+ var appId = TenantAndApplicationId.from(id);
+ var entity = createApplicationDeployData(applicationPackageInstance1);
+
+ assertTrue(tester.controller().applications().getApplication(appId).isEmpty());
+
+ // POST (deploy) an application to start a manual deployment to dev
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploy/dev-us-east-1/", POST)
+ .data(entity)
+ .oktaIdentityToken(OKTA_IT)
+ .oktaAccessToken(OKTA_AT)
+ .userIdentity(USER_ID),
+ "{\"message\":\"Deployment started in run 1 of dev-us-east-1 for tenant1.application1.instance1. This may take about 15 minutes the first time.\",\"run\":1}");
+
+ assertTrue(tester.controller().applications().getApplication(appId).isPresent());
+ }
+
private static String serializeInstant(Instant i) {
return DateTimeFormatter.ISO_INSTANT.format(i.truncatedTo(ChronoUnit.SECONDS));
}