diff options
10 files changed, 103 insertions, 34 deletions
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java index 763118dbf03..32718524997 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java @@ -24,7 +24,10 @@ public enum NodeType { config(false, "Config server"), /** A host of a (docker) config server node */ - confighost(true, "Config docker host"); + confighost(true, "Config docker host"), + + /** A controller */ + controller(true, "Controller"); private final boolean isDockerHost; private final String description; 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 aea809de365..b0b3b352726 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 @@ -27,12 +27,9 @@ import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.serviceview.bindings.ApplicationView; import com.yahoo.vespa.serviceview.bindings.ClusterView; import com.yahoo.vespa.serviceview.bindings.ServiceView; -import org.json.JSONException; -import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -53,7 +50,6 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer private final Map<ApplicationId, Application> applications = new LinkedHashMap<>(); private final Map<String, EndpointStatus> endpoints = new HashMap<>(); - private final Map<URI, Version> versions = new HashMap<>(); private final NodeRepositoryMock nodeRepository = new NodeRepositoryMock(); private final Map<DeploymentId, ServiceConvergence> serviceStatus = new HashMap<>(); private final Version initialVersion = new Version(6, 1, 0); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java index b6955195dcf..f61d4158253 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java @@ -12,6 +12,7 @@ import com.yahoo.vespa.hosted.provision.Node; import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; import com.yahoo.vespa.service.monitor.application.ConfigServerHostApplication; +import com.yahoo.vespa.service.monitor.application.ControllerApplication; import com.yahoo.vespa.service.monitor.application.HostedVespaApplication; import com.yahoo.vespa.service.monitor.application.ProxyHostApplication; @@ -35,7 +36,8 @@ public class InfrastructureProvisioner extends Maintainer { private static final List<HostedVespaApplication> HOSTED_VESPA_APPLICATIONS = Arrays.asList( ConfigServerApplication.CONFIG_SERVER_APPLICATION, ConfigServerHostApplication.CONFIG_SERVER_HOST_APPLICATION, - ProxyHostApplication.PROXY_HOST_APPLICATION); + ProxyHostApplication.PROXY_HOST_APPLICATION, + ControllerApplication.CONTROLLER_APPLICATION); private final Provisioner provisioner; private final InfrastructureVersions infrastructureVersions; @@ -101,4 +103,5 @@ public class InfrastructureProvisioner extends Maintainer { } return targetVersion; } + } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureVersions.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureVersions.java index 61783bb4483..31dd5d74404 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureVersions.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureVersions.java @@ -28,8 +28,14 @@ public class InfrastructureVersions { } public void setTargetVersion(NodeType nodeType, Version newTargetVersion, boolean force) { - if (nodeType != NodeType.config && nodeType != NodeType.confighost && nodeType != NodeType.proxyhost) { - throw new IllegalArgumentException("Cannot set version for type " + nodeType); + switch (nodeType) { + case config: + case confighost: + case proxyhost: + case controller: + break; + default: + throw new IllegalArgumentException("Cannot set version for type " + nodeType); } if (newTargetVersion.isEmpty()) { throw new IllegalArgumentException("Invalid target version: " + newTargetVersion.toFullString()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java index dbe6589dd7f..db3db139044 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java @@ -320,12 +320,13 @@ public class NodeSerializer { static NodeType nodeTypeFromString(String typeString) { switch (typeString) { - case "tenant" : return NodeType.tenant; - case "host" : return NodeType.host; - case "proxy" : return NodeType.proxy; - case "proxyhost" : return NodeType.proxyhost; - case "config" : return NodeType.config; - case "confighost" : return NodeType.confighost; + case "tenant": return NodeType.tenant; + case "host": return NodeType.host; + case "proxy": return NodeType.proxy; + case "proxyhost": return NodeType.proxyhost; + case "config": return NodeType.config; + case "confighost": return NodeType.confighost; + case "controller": return NodeType.controller; default : throw new IllegalArgumentException("Unknown node type '" + typeString + "'"); } } @@ -338,6 +339,7 @@ public class NodeSerializer { case proxyhost: return "proxyhost"; case config: return "config"; case confighost: return "confighost"; + case controller: return "controller"; } throw new IllegalArgumentException("Serialized form of '" + type + "' not defined"); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java index 970871a4d05..3b7cf857a86 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java @@ -196,6 +196,7 @@ class NodesResponse extends HttpResponse { case proxyhost: return "proxyhost"; case config: return "config"; case confighost: return "confighost"; + case controller: return "controller"; default: throw new RuntimeException("New type added to enum, not implemented in NodesResponse: " + type.name()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java index f0c4ad2ef2d..642e6adfc75 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java @@ -2,8 +2,8 @@ package com.yahoo.vespa.hosted.provision.maintenance; import com.yahoo.component.Version; -import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.ClusterMembership; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.Provisioner; import com.yahoo.vespa.hosted.provision.Node; @@ -13,11 +13,17 @@ import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.Allocation; import com.yahoo.vespa.hosted.provision.node.Generation; import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; +import com.yahoo.vespa.service.monitor.application.ControllerApplication; +import com.yahoo.vespa.service.monitor.application.HostedVespaApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.time.Duration; +import java.util.Arrays; import java.util.Optional; -import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -26,47 +32,63 @@ import static org.mockito.Mockito.when; /** * @author freva */ +@RunWith(Parameterized.class) public class InfrastructureProvisionerTest { - private final NodeRepositoryTester tester = new NodeRepositoryTester(); + @Parameters(name = "application={0}") + public static Iterable<Object[]> parameters() { + return Arrays.asList( + new HostedVespaApplication[]{ConfigServerApplication.CONFIG_SERVER_APPLICATION}, + new HostedVespaApplication[]{ControllerApplication.CONTROLLER_APPLICATION} + ); + } + private final NodeRepositoryTester tester = new NodeRepositoryTester(); private final Provisioner provisioner = mock(Provisioner.class); private final NodeRepository nodeRepository = tester.nodeRepository(); private final InfrastructureVersions infrastructureVersions = mock(InfrastructureVersions.class); private final InfrastructureProvisioner infrastructureProvisioner = new InfrastructureProvisioner( provisioner, nodeRepository, infrastructureVersions, Duration.ofDays(99), new JobControl(nodeRepository.database())); + private final HostedVespaApplication application; + private final NodeType nodeType; + + public InfrastructureProvisionerTest(HostedVespaApplication application) { + this.application = application; + this.nodeType = application.getCapacity().type(); + } + @Test public void returns_version_if_usable_nodes_on_old_version() { Version target = Version.fromString("6.123.456"); Version oldVersion = Version.fromString("6.122.333"); - when(infrastructureVersions.getTargetVersionFor(eq(NodeType.config))).thenReturn(Optional.of(target)); + when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target)); addNode(1, Node.State.failed, Optional.of(oldVersion)); addNode(2, Node.State.dirty, Optional.empty()); addNode(3, Node.State.active, Optional.of(oldVersion)); - assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(NodeType.config)); + assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(nodeType)); } @Test public void returns_version_if_has_usable_nodes_without_version() { Version target = Version.fromString("6.123.456"); Version oldVersion = Version.fromString("6.122.333"); - when(infrastructureVersions.getTargetVersionFor(eq(NodeType.config))).thenReturn(Optional.of(target)); + when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target)); addNode(1, Node.State.failed, Optional.of(oldVersion)); addNode(2, Node.State.ready, Optional.empty()); addNode(3, Node.State.active, Optional.of(target)); - assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(NodeType.config)); + assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(nodeType)); } @Test public void returns_empty_if_usable_nodes_on_target_version() { Version target = Version.fromString("6.123.456"); Version oldVersion = Version.fromString("6.122.333"); - when(infrastructureVersions.getTargetVersionFor(eq(NodeType.config))).thenReturn(Optional.of(target)); + when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target)); addNode(1, Node.State.failed, Optional.of(oldVersion)); addNode(2, Node.State.parked, Optional.of(target)); @@ -74,32 +96,31 @@ public class InfrastructureProvisionerTest { addNode(4, Node.State.inactive, Optional.of(target)); addNode(5, Node.State.dirty, Optional.empty()); - assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(NodeType.config)); + assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType)); } @Test public void returns_empty_if_no_usable_nodes() { - when(infrastructureVersions.getTargetVersionFor(eq(NodeType.config))).thenReturn(Optional.of(Version.fromString("6.123.456"))); + when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(Version.fromString("6.123.456"))); // No nodes in node repo - assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(NodeType.config)); + assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType)); // Add nodes in non-provisionable states addNode(1, Node.State.dirty, Optional.empty()); addNode(2, Node.State.failed, Optional.empty()); - assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(NodeType.config)); + assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType)); } @Test public void returns_empty_if_target_version_not_set() { - when(infrastructureVersions.getTargetVersionFor(eq(NodeType.config))).thenReturn(Optional.empty()); - assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(NodeType.config)); + when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.empty()); + assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType)); } private Node addNode(int id, Node.State state, Optional<Version> wantedVespaVersion) { - Node node = tester.addNode("id-" + id, "node-" + id, "default", NodeType.config); + Node node = tester.addNode("id-" + id, "node-" + id, "default", nodeType); Optional<Node> nodeWithAllocation = wantedVespaVersion.map(version -> { - ConfigServerApplication application = ConfigServerApplication.CONFIG_SERVER_APPLICATION; ClusterSpec clusterSpec = ClusterSpec.from(application.getClusterType(), application.getClusterId(), ClusterSpec.Group.from(0), version, false); ClusterMembership membership = ClusterMembership.from(clusterSpec, 1); Allocation allocation = new Allocation(application.getApplicationId(), membership, new Generation(0, 0), false); @@ -107,4 +128,5 @@ public class InfrastructureProvisionerTest { }); return nodeRepository.database().writeTo(state, nodeWithAllocation.orElse(node), Agent.system, Optional.empty()); } + } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java index a838d5c7b64..bc810d93f02 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java @@ -508,7 +508,7 @@ public class RestApiTest { // Initially, no versions are set assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/"), "{\"versions\":{},\"osVersions\":{}}"); - // Set version for config and confighost + // Set version for config, confighost and controller assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/config", Utf8.toBytes("{\"version\": \"6.123.456\"}"), Request.Method.PATCH), @@ -517,10 +517,15 @@ public class RestApiTest { Utf8.toBytes("{\"version\": \"6.123.456\"}"), Request.Method.PATCH), "{\"message\":\"Set version to 6.123.456 for nodes of type confighost\"}"); + assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/controller", + Utf8.toBytes("{\"version\": \"6.123.456\"}"), + Request.Method.PATCH), + "{\"message\":\"Set version to 6.123.456 for nodes of type controller\"}"); + // Verify versions are set assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/"), - "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.456\"},\"osVersions\":{}}"); + "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.456\",\"controller\":\"6.123.456\"},\"osVersions\":{}}"); // Setting empty version fails assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/confighost", @@ -529,6 +534,13 @@ public class RestApiTest { 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Invalid target version: 0.0.0\"}"); + // Setting version for unsupported node type fails + assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/tenant", + Utf8.toBytes("{\"version\": \"6.123.456\"}"), + Request.Method.PATCH), + 400, + "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Cannot set version for type tenant\"}"); + // Omitting version field fails assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/confighost", Utf8.toBytes("{}"), @@ -552,7 +564,7 @@ public class RestApiTest { // Verify version has been updated assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/"), - "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.1\"},\"osVersions\":{}}"); + "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.1\",\"controller\":\"6.123.456\"},\"osVersions\":{}}"); // Upgrade OS for confighost and host assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/confighost", @@ -566,7 +578,7 @@ public class RestApiTest { // OS versions are set assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/"), - "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.1\"},\"osVersions\":{\"host\":\"7.5.2\",\"confighost\":\"7.5.2\"}}"); + "{\"versions\":{\"config\":\"6.123.456\",\"confighost\":\"6.123.1\",\"controller\":\"6.123.456\"},\"osVersions\":{\"host\":\"7.5.2\",\"confighost\":\"7.5.2\"}}"); // Upgrade OS and Vespa together assertResponse(new Request("http://localhost:8080/nodes/v2/upgrade/confighost", diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java new file mode 100644 index 00000000000..c1bc303e792 --- /dev/null +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java @@ -0,0 +1,18 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.service.monitor.application; + +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.NodeType; + +/** + * @author mpolden + */ +public class ControllerApplication extends HostedVespaApplication { + + public static final ControllerApplication CONTROLLER_APPLICATION = new ControllerApplication(); + + private ControllerApplication() { + super("controller", NodeType.controller, ClusterSpec.Type.container, ClusterSpec.Id.from("controller")); + } + +} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java index d1111bdd5d7..23fafa701d9 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java @@ -60,4 +60,10 @@ public abstract class HostedVespaApplication { .applicationName(applicationName) .build(); } + + @Override + public String toString() { + return applicationId.toString(); + } + } |