summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/pom.xml4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java15
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiHandler.java60
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tls/ControllerSslContextFactoryProvider.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java16
9 files changed, 115 insertions, 14 deletions
diff --git a/controller-server/pom.xml b/controller-server/pom.xml
index 7e27a727bfd..23d2bfc33d4 100644
--- a/controller-server/pom.xml
+++ b/controller-server/pom.xml
@@ -8,12 +8,12 @@
<parent>
<groupId>com.yahoo.vespa</groupId>
<artifactId>parent</artifactId>
- <version>6-SNAPSHOT</version>
+ <version>7-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<artifactId>controller-server</artifactId>
<packaging>container-plugin</packaging>
- <version>6-SNAPSHOT</version>
+ <version>7-SNAPSHOT</version>
<dependencies>
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 82355144b20..963dca8d3b5 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
@@ -153,9 +153,8 @@ public class Application {
}
/**
- * Overrides the preferred major version for this application.
- * This overrides the major version set in the deployment spec (if any) and the major version the system
- * wants to use.
+ * Overrides the system major version for this application. This override takes effect if the deployment
+ * spec does not specify a major version.
*/
public Optional<Integer> majorVersion() { return majorVersion; }
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 3185b7d5f45..4a8670b9f9e 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
@@ -58,6 +58,7 @@ import com.yahoo.vespa.hosted.controller.rotation.RotationLock;
import com.yahoo.vespa.hosted.controller.rotation.RotationRepository;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
+import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import com.yahoo.vespa.hosted.rotation.config.RotationsConfig;
import com.yahoo.yolean.Exceptions;
@@ -67,8 +68,10 @@ import java.net.URI;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Deque;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
@@ -277,7 +280,9 @@ public class ApplicationController {
ApplicationVersion applicationVersion;
ApplicationPackage applicationPackage;
if (canDeployDirectly) {
- platformVersion = options.vespaVersion.map(Version::new).orElse(controller.systemVersion());
+ platformVersion = options.vespaVersion.map(Version::new).orElse(application.get().deploymentSpec().majorVersion()
+ .flatMap(this::lastCompatibleVersion)
+ .orElse(controller.systemVersion()));
applicationVersion = applicationVersionFromDeployer.orElse(ApplicationVersion.unknown);
applicationPackage = applicationPackageFromDeployer.orElseThrow(
() -> new IllegalArgumentException("Application package must be given when deploying to " + zone));
@@ -727,6 +732,14 @@ public class ApplicationController {
});
}
+ /** Returns the latest known version within the given major. */
+ private Optional<Version> lastCompatibleVersion(int targetMajorVersion) {
+ return controller.versionStatus().versions().stream()
+ .map(VespaVersion::versionNumber)
+ .filter(version -> version.getMajor() == targetMajorVersion)
+ .max(naturalOrder());
+ }
+
private boolean isUserDeployment(Optional<AthenzIdentity> identity) {
return identity
.filter(id -> id instanceof AthenzUser)
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
index 6f1e108ea77..936b0f3fce2 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationList.java
@@ -166,7 +166,7 @@ public class ApplicationList {
* @param defaultMajorVersion the default major version to assume for applications not specifying one
*/
public ApplicationList allowMajorVersion(int targetMajorVersion, int defaultMajorVersion) {
- return listOf(list.stream().filter(a -> a.majorVersion().orElse(a.deploymentSpec().majorVersion().orElse(defaultMajorVersion))
+ return listOf(list.stream().filter(a -> a.deploymentSpec().majorVersion().orElse(a.majorVersion().orElse(defaultMajorVersion))
>= targetMajorVersion));
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiHandler.java
index fa1b8699612..76e15c8de5a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiHandler.java
@@ -2,6 +2,8 @@
package com.yahoo.vespa.hosted.controller.restapi.os;
import com.yahoo.component.Version;
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.RegionName;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.jdisc.LoggingRequestHandler;
@@ -13,7 +15,10 @@ import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.integration.zone.CloudName;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneList;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
+import com.yahoo.vespa.hosted.controller.restapi.MessageResponse;
import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse;
import com.yahoo.vespa.hosted.controller.versions.OsVersion;
import com.yahoo.yolean.Exceptions;
@@ -21,8 +26,12 @@ import com.yahoo.yolean.Exceptions;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.StringJoiner;
import java.util.logging.Level;
+import java.util.stream.Collectors;
/**
* This implements the /os/v1 API which provides operators with information about, and scheduling of OS upgrades for
@@ -45,6 +54,8 @@ public class OsApiHandler extends LoggingRequestHandler {
try {
switch (request.getMethod()) {
case GET: return get(request);
+ case POST: return post(request);
+ case DELETE: return delete(request);
case PATCH: return patch(request);
default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is unsupported");
}
@@ -68,6 +79,55 @@ public class OsApiHandler extends LoggingRequestHandler {
return ErrorResponse.notFoundError("Nothing at " + path);
}
+ private HttpResponse post(HttpRequest request) {
+ Path path = new Path(request.getUri().getPath());
+ if (path.matches("/os/v1/firmware/")) return requestFirmwareCheckResponse(path);
+ if (path.matches("/os/v1/firmware/{environment}/")) return requestFirmwareCheckResponse(path);
+ if (path.matches("/os/v1/firmware/{environment}/{region}/")) return requestFirmwareCheckResponse(path);
+ return ErrorResponse.notFoundError("Nothing at " + path);
+ }
+
+ private HttpResponse delete(HttpRequest request) {
+ Path path = new Path(request.getUri().getPath());
+ if (path.matches("/os/v1/firmware/")) return cancelFirmwareCheckResponse(path);
+ if (path.matches("/os/v1/firmware/{environment}/")) return cancelFirmwareCheckResponse(path);
+ if (path.matches("/os/v1/firmware/{environment}/{region}/")) return cancelFirmwareCheckResponse(path);
+ return ErrorResponse.notFoundError("Nothing at " + path);
+ }
+
+ private HttpResponse requestFirmwareCheckResponse(Path path) {
+ List<ZoneId> zones = zonesAt(path);
+ if (zones.isEmpty())
+ return ErrorResponse.notFoundError("No zones at " + path);
+
+ StringJoiner response = new StringJoiner(", ", "Requested firmware checks in ", ".");
+ for (ZoneId zone : zones) {
+ controller.configServer().nodeRepository().requestFirmwareCheck(zone);
+ response.add(zone.value());
+ }
+ return new MessageResponse(response.toString());
+ }
+
+ private HttpResponse cancelFirmwareCheckResponse(Path path) {
+ List<ZoneId> zones = zonesAt(path);
+ if (zones.isEmpty())
+ return ErrorResponse.notFoundError("No zones at " + path);
+
+ StringJoiner response = new StringJoiner(", ", "Cancelled firmware checks in ", ".");
+ for (ZoneId zone : zones) {
+ controller.configServer().nodeRepository().cancelFirmwareCheck(zone);
+ response.add(zone.value());
+ }
+ return new MessageResponse(response.toString());
+ }
+
+ private List<ZoneId> zonesAt(Path path) {
+ ZoneList zones = controller.zoneRegistry().zones().controllerUpgraded();
+ if (path.get("region") != null) zones = zones.in(RegionName.from(path.get("region")));
+ if (path.get("environment") != null) zones = zones.in(Environment.from(path.get("environment")));
+ return zones.ids();
+ }
+
private Slime setOsVersion(HttpRequest request) {
Slime requestData = toSlime(request.getData());
Inspector root = requestData.get();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tls/ControllerSslContextFactoryProvider.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tls/ControllerSslContextFactoryProvider.java
index 81a0a314dc5..d20c86528a5 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tls/ControllerSslContextFactoryProvider.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tls/ControllerSslContextFactoryProvider.java
@@ -17,7 +17,6 @@ import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -58,12 +57,6 @@ public class ControllerSslContextFactoryProvider extends AbstractComponent imple
/** Create a SslContextFactory backed by an in-memory key and trust store */
private SslContextFactory createSslContextFactory(int port) {
SslContextFactory factory = new SslContextFactory();
- // TODO Remove cipher exclusions on Vespa 7 (require ciphers with forward secrecy)
- // Do not exclude TLS_RSA_* ciphers
- String[] excludedCiphers = Arrays.stream(factory.getExcludeCipherSuites())
- .filter(cipherPattern -> !cipherPattern.equals("^TLS_RSA_.*$"))
- .toArray(String[]::new);
- factory.setExcludeCipherSuites(excludedCiphers);
if (port != 443) {
factory.setWantClientAuth(true);
}
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 1199f0229b6..343deaec752 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
@@ -446,10 +446,13 @@ public class ControllerTest {
@Test
public void testDeployDirectly() {
DeploymentTester tester = new DeploymentTester();
+ Version six = Version.fromString("6.1");
+ tester.upgradeSystem(six);
tester.controllerTester().zoneRegistry().setSystemName(SystemName.cd);
tester.controllerTester().zoneRegistry().setZones(ZoneId.from("prod", "cd-us-central-1"));
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
+ .majorVersion(6)
.region("cd-us-central-1")
.build();
@@ -468,6 +471,11 @@ public class ControllerTest {
assertTrue("No job status added",
tester.applications().require(app.id()).deploymentJobs().jobStatus().isEmpty());
+
+ Version seven = Version.fromString("7.2");
+ tester.upgradeSystem(seven);
+ tester.controller().applications().deploy(app.id(), zone, Optional.of(applicationPackage), options);
+ assertEquals(six, tester.application(app.id()).deployments().get(zone).version());
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
index b160b853986..f375d80b28b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
@@ -12,11 +12,13 @@ import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
@@ -93,6 +95,16 @@ public class NodeRepositoryMock implements NodeRepository {
.forEach(node -> putByHostname(zone, node));
}
+ @Override
+ public void requestFirmwareCheck(ZoneId zone) {
+ ;
+ }
+
+ @Override
+ public void cancelFirmwareCheck(ZoneId zone) {
+ ;
+ }
+
public void doUpgrade(DeploymentId deployment, Optional<HostName> hostName, Version version) {
modifyNodes(deployment, hostName, node -> {
assert node.wantedVersion().equals(version);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
index a7f98103885..9ec254b59fd 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java
@@ -111,6 +111,22 @@ public class OsApiTest extends ControllerContainerTest {
assertResponse(new Request("http://localhost:8080/os/v1/", "{\"version\": \"7.4.1\", \"cloud\": \"cloud1\"}", Request.Method.PATCH),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Cannot downgrade cloud 'cloud1' to version 7.4.1\"}", 400);
+ // Request firmware checks in all zones.
+ assertResponse(new Request("http://localhost:8080/os/v1/firmware/", "", Request.Method.POST),
+ "{\"message\":\"Requested firmware checks in prod.us-east-3, prod.us-west-1, prod.eu-west-1.\"}", 200);
+
+ // Cancel firmware checks in all prod zones.
+ assertResponse(new Request("http://localhost:8080/os/v1/firmware/prod/", "", Request.Method.DELETE),
+ "{\"message\":\"Cancelled firmware checks in prod.us-east-3, prod.us-west-1, prod.eu-west-1.\"}", 200);
+
+ // Request firmware checks in prod.us-east-3.
+ assertResponse(new Request("http://localhost:8080/os/v1/firmware/prod/us-east-3", "", Request.Method.POST),
+ "{\"message\":\"Requested firmware checks in prod.us-east-3.\"}", 200);
+
+ // Error: Cancel firmware checks in an empty set of zones.
+ assertResponse(new Request("http://localhost:8080/os/v1/firmware/dev/", "", Request.Method.DELETE),
+ "{\"error-code\":\"NOT_FOUND\",\"message\":\"No zones at path '/os/v1/firmware/dev'\"}", 404);
+
}
private void upgradeAndUpdateStatus() {