aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorJon Marius Venstad <jonmv@users.noreply.github.com>2019-02-11 13:23:31 +0100
committerGitHub <noreply@github.com>2019-02-11 13:23:31 +0100
commitee45d854e0a540d8ed954cb4dd7749644f93de12 (patch)
treeec55c0d0bc43bb36fb6474642c5f18f8bbf14a7c /controller-server
parenta73d44d194df6296976d8f53116c835aa992015e (diff)
parent1f3d5bb43009736f3a1478cebecdc6e933ee7ea2 (diff)
Merge branch 'master' into jvenstad/deploy-without-application-lock
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java46
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java25
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json6
7 files changed, 84 insertions, 39 deletions
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 e5fe8a68444..66ba44ec129 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
@@ -276,17 +276,17 @@ public class ApplicationController {
.map(app -> new LockedApplication(app, lock))
.orElseGet(() -> new LockedApplication(createApplication(applicationId, Optional.empty()), lock));
- boolean canDeployDirectly = options.deployDirectly || zone.environment().isManuallyDeployed();
+ boolean manuallyDeployed = options.deployDirectly || zone.environment().isManuallyDeployed();
boolean preferOldestVersion = options.deployCurrentVersion;
// Determine versions to use.
- if (canDeployDirectly) {
- platformVersion = options.vespaVersion.map(Version::new).orElse(application.get().deploymentSpec().majorVersion()
- .flatMap(this::lastCompatibleVersion)
- .orElse(controller.systemVersion()));
+ if (manuallyDeployed) {
applicationVersion = applicationVersionFromDeployer.orElse(ApplicationVersion.unknown);
applicationPackage = applicationPackageFromDeployer.orElseThrow(
() -> new IllegalArgumentException("Application package must be given when deploying to " + zone));
+ platformVersion = options.vespaVersion.map(Version::new).orElse(applicationPackage.deploymentSpec().majorVersion()
+ .flatMap(this::lastCompatibleVersion)
+ .orElse(controller.systemVersion()));
}
else {
JobType jobType = JobType.from(controller.system(), zone)
@@ -320,8 +320,10 @@ public class ApplicationController {
});
// Update application with information from application package
- if ( ! preferOldestVersion && ! application.get().deploymentJobs().deployedInternally())
- // TODO jvenstad: Store only on submissions (not on deployments to dev!!)
+ if ( ! preferOldestVersion
+ && ! application.get().deploymentJobs().deployedInternally()
+ && ! zone.environment().isManuallyDeployed())
+ // TODO jvenstad: Store only on submissions
storeWithUpdatedConfig(application, applicationPackage);
}
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 19ff6df3ccb..1cac93a9971 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
@@ -49,7 +49,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFact
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Log;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Logs;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
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.RunId;
@@ -70,7 +69,6 @@ import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.athenz.impl.ZmsClientFacade;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel;
-import com.yahoo.vespa.hosted.controller.maintenance.InfrastructureUpgrader;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
import com.yahoo.vespa.hosted.controller.restapi.MessageResponse;
import com.yahoo.vespa.hosted.controller.restapi.ResourceResponse;
@@ -95,13 +93,11 @@ import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Scanner;
-import java.util.function.Function;
import java.util.logging.Level;
import static java.util.stream.Collectors.joining;
@@ -178,6 +174,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
if (path.matches("/application/v4/tenant/{tenant}")) return tenant(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/application")) return applications(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), request);
+ if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deploying")) return deploying(path.get("tenant"), path.get("application"), request);
+ if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deploying/pin")) return deploying(path.get("tenant"), path.get("application"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/logs")) return logs(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request.getUri().getQuery());
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job")) return JobControllerApiHandlerHelper.jobTypeResponse(controller, appIdFromPath(path), request.getUri());
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}")) return JobControllerApiHandlerHelper.runResponse(controller.jobController().runs(appIdFromPath(path), jobTypeFromPath(path)), request.getUri());
@@ -682,6 +680,18 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return new SlimeJsonResponse(slime);
}
+ private HttpResponse deploying(String tenant, String application, HttpRequest request) {
+ Application app = controller.applications().require(ApplicationId.from(tenant, application, "default"));
+ Slime slime = new Slime();
+ Cursor root = slime.setObject();
+ if (!app.change().isEmpty()) {
+ app.change().platform().ifPresent(version -> root.setString("platform", version.toString()));
+ app.change().application().ifPresent(applicationVersion -> root.setString("application", applicationVersion.id()));
+ root.setBool("pinned", app.change().isPinned());
+ }
+ return new SlimeJsonResponse(slime);
+ }
+
private HttpResponse suspended(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
ZoneId.from(environment, region));
@@ -882,12 +892,15 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
}
// To avoid second guessing the orchestrated upgrades of system applications
// we don't allow to deploy these during an system upgrade (i.e when new vespa is being rolled out)
- Version version = wantedSystemVersion(zone, SystemApplication.zone);
- if (!controller.systemVersion().equals(version)) {
- throw new RuntimeException("Deployment of system applications during a system upgrade is not allowed");
+ if (controller.versionStatus().isUpgrading()) {
+ throw new IllegalArgumentException("Deployment of system applications during a system upgrade is not allowed");
+ }
+ Optional<VespaVersion> systemVersion = controller.versionStatus().systemVersion();
+ if (systemVersion.isEmpty()) {
+ throw new IllegalArgumentException("Deployment of system applications is not permitted until system version is determined");
}
ActivateResult result = controller.applications()
- .deploySystemApplicationPackage(SystemApplication.zone, zone, version);
+ .deploySystemApplicationPackage(SystemApplication.zone, zone, systemVersion.get().versionNumber());
return new SlimeJsonResponse(toSlime(result));
}
@@ -956,23 +969,6 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return new SlimeJsonResponse(toSlime(result));
}
- /** Find the minimum value of a version field in a zone */
- private Version wantedSystemVersion(ZoneId zone, SystemApplication application) {
- try {
- return controller.configServer()
- .nodeRepository()
- .list(zone, application.id())
- .stream()
- .filter(node -> node.state().equals(Node.State.active))
- .map(Node::wantedVersion)
- .min(Comparator.naturalOrder()).orElseThrow(
- () -> new RuntimeException("System version not found in node repo"));
- } catch (Exception e) {
- throw new RuntimeException(String.format("Failed to get version for %s in %s: %s",
- application.id(), zone, Exceptions.toMessageString(e)));
- }
- }
-
private HttpResponse deleteTenant(String tenantName, HttpRequest request) {
Optional<Tenant> tenant = controller.tenants().tenant(tenantName);
if ( ! tenant.isPresent()) return ErrorResponse.notFoundError("Could not delete tenant '" + tenantName + "': Tenant not found"); // NOTE: The Jersey implementation would silently ignore this
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 e367de35d46..26410280566 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
@@ -72,6 +72,12 @@ public class VersionStatus {
return versions().stream().filter(VespaVersion::isSystemVersion).findFirst();
}
+ /** Returns whether the system is currently upgrading */
+ public boolean isUpgrading() {
+ return systemVersion().map(VespaVersion::versionNumber).orElse(Version.emptyVersion)
+ .isBefore(controllerVersion().map(VespaVersion::versionNumber).orElse(Version.emptyVersion));
+ }
+
/**
* Lists all currently active Vespa versions, with deployment statistics,
* sorted from lowest to highest version number.
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 06417da8157..32068b006f0 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
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller;
import com.yahoo.component.Version;
+import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
@@ -426,7 +427,7 @@ public class ControllerTest {
}
@Test
- public void testDeployDirectly() {
+ public void testIntegrationTestDeployment() {
DeploymentTester tester = new DeploymentTester();
Version six = Version.fromString("6.1");
tester.upgradeSystem(six);
@@ -461,6 +462,28 @@ public class ControllerTest {
}
@Test
+ public void testDevDeployment() {
+ DeploymentTester tester = new DeploymentTester();
+ ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ .environment(Environment.dev)
+ .majorVersion(6)
+ .region("us-east-1")
+ .build();
+
+ // Create application
+ Application app = tester.createApplication("app1", "tenant1", 1, 2L);
+ ZoneId zone = ZoneId.from("dev", "us-east-1");
+
+ // Deploy
+ tester.controller().applications().deploy(app.id(), zone, Optional.of(applicationPackage), DeployOptions.none());
+ assertTrue("Application deployed and activated",
+ tester.controllerTester().configServer().application(app.id()).get().activated());
+ assertTrue("No job status added",
+ tester.applications().require(app.id()).deploymentJobs().jobStatus().isEmpty());
+ assertEquals("DeploymentSpec is not persisted", DeploymentSpec.empty, tester.applications().require(app.id()).deploymentSpec());
+ }
+
+ @Test
public void testSuspension() {
DeploymentTester tester = new DeploymentTester();
Application app = tester.createApplication("app1", "tenant1", 1, 11L);
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 7697cf00b86..552bcd34fe4 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
@@ -392,27 +392,39 @@ public class ApplicationApiTest extends ControllerContainerTest {
.userIdentity(USER_ID)
.data("6.1.0"),
"{\"message\":\"Triggered pin to 6.1 for tenant1.application1\"}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying", GET)
+ .userIdentity(USER_ID), "{\"platform\":\"6.1\",\"pinned\":true}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying/pin", GET)
+ .userIdentity(USER_ID), "{\"platform\":\"6.1\",\"pinned\":true}");
// DELETE only the pin to a given version
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying/pin", DELETE)
.userIdentity(USER_ID),
"{\"message\":\"Changed deployment from 'pin to 6.1' to 'upgrade to 6.1' for application 'tenant1.application1'\"}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying", GET)
+ .userIdentity(USER_ID), "{\"platform\":\"6.1\",\"pinned\":false}");
// POST pinning again
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying/pin", POST)
.userIdentity(USER_ID)
.data("6.1"),
"{\"message\":\"Triggered pin to 6.1 for tenant1.application1\"}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying", GET)
+ .userIdentity(USER_ID), "{\"platform\":\"6.1\",\"pinned\":true}");
// DELETE only the version, but leave the pin
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying/platform", DELETE)
.userIdentity(USER_ID),
"{\"message\":\"Changed deployment from 'pin to 6.1' to 'pin to current platform' for application 'tenant1.application1'\"}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying", GET)
+ .userIdentity(USER_ID), "{\"pinned\":true}");
// DELETE also the pin to a given version
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying/pin", DELETE)
.userIdentity(USER_ID),
"{\"message\":\"Changed deployment from 'pin to current platform' to 'no change' for application 'tenant1.application1'\"}");
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/deploying", GET)
+ .userIdentity(USER_ID), "{}");
// POST a pause to a production job
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/default/job/production-us-west-1/pause", POST)
@@ -672,6 +684,12 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST (deploy) a system application with an application package
HttpEntity noAppEntity = createApplicationDeployData(Optional.empty(), true);
tester.assertResponse(request("/application/v4/tenant/hosted-vespa/application/routing/environment/prod/region/us-central-1/instance/default/deploy", POST)
+ .data(noAppEntity)
+ .userIdentity(USER_ID),
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Deployment of system applications during a system upgrade is not allowed\"}",
+ 400);
+ tester.upgradeSystem(tester.controller().versionStatus().controllerVersion().get().versionNumber());
+ tester.assertResponse(request("/application/v4/tenant/hosted-vespa/application/routing/environment/prod/region/us-central-1/instance/default/deploy", POST)
.data(noAppEntity)
.userIdentity(USER_ID),
new File("deploy-result.json"));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json
index 443a2c23b6a..3744e44152a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json
@@ -66,7 +66,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
},
"lastCompleted": {
@@ -80,7 +80,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
},
"lastSuccess": {
@@ -94,7 +94,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
}
},
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json
index 64c92f9cde4..822bc447d8d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json
@@ -66,7 +66,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
},
"lastCompleted": {
@@ -80,7 +80,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
},
"lastSuccess": {
@@ -94,7 +94,7 @@
"gitCommit": "commit1"
}
},
- "reason": "Testing deployment for production-us-central-1 (platform 6.1, application 1.0.42-commit1)",
+ "reason": "Testing last changes outside prod",
"at": "(ignore)"
}
},