summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java13
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java87
5 files changed, 77 insertions, 33 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
index 1a75e5c4c74..eaa5aebda90 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
@@ -67,16 +67,17 @@ public class AutoscalingMaintainer extends Maintainer {
int currentGroups = (int) clusterNodes.stream().map(node -> node.allocation().get().membership().cluster().group()).distinct().count();
ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
log.info("Autoscale: " + application + " " + clusterType + " " + clusterId +
- " from " + toString(clusterNodes.size(), currentGroups, clusterNodes.get(0).flavor().resources()) +
- " to " + toString(target.get().nodes(), target.get().groups(), target.get().advertisedResources()));
+ "\nfrom " + toString(clusterNodes.size(), currentGroups, clusterNodes.get(0).flavor().resources()) +
+ "\nto " + toString(target.get().nodes(), target.get().groups(), target.get().advertisedResources()));
lastLogged.put(new Pair<>(application, clusterId), nodeRepository().clock().instant());
}
private String toString(int nodes, int groups, NodeResources resources) {
- return nodes +
- (groups > 1 ? " in " + groups + " groups " : " ") +
- " * " + resources +
- " (total: " + "[vcpu: " + nodes * resources.vcpu() + ", memory: " + nodes * resources.memoryGb() + " Gb, disk " + nodes * resources.diskGb() + " Gb])";
+ return String.format(nodes + (groups > 1 ? " (in " + groups + " groups)" : "") +
+ " * [vcpu: %1$.1f, memory: %2$.1f Gb, disk %3$.1f Gb]" +
+ " (total: [vcpu: %4$.1f, memory: %5$.1f Gb, disk %6$.1f Gb])," +
+ resources.vcpu(), resources.memoryGb(), resources.diskGb(),
+ nodes * resources.vcpu(), nodes * resources.memoryGb(), nodes * resources.diskGb());
}
private Map<ClusterSpec.Id, List<Node>> nodesByCluster(List<Node> applicationNodes) {
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 be43c0139e0..94f4dab1245 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
@@ -187,8 +187,7 @@ public class NodeSerializer {
object.setLong(currentRestartGenerationKey, allocation.restartGeneration().current());
object.setBool(removableKey, allocation.isRemovable());
object.setString(wantedVespaVersionKey, allocation.membership().cluster().vespaVersion().toString());
- // TODO serialize dockerImageRepo
- //object.setString(wantedDockerImageRepoKey, allocation.membership().cluster().dockerImageRepo().orElse(""));
+ allocation.membership().cluster().dockerImageRepo().ifPresent(repo -> object.setString(wantedDockerImageRepoKey, repo));
allocation.networkPorts().ifPresent(ports -> NetworkPortsSerializer.toSlime(ports, object.setArray(networkPortsKey)));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index 7a49ad9c44d..73061acd9c1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -5,6 +5,7 @@ import com.google.inject.Inject;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostFilter;
import com.yahoo.config.provision.HostSpec;
@@ -148,7 +149,8 @@ public class NodeRepositoryProvisioner implements Provisioner {
Optional.of(nodeAllocation.membership()),
node.status().vespaVersion(),
nodeAllocation.networkPorts(),
- requestedResources));
+ requestedResources,
+ node.status().dockerImage().map(DockerImage::repository)));
if (nodeAllocation.networkPorts().isPresent()) {
log.log(LogLevel.DEBUG, () -> "Prepared node " + node.hostname() + " has port allocations");
}
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 7f283452538..248cfbec662 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
@@ -157,7 +157,8 @@ class NodesResponse extends HttpResponse {
toSlime(allocation.membership(), object.setObject("membership"));
object.setLong("restartGeneration", allocation.restartGeneration().wanted());
object.setLong("currentRestartGeneration", allocation.restartGeneration().current());
- object.setString("wantedDockerImage", nodeRepository.dockerImage(node).withTag(allocation.membership().cluster().vespaVersion()).asString());
+ object.setString("wantedDockerImage", allocation.membership().cluster().dockerImage()
+ .orElseGet(() -> nodeRepository.dockerImage(node).withTag(allocation.membership().cluster().vespaVersion()).asString()));
object.setString("wantedVespaVersion", allocation.membership().cluster().vespaVersion().toFullString());
toSlime(allocation.requestedResources(), object.setObject("requestedResources"));
allocation.networkPorts().ifPresent(ports -> NetworkPortsSerializer.toSlime(ports, object.setArray("networkPorts")));
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
index 1f9d7ce5126..931d87a3265 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostFilter;
import com.yahoo.config.provision.HostSpec;
@@ -157,6 +158,34 @@ public class ProvisioningTest {
}
@Test
+ public void dockerImageRepoIsReturnedIfSet() {
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build();
+
+ tester.makeReadyNodes(4, defaultResources, NodeType.host, 1);
+ tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host);
+
+ // deploy
+ ApplicationId application1 = tester.makeApplicationId();
+ SystemState state1 = prepare(application1, tester, 1, 1, 1, 1, defaultResources, "1.2.3");
+ String dockerImageRepo = "docker.domain.tld/my/image";
+ prepare(application1, tester, 1, 1, 1 , 1 , false, defaultResources, "1.2.3", Optional.of(dockerImageRepo));
+ tester.activate(application1, state1.allHosts);
+
+ HostSpec host1 = state1.container0.iterator().next();
+ Node node1 = tester.nodeRepository().getNode(host1.hostname()).get();
+ DockerImage dockerImage = DockerImage.fromString(dockerImageRepo).withTag(Version.fromString("1.2.3"));
+ tester.nodeRepository().write(node1.with(node1.status().withDockerImage(dockerImage)), () -> {});
+
+ // redeploy
+ SystemState state2 = prepare(application1, tester, 1, 1, 1 ,1 , false, defaultResources, "1.2.3", Optional.of(dockerImageRepo));
+ tester.activate(application1, state2.allHosts);
+
+ host1 = state2.container0.iterator().next();
+ node1 = tester.nodeRepository().getNode(host1.hostname()).get();
+ assertEquals(dockerImage, node1.status().dockerImage().get());
+ }
+
+ @Test
public void application_deployment_variable_application_size() {
ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build();
@@ -334,7 +363,21 @@ public class ProvisioningTest {
tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host);
ApplicationId application = tester.makeApplicationId();
- SystemState state = prepare(application, 2, 2, 3, 3, defaultResources, Version.fromString("6.91"), tester);
+ SystemState state = prepare(application, tester, 2, 2, 3, 3, defaultResources, "6.91");
+ assertEquals(4, state.allHosts.size());
+ tester.activate(application, state.allHosts);
+ }
+
+ @Test
+ public void deploy_specific_vespa_version_and_docker_image() {
+ ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build();
+
+ tester.makeReadyNodes(4, defaultResources, NodeType.host, 1);
+ tester.prepareAndActivateInfraApplication(tester.makeApplicationId(), NodeType.host);
+
+ ApplicationId application = tester.makeApplicationId();
+ String dockerImageRepo = "docker.domain.tld/my/image";
+ SystemState state = prepare(application, tester, 2, 2, 3, 3, false, defaultResources, "6.91", Optional.of(dockerImageRepo));
assertEquals(4, state.allHosts.size());
tester.activate(application, state.allHosts);
}
@@ -630,7 +673,7 @@ public class ProvisioningTest {
ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build();
ApplicationId application = tester.makeApplicationId();
try {
- prepare(application, 1, 0, 1, 0, true, defaultResources, Version.fromString("6.42"), tester);
+ prepare(application, tester, 1, 0, 1, 0, true, defaultResources, "6.42", Optional.empty());
fail("Expected exception");
} catch (IllegalArgumentException ignored) {}
}
@@ -652,17 +695,17 @@ public class ProvisioningTest {
public void cluster_spec_update_for_already_reserved_nodes() {
ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.dev, RegionName.from("us-east"))).build();
ApplicationId application = tester.makeApplicationId();
- Version version1 = Version.fromString("6.42");
- Version version2 = Version.fromString("6.43");
+ String version1 = "6.42";
+ String version2 = "6.43";
tester.makeReadyNodes(2, defaultResources);
- prepare(application, 1, 0, 1, 0, true, defaultResources, version1, tester);
+ prepare(application, tester, 1, 0, 1, 0, true, defaultResources, version1, Optional.empty());
tester.getNodes(application, Node.State.reserved).forEach(node ->
- assertEquals(version1, node.allocation().get().membership().cluster().vespaVersion()));
+ assertEquals(Version.fromString(version1), node.allocation().get().membership().cluster().vespaVersion()));
- prepare(application, 1, 0, 1, 0, true, defaultResources, version2, tester);
+ prepare(application, tester, 1, 0, 1, 0, true, defaultResources, version2, Optional.empty());
tester.getNodes(application, Node.State.reserved).forEach(node ->
- assertEquals(version2, node.allocation().get().membership().cluster().vespaVersion()));
+ assertEquals(Version.fromString(version2), node.allocation().get().membership().cluster().vespaVersion()));
}
@Test
@@ -702,29 +745,27 @@ public class ProvisioningTest {
private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size,
int content1Size, NodeResources flavor, ProvisioningTester tester) {
- return prepare(application, container0Size, container1Size, content0Size, content1Size, flavor,
- Version.fromString("6.42"), tester);
+ return prepare(application, tester, container0Size, container1Size, content0Size, content1Size, flavor, "6.42");
}
- private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size,
- int content1Size, NodeResources nodeResources, Version wantedVersion, ProvisioningTester tester) {
- return prepare(application, container0Size, container1Size, content0Size, content1Size, false, nodeResources,
- wantedVersion, tester);
+ private SystemState prepare(ApplicationId application, ProvisioningTester tester, int container0Size, int container1Size, int content0Size,
+ int content1Size, NodeResources nodeResources, String wantedVersion) {
+ return prepare(application, tester, container0Size, container1Size, content0Size, content1Size, false, nodeResources,
+ wantedVersion, Optional.empty());
}
- private SystemState prepare(ApplicationId application, int container0Size, int container1Size, int content0Size,
- int content1Size, boolean required, NodeResources nodeResources, Version wantedVersion,
- ProvisioningTester tester) {
+ private SystemState prepare(ApplicationId application, ProvisioningTester tester, int container0Size, int container1Size, int content0Size,
+ int content1Size, boolean required, NodeResources nodeResources, String wantedVersion, Optional<String> dockerImageRepo) {
// "deploy prepare" with a two container clusters and a storage cluster having of two groups
ClusterSpec containerCluster0 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("container0")).vespaVersion(wantedVersion).build();
ClusterSpec containerCluster1 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("container1")).vespaVersion(wantedVersion).build();
ClusterSpec contentCluster0 = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("content0")).vespaVersion(wantedVersion).build();
ClusterSpec contentCluster1 = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("content1")).vespaVersion(wantedVersion).build();
- Set<HostSpec> container0 = prepare(application, containerCluster0, container0Size, 1, required, nodeResources, tester);
- Set<HostSpec> container1 = prepare(application, containerCluster1, container1Size, 1, required, nodeResources, tester);
- Set<HostSpec> content0 = prepare(application, contentCluster0, content0Size, 1, required, nodeResources, tester);
- Set<HostSpec> content1 = prepare(application, contentCluster1, content1Size, 1, required, nodeResources, tester);
+ Set<HostSpec> container0 = prepare(application, tester, containerCluster0, container0Size, 1, required, nodeResources);
+ Set<HostSpec> container1 = prepare(application, tester, containerCluster1, container1Size, 1, required, nodeResources);
+ Set<HostSpec> content0 = prepare(application, tester, contentCluster0, content0Size, 1, required, nodeResources);
+ Set<HostSpec> content1 = prepare(application, tester, contentCluster1, content1Size, 1, required, nodeResources);
Set<HostSpec> allHosts = new HashSet<>();
allHosts.addAll(container0);
@@ -755,8 +796,8 @@ public class ProvisioningTest {
return new SystemState(allHosts, container0, container1, content0, content1);
}
- private Set<HostSpec> prepare(ApplicationId application, ClusterSpec cluster, int nodeCount, int groups,
- boolean required, NodeResources nodeResources, ProvisioningTester tester) {
+ private Set<HostSpec> prepare(ApplicationId application, ProvisioningTester tester, ClusterSpec cluster, int nodeCount, int groups,
+ boolean required, NodeResources nodeResources) {
if (nodeCount == 0) return Collections.emptySet(); // this is a shady practice
return new HashSet<>(tester.prepare(application, cluster, nodeCount, groups, required, nodeResources));
}