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/NodeRepository.java14
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java22
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImages.java42
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java16
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java10
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java31
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java20
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacityTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImagesTest.java51
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java36
26 files changed, 187 insertions, 114 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
index 4af68fa702c..7d925b2a4aa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
@@ -16,6 +16,8 @@ import com.yahoo.config.provisioning.NodeRepositoryConfig;
import com.yahoo.transaction.Mutex;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.curator.Curator;
+import com.yahoo.vespa.flags.FlagSource;
+import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerInstance;
@@ -101,8 +103,8 @@ public class NodeRepository extends AbstractComponent {
* This will use the system time to make time-sensitive decisions
*/
@Inject
- public NodeRepository(NodeRepositoryConfig config, NodeFlavors flavors, Curator curator, Zone zone) {
- this(flavors, curator, Clock.systemUTC(), zone, new DnsNameResolver(), DockerImage.fromString(config.dockerImage()), config.useCuratorClientCache());
+ public NodeRepository(NodeRepositoryConfig config, NodeFlavors flavors, Curator curator, Zone zone, FlagSource flagSource) {
+ this(flavors, curator, Clock.systemUTC(), zone, new DnsNameResolver(), DockerImage.fromString(config.dockerImage()), config.useCuratorClientCache(), flagSource);
}
/**
@@ -110,7 +112,7 @@ public class NodeRepository extends AbstractComponent {
* which will be used for time-sensitive decisions.
*/
public NodeRepository(NodeFlavors flavors, Curator curator, Clock clock, Zone zone, NameResolver nameResolver,
- DockerImage dockerImage, boolean useCuratorClientCache) {
+ DockerImage dockerImage, boolean useCuratorClientCache, FlagSource flagSource) {
this.db = new CuratorDatabaseClient(flavors, curator, clock, zone, useCuratorClientCache);
this.zone = zone;
this.clock = clock;
@@ -119,7 +121,7 @@ public class NodeRepository extends AbstractComponent {
this.osVersions = new OsVersions(this);
this.infrastructureVersions = new InfrastructureVersions(db);
this.firmwareChecks = new FirmwareChecks(db, clock);
- this.dockerImages = new DockerImages(db, dockerImage);
+ this.dockerImages = new DockerImages(db, dockerImage, Flags.DOCKER_IMAGE_OVERRIDE.bindTo(flagSource));
this.jobControl = new JobControl(db);
// read and write all nodes to make sure they are stored in the latest version of the serialized format
@@ -130,8 +132,8 @@ public class NodeRepository extends AbstractComponent {
/** Returns the curator database client used by this */
public CuratorDatabaseClient database() { return db; }
- /** Returns the Docker image to use for nodes in this */
- public DockerImage dockerImage(NodeType nodeType) { return dockerImages.dockerImageFor(nodeType); }
+ /** Returns the Docker image to use for given node */
+ public DockerImage dockerImage(Node node) { return dockerImages.dockerImageFor(node); }
/** @return The name resolver used to resolve hostname and ip addresses */
public NameResolver nameResolver() { return nameResolver; }
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
index bb6d53d3304..f75621e18a0 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
@@ -17,6 +17,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator;
import com.yahoo.vespa.hosted.provision.provisioning.NodePrioritizer;
import com.yahoo.vespa.hosted.provision.provisioning.NodeResourceComparator;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost;
@@ -44,13 +45,15 @@ public class DynamicProvisioningMaintainer extends Maintainer {
private static final ApplicationId preprovisionAppId = ApplicationId.from("hosted-vespa", "tenant-host", "preprovision");
private final HostProvisioner hostProvisioner;
+ private final HostResourcesCalculator hostResourcesCalculator;
private final BooleanFlag dynamicProvisioningEnabled;
private final ListFlag<PreprovisionCapacity> preprovisionCapacityFlag;
- DynamicProvisioningMaintainer(NodeRepository nodeRepository, Duration interval,
- HostProvisioner hostProvisioner, FlagSource flagSource) {
+ DynamicProvisioningMaintainer(NodeRepository nodeRepository, Duration interval, HostProvisioner hostProvisioner,
+ HostResourcesCalculator hostResourcesCalculator, FlagSource flagSource) {
super(nodeRepository, interval);
this.hostProvisioner = hostProvisioner;
+ this.hostResourcesCalculator = hostResourcesCalculator;
this.dynamicProvisioningEnabled = Flags.ENABLE_DYNAMIC_PROVISIONING.bindTo(flagSource);
this.preprovisionCapacityFlag = Flags.PREPROVISION_CAPACITY.bindTo(flagSource);
}
@@ -68,17 +71,14 @@ public class DynamicProvisioningMaintainer extends Maintainer {
}
void updateProvisioningNodes(NodeList nodes, Mutex lock) {
- Map<String, Node> provisionedHostsByHostname = nodes.state(Node.State.provisioned).nodeType(NodeType.host)
- .asList().stream()
- .collect(Collectors.toMap(Node::hostname, Function.identity()));
-
- Map<Node, Set<Node>> nodesByProvisionedParent = nodes.asList().stream()
- .filter(node -> node.parentHostname().map(provisionedHostsByHostname::containsKey).orElse(false))
+ Map<String, Set<Node>> nodesByProvisionedParentHostname = nodes.nodeType(NodeType.tenant).asList().stream()
+ .filter(node -> node.parentHostname().isPresent())
.collect(Collectors.groupingBy(
- node -> provisionedHostsByHostname.get(node.parentHostname().get()),
+ node -> node.parentHostname().get(),
Collectors.toSet()));
- nodesByProvisionedParent.forEach((host, children) -> {
+ nodes.state(Node.State.provisioned).nodeType(NodeType.host).forEach(host -> {
+ Set<Node> children = nodesByProvisionedParentHostname.getOrDefault(host.hostname(), Set.of());
try {
List<Node> updatedNodes = hostProvisioner.provision(host, children);
nodeRepository().write(updatedNodes, lock);
@@ -112,7 +112,7 @@ public class DynamicProvisioningMaintainer extends Maintainer {
NodeResources resources = it.next();
removableHosts.stream()
.filter(host -> NodePrioritizer.ALLOCATABLE_HOST_STATES.contains(host.state()))
- .filter(host -> host.flavor().resources().satisfies(resources))
+ .filter(host -> hostResourcesCalculator.availableCapacityOf(host.flavor().name(), host.flavor().resources()).satisfies(resources))
.min(Comparator.comparingInt(n -> n.flavor().cost()))
.ifPresent(host -> {
removableHosts.remove(host);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
index ae8f8b052db..063b5ad2c2a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
@@ -81,7 +81,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
loadBalancerExpirer = provisionServiceProvider.getLoadBalancerService().map(lbService ->
new LoadBalancerExpirer(nodeRepository, defaults.loadBalancerExpirerInterval, lbService));
dynamicProvisioningMaintainer = provisionServiceProvider.getHostProvisioner().map(hostProvisioner ->
- new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, flagSource));
+ new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, provisionServiceProvider.getHostResourcesCalculator(), flagSource));
capacityReportMaintainer = new CapacityReportMaintainer(nodeRepository, metric, defaults.capacityReportInterval);
osUpgradeActivator = new OsUpgradeActivator(nodeRepository, defaults.osUpgradeActivatorInterval);
rebalancer = new Rebalancer(deployer, nodeRepository, provisionServiceProvider.getHostResourcesCalculator(), provisionServiceProvider.getHostProvisioner(), metric, clock, defaults.rebalancerInterval);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
index a609103ac89..fb76dc54d1a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacity.java
@@ -26,12 +26,6 @@ public class DockerHostCapacity {
this.hostResourcesCalculator = Objects.requireNonNull(hostResourcesCalculator, "hostResourcesCalculator must be non-null");
}
- /** Returns the allocation skew of this host */
- public double skew(Node host) {
- NodeResources free = freeCapacityOf(host, false);
- return Node.skew(host.flavor().resources(), free);
- }
-
int compareWithoutInactive(Node hostA, Node hostB) {
int result = compare(freeCapacityOf(hostB, true), freeCapacityOf(hostA, true));
if (result != 0) return result;
@@ -72,7 +66,7 @@ public class DockerHostCapacity {
NodeResources freeCapacityOf(Node host, boolean excludeInactive) {
// Only hosts have free capacity
if (!host.type().canRun(NodeType.tenant)) return new NodeResources(0, 0, 0, 0);
- NodeResources hostResources = hostResourcesCalculator.availableCapacityOf(host.flavor().resources());
+ NodeResources hostResources = hostResourcesCalculator.availableCapacityOf(host.flavor().name(), host.flavor().resources());
return allNodes.childrenOf(host).asList().stream()
.filter(node -> !(excludeInactive && isInactiveOrRetired(node)))
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImages.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImages.java
index 9a06f2a980a..4416106f23e 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImages.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImages.java
@@ -3,9 +3,14 @@ package com.yahoo.vespa.hosted.provision.provisioning;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.curator.Lock;
+import com.yahoo.vespa.flags.FetchVector;
+import com.yahoo.vespa.flags.StringFlag;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient;
import java.time.Duration;
@@ -13,6 +18,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
import java.util.logging.Logger;
/**
@@ -28,6 +34,7 @@ public class DockerImages {
private final CuratorDatabaseClient db;
private final DockerImage defaultImage;
private final Duration cacheTtl;
+ private final StringFlag imageOverride;
/**
* Docker image is read on every request to /nodes/v2/node/[fqdn]. Cache current getDockerImages to avoid
@@ -36,20 +43,41 @@ public class DockerImages {
*/
private volatile Supplier<Map<NodeType, DockerImage>> dockerImages;
- public DockerImages(CuratorDatabaseClient db, DockerImage defaultImage) {
- this(db, defaultImage, defaultCacheTtl);
+ public DockerImages(CuratorDatabaseClient db, DockerImage defaultImage, StringFlag imageOverride) {
+ this(db, defaultImage, defaultCacheTtl, imageOverride);
}
- DockerImages(CuratorDatabaseClient db, DockerImage defaultImage, Duration cacheTtl) {
+ DockerImages(CuratorDatabaseClient db, DockerImage defaultImage, Duration cacheTtl, StringFlag imageOverride) {
this.db = db;
this.defaultImage = defaultImage;
this.cacheTtl = cacheTtl;
+ this.imageOverride = imageOverride;
createCache();
}
private void createCache() {
this.dockerImages = Suppliers.memoizeWithExpiration(() -> Collections.unmodifiableMap(db.readDockerImages()),
- cacheTtl.toMillis(), TimeUnit.MILLISECONDS);
+ cacheTtl.toMillis(), TimeUnit.MILLISECONDS);
+ }
+
+ /** Returns the image to use for given node and zone */
+ public DockerImage dockerImageFor(Node node) {
+ if (node.type().isDockerHost()) {
+ // Docker hosts do not run in containers, and thus has no image. Return the image of the child node type
+ // instead as this allows the host to pre-download the (likely) image its node will run.
+ //
+ // Note that if the Docker image has been overridden through feature flag, the preloaded image won't match.
+ return dockerImageFor(node.type().childNodeType());
+ }
+ return node.allocation()
+ .map(Allocation::owner)
+ .map(ApplicationId::serializedForm)
+ // Return overridden image for this application
+ .map(application -> imageOverride.with(FetchVector.Dimension.APPLICATION_ID, application).value())
+ .filter(Predicate.not(String::isEmpty))
+ .map(DockerImage::fromString)
+ // ... or default Docker image for this node type
+ .orElseGet(() -> dockerImageFor(node.type()));
}
/** Returns the current docker images for each node type */
@@ -58,7 +86,7 @@ public class DockerImages {
}
/** Returns the current docker image for given node type, or default */
- public DockerImage dockerImageFor(NodeType type) {
+ private DockerImage dockerImageFor(NodeType type) {
return getDockerImages().getOrDefault(type, defaultImage);
}
@@ -69,8 +97,8 @@ public class DockerImages {
}
try (Lock lock = db.lockDockerImages()) {
Map<NodeType, DockerImage> dockerImages = db.readDockerImages();
-
- dockerImage.ifPresentOrElse(image -> dockerImages.put(nodeType, image), () -> dockerImages.remove(nodeType));
+ dockerImage.ifPresentOrElse(image -> dockerImages.put(nodeType, image),
+ () -> dockerImages.remove(nodeType));
db.writeDockerImages(dockerImages);
createCache(); // Throw away current cache
log.info("Set docker image for " + nodeType + " nodes to " + dockerImage.map(DockerImage::asString).orElse(null));
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java
index 05915b82bae..b5c4478cd5a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/EmptyProvisionServiceProvider.java
@@ -30,7 +30,7 @@ public class EmptyProvisionServiceProvider implements ProvisionServiceProvider {
public static class NoopHostResourcesCalculator implements HostResourcesCalculator {
@Override
- public NodeResources availableCapacityOf(NodeResources hostResources) {
+ public NodeResources availableCapacityOf(String flavorName, NodeResources hostResources) {
return hostResources;
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java
index c5808a53837..a5570dbf169 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostResourcesCalculator.java
@@ -9,6 +9,6 @@ import com.yahoo.config.provision.NodeResources;
public interface HostResourcesCalculator {
/** Calculates the resources that are reserved for host level processes and returns the remainder. */
- NodeResources availableCapacityOf(NodeResources hostResources);
+ NodeResources availableCapacityOf(String flavorName, NodeResources hostResources);
}
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 8ca8dfc26f6..7f283452538 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,7 @@ 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", dockerImageFor(node.type()).withTag(allocation.membership().cluster().vespaVersion()).asString());
+ object.setString("wantedDockerImage", 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")));
@@ -222,16 +222,10 @@ class NodesResponse extends HttpResponse {
// TODO: Remove current + wanted docker image from response for non-docker types
private Optional<DockerImage> currentDockerImage(Node node) {
return node.status().dockerImage()
- .or(() -> Optional.of(node)
- .filter(n -> n.flavor().getType() != Flavor.Type.DOCKER_CONTAINER)
- .flatMap(n -> n.status().vespaVersion()
- .map(version -> dockerImageFor(n.type()).withTag(version))));
- }
-
- // Docker hosts are not running in an image, but return the image of the node type running on it anyway,
- // this allows the docker host to pre-download the (likely) image its node will run
- private DockerImage dockerImageFor(NodeType nodeType) {
- return nodeRepository.dockerImage(nodeType.isDockerHost() ? nodeType.childNodeType() : nodeType);
+ .or(() -> Optional.of(node)
+ .filter(n -> n.flavor().getType() != Flavor.Type.DOCKER_CONTAINER)
+ .flatMap(n -> n.status().vespaVersion()
+ .map(version -> nodeRepository.dockerImage(n).withTag(version))));
}
private void ipAddressesToSlime(Set<String> ipAddresses, Cursor array) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
index 1817470a63b..a2579bee0a1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
@@ -54,7 +54,7 @@ public class MockNodeRepository extends NodeRepository {
super(flavors, curator, Clock.fixed(Instant.ofEpochMilli(123), ZoneId.of("Z")), Zone.defaultZone(),
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
this.flavors = flavors;
curator.setZooKeeperEnsembleConnectionSpec("cfg1:1234,cfg2:1234,cfg3:1234");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
index f0f523b9b9b..ab813ddeb5a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTester.java
@@ -9,6 +9,7 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.config.provisioning.FlavorsConfig;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
@@ -27,9 +28,12 @@ public class NodeRepositoryTester {
private final NodeRepository nodeRepository;
private final Clock clock;
private final MockCurator curator;
-
-
+
public NodeRepositoryTester() {
+ this(new InMemoryFlagSource());
+ }
+
+ public NodeRepositoryTester(InMemoryFlagSource flagSource) {
nodeFlavors = new NodeFlavors(createConfig());
clock = new ManualClock();
curator = new MockCurator();
@@ -37,7 +41,7 @@ public class NodeRepositoryTester {
nodeRepository = new NodeRepository(nodeFlavors, curator, clock, Zone.defaultZone(),
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, flagSource);
}
public NodeRepository nodeRepository() { return nodeRepository; }
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
index afac44856c9..96236b5fb84 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
@@ -22,6 +22,7 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.IP;
@@ -54,7 +55,8 @@ public class CapacityCheckerTester {
Curator curator = new MockCurator();
NodeFlavors f = new NodeFlavors(new FlavorConfigBuilder().build());
nodeRepository = new NodeRepository(f, curator, clock, zone, new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true);
+ DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true,
+ new InMemoryFlagSource());
}
private void updateCapacityChecker() {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
index c7a1486a1a4..36f876fb6bb 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
@@ -26,9 +26,11 @@ import com.yahoo.vespa.hosted.provision.node.Status;
import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
+import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
+import org.junit.Before;
import org.junit.Test;
import java.time.Duration;
@@ -49,6 +51,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -64,18 +67,23 @@ public class DynamicProvisioningMaintainerTest {
private final HostProvisionerTester tester = new HostProvisionerTester();
private final HostProvisioner hostProvisioner = mock(HostProvisioner.class);
+ private final HostResourcesCalculator hostResourcesCalculator = mock(HostResourcesCalculator.class);
private final InMemoryFlagSource flagSource = new InMemoryFlagSource()
.withBooleanFlag(Flags.ENABLE_DYNAMIC_PROVISIONING.id(), true)
.withListFlag(Flags.PREPROVISION_CAPACITY.id(), List.of(), PreprovisionCapacity.class);
private final DynamicProvisioningMaintainer maintainer = new DynamicProvisioningMaintainer(
- tester.nodeRepository, Duration.ofDays(1), hostProvisioner, flagSource);
+ tester.nodeRepository, Duration.ofDays(1), hostProvisioner, hostResourcesCalculator, flagSource);
@Test
public void delegates_to_host_provisioner_and_writes_back_result() {
addNodes();
+ Node host3 = tester.nodeRepository.getNode("host3").orElseThrow();
Node host4 = tester.nodeRepository.getNode("host4").orElseThrow();
Node host41 = tester.nodeRepository.getNode("host4-1").orElseThrow();
- assertTrue(Stream.of(host4, host41).map(Node::ipAddresses).allMatch(Set::isEmpty));
+ assertTrue(Stream.of(host3, host4, host41).map(Node::ipAddresses).allMatch(Set::isEmpty));
+
+ Node host3new = host3.with(host3.ipConfig().with(Set.of("::5")));
+ when(hostProvisioner.provision(eq(host3), eq(Set.of()))).thenReturn(List.of(host3new));
Node host4new = host4.with(host4.ipConfig().with(Set.of("::2")));
Node host41new = host41.with(host4.ipConfig().with(Set.of("::4", "10.0.0.1")));
@@ -83,8 +91,10 @@ public class DynamicProvisioningMaintainerTest {
maintainer.updateProvisioningNodes(tester.nodeRepository.list(), () -> {});
verify(hostProvisioner).provision(eq(host4), eq(Set.of(host41)));
+ verify(hostProvisioner).provision(eq(host3), eq(Set.of()));
verifyNoMoreInteractions(hostProvisioner);
+ assertEquals(Optional.of(host3new), tester.nodeRepository.getNode("host3"));
assertEquals(Optional.of(host4new), tester.nodeRepository.getNode("host4"));
assertEquals(Optional.of(host41new), tester.nodeRepository.getNode("host4-1"));
}
@@ -127,7 +137,7 @@ public class DynamicProvisioningMaintainerTest {
@Test
public void provision_deficit_and_deprovision_excess() {
- flagSource.withListFlag(Flags.PREPROVISION_CAPACITY.id(), List.of(new PreprovisionCapacity(1, 3, 2, 1), new PreprovisionCapacity(2, 3, 2, 2)), PreprovisionCapacity.class);
+ flagSource.withListFlag(Flags.PREPROVISION_CAPACITY.id(), List.of(new PreprovisionCapacity(2, 4, 8, 1), new PreprovisionCapacity(2, 3, 2, 2)), PreprovisionCapacity.class);
addNodes();
maintainer.convergeToCapacity(tester.nodeRepository.list());
@@ -150,6 +160,15 @@ public class DynamicProvisioningMaintainerTest {
verifyNoMoreInteractions(hostProvisioner);
}
+ @Before
+ public void setup() {
+ doAnswer(invocation -> {
+ String flavorName = invocation.getArgument(0, String.class);
+ if ("default".equals(flavorName)) return new NodeResources(2, 4, 8, 1);
+ return invocation.getArguments()[1];
+ }).when(hostResourcesCalculator).availableCapacityOf(any(), any());
+ }
+
public void addNodes() {
List.of(createNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp)),
createNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
@@ -157,6 +176,7 @@ public class DynamicProvisioningMaintainerTest {
createNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp)),
createNode("host2-1", Optional.of("host2"), NodeType.tenant, Node.State.failed, Optional.empty()),
+
createNode("host3", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
createNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
@@ -186,7 +206,8 @@ public class DynamicProvisioningMaintainerTest {
private final ManualClock clock = new ManualClock();
private final NodeRepository nodeRepository = new NodeRepository(
- nodeFlavors, new MockCurator(), clock, Zone.defaultZone(), new MockNameResolver().mockAnyLookup(), DockerImage.fromString("docker-image"), true);
+ nodeFlavors, new MockCurator(), clock, Zone.defaultZone(), new MockNameResolver().mockAnyLookup(),
+ DockerImage.fromString("docker-image"), true, new InMemoryFlagSource());
Node addNode(String hostname, Optional<String> parentHostname, NodeType nodeType, Node.State state, Optional<ApplicationId> application) {
Node node = createNode(hostname, parentHostname, nodeType, state, application);
@@ -207,4 +228,4 @@ public class DynamicProvisioningMaintainerTest {
state, allocation, History.empty(), nodeType, new Reports(), Optional.empty(), Optional.empty());
}
}
-} \ No newline at end of file
+}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
index 8509722b016..c293a3436b8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java
@@ -256,7 +256,7 @@ public class FailedExpirerTest {
this.nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-image"),
- true);
+ true, new InMemoryFlagSource());
this.provisioner = new NodeRepositoryProvisioner(nodeRepository, Zone.defaultZone(), new MockProvisionServiceProvider(), new InMemoryFlagSource());
this.expirer = new FailedExpirer(nodeRepository, zone, clock, Duration.ofMinutes(30));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java
index 4b7534b431e..7e8fcddb1ae 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirerTest.java
@@ -75,7 +75,7 @@ public class LoadBalancerExpirerTest {
assertTrue("Inactive load balancer not removed", tester.loadBalancerService().instances().containsKey(lb1));
// Expirer removes load balancers once expiration time passes
- tester.clock().advance(Duration.ofHours(1));
+ tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
expirer.maintain();
assertFalse("Inactive load balancer removed", tester.loadBalancerService().instances().containsKey(lb1));
@@ -94,7 +94,7 @@ public class LoadBalancerExpirerTest {
dirtyNodesOf(app2, cluster2);
// Expirer removes load balancer for removed cluster
- tester.clock().advance(Duration.ofHours(1));
+ tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
expirer.maintain();
assertFalse("Inactive load balancer removed", tester.loadBalancerService().instances().containsKey(lb3));
}
@@ -122,7 +122,7 @@ public class LoadBalancerExpirerTest {
// Application never activates and nodes are dirtied. Expirer moves load balancer to inactive after timeout
dirtyNodesOf(app, cluster);
- tester.clock().advance(Duration.ofHours(1));
+ tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
expirer.maintain();
assertSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb).state());
@@ -131,7 +131,7 @@ public class LoadBalancerExpirerTest {
assertSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb).state());
// Expirer removes inactive load balancer
- tester.clock().advance(Duration.ofHours(1));
+ tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
expirer.maintain();
assertFalse("Inactive load balancer removed", loadBalancers.get().containsKey(lb));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java
index a4b66d3cf9e..246f2509397 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceTester.java
@@ -9,6 +9,7 @@ import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
@@ -35,7 +36,7 @@ public class MaintenanceTester {
public final NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
public MaintenanceTester() {
curator.setZooKeeperEnsembleConnectionSpec("zk1.host:1,zk2.host:2,zk3.host:3");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
index 672709a2f8f..321812497bd 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
@@ -13,6 +13,7 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
@@ -56,7 +57,7 @@ public class MetricsReporterTest {
NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, Clock.systemUTC(), Zone.defaultZone(),
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
Node node = nodeRepository.createNode("openStackId", "hostname", Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.tenant);
nodeRepository.addNodes(List.of(node));
Node hostNode = nodeRepository.createNode("openStackId2", "parent", Optional.empty(), nodeFlavors.getFlavorOrThrow("default"), NodeType.proxy);
@@ -121,7 +122,7 @@ public class MetricsReporterTest {
NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, Clock.systemUTC(), Zone.defaultZone(),
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
// Allow 4 containers
Set<String> ipAddressPool = Set.of("::2", "::3", "::4", "::5");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
index 5872a78e1e2..033ddcd827e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailTester.java
@@ -75,7 +75,8 @@ public class NodeFailTester {
clock = new ManualClock();
curator = new MockCurator();
nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone, new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true);
+ DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true,
+ new InMemoryFlagSource());
provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, new MockProvisionServiceProvider(), new InMemoryFlagSource());
hostLivenessTracker = new TestHostLivenessTracker(clock);
orchestrator = new OrchestratorMock();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
index 50c00c730bb..22d7f03c449 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java
@@ -56,7 +56,7 @@ public class OperatorChangeApplicationMaintainerTest {
this.nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
this.fixture = new Fixture(zone, nodeRepository);
createReadyNodes(15, this.fixture.nodeResources, nodeRepository);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
index b1c3b23016c..913b8b53c46 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
@@ -62,7 +62,7 @@ public class PeriodicApplicationMaintainerTest {
this.nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
this.fixture = new Fixture(zone, nodeRepository);
createReadyNodes(15, fixture.nodeResources, nodeRepository);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java
index d1a330a3bd6..d0c678bdf45 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RebalancerTest.java
@@ -152,7 +152,7 @@ public class RebalancerTest {
private static class IdentityHostResourcesCalculator implements HostResourcesCalculator {
@Override
- public NodeResources availableCapacityOf(NodeResources hostResources) {
+ public NodeResources availableCapacityOf(String flavorName, NodeResources hostResources) {
return hostResources;
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
index 11ee6637720..96c3cc09b6b 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java
@@ -47,7 +47,7 @@ public class ReservationExpirerTest {
NodeRepository nodeRepository = new NodeRepository(flavors, curator, clock, Zone.defaultZone(),
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
- true);
+ true, new InMemoryFlagSource());
NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, Zone.defaultZone(), new MockProvisionServiceProvider(), new InMemoryFlagSource());
List<Node> nodes = new ArrayList<>(2);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
index 67af2df36e7..bdbe046fbdf 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java
@@ -64,8 +64,8 @@ public class RetiredExpirerTest {
private final Zone zone = new Zone(Environment.prod, RegionName.from("us-east"));
private final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default");
private final NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
- new MockNameResolver().mockAnyLookup(),
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true);
+ new MockNameResolver().mockAnyLookup(),
+ DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true, new InMemoryFlagSource());
private final NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, new MockProvisionServiceProvider(), new InMemoryFlagSource());
private final Orchestrator orchestrator = mock(Orchestrator.class);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
index 8995897769c..1d028f13340 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java
@@ -4,8 +4,6 @@ package com.yahoo.vespa.hosted.provision.provisioning;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
-import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.Node;
@@ -40,14 +38,14 @@ public class AclProvisioningTest {
tester.makeReadyNodes(10, new NodeResources(1, 4, 10, 1));
List<Node> dockerHost = tester.makeReadyNodes(1, new NodeResources(1, 4, 10, 1), NodeType.host);
ApplicationId zoneApplication = tester.makeApplicationId();
- deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.host));
+ tester.deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.host));
tester.makeReadyVirtualDockerNodes(1,new NodeResources(1, 4, 10, 1),
dockerHost.get(0).hostname());
List<Node> proxyNodes = tester.makeReadyNodes(3, new NodeResources(1, 4, 10, 1), NodeType.proxy);
// Allocate 2 nodes
ApplicationId application = tester.makeApplicationId();
- List<Node> activeNodes = deploy(application, Capacity.fromCount(2, new NodeResources(1, 4, 10, 1), false, true));
+ List<Node> activeNodes = tester.deploy(application, Capacity.fromCount(2, new NodeResources(1, 4, 10, 1), false, true));
assertEquals(2, activeNodes.size());
// Get trusted nodes for the first active node
@@ -112,7 +110,7 @@ public class AclProvisioningTest {
// Deploy zone application
ApplicationId zoneApplication = tester.makeApplicationId();
- deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.proxy));
+ tester.deploy(zoneApplication, Capacity.fromRequiredNodeType(NodeType.proxy));
// Get trusted nodes for first proxy node
List<Node> proxyNodes = tester.nodeRepository().getNodes(zoneApplication);
@@ -154,7 +152,7 @@ public class AclProvisioningTest {
// Allocate
ApplicationId controllerApplication = tester.makeApplicationId();
- List<Node> controllers = deploy(controllerApplication, Capacity.fromRequiredNodeType(NodeType.controller));
+ List<Node> controllers = tester.deploy(controllerApplication, Capacity.fromRequiredNodeType(NodeType.controller));
// Controllers and hosts all trust each other
List<NodeAcl> controllerAcls = tester.nodeRepository().getNodeAcls(controllers.get(0), false);
@@ -212,15 +210,7 @@ public class AclProvisioningTest {
}
private List<Node> deploy(ApplicationId application, int nodeCount) {
- return deploy(application, Capacity.fromCount(nodeCount, nodeResources));
- }
-
- private List<Node> deploy(ApplicationId application, Capacity capacity) {
- ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test"),
- Version.fromString("6.42"), false);
- List<HostSpec> prepared = tester.prepare(application, cluster, capacity, 1);
- tester.activate(application, Set.copyOf(prepared));
- return tester.getNodes(application, Node.State.active).asList();
+ return tester.deploy(application, Capacity.fromCount(nodeCount, nodeResources));
}
private static void assertAcls(List<List<Node>> expected, NodeAcl actual) {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacityTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacityTest.java
index 7d9ac230771..ba9a04573e1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacityTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerHostCapacityTest.java
@@ -37,7 +37,7 @@ public class DockerHostCapacityTest {
@Before
public void setup() {
- doAnswer(invocation -> invocation.getArguments()[0]).when(hostResourcesCalculator).availableCapacityOf(any());
+ doAnswer(invocation -> invocation.getArguments()[1]).when(hostResourcesCalculator).availableCapacityOf(any(), any());
// Create flavors
NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("host", "docker", "docker2");
@@ -95,9 +95,9 @@ public class DockerHostCapacityTest {
capacity.freeCapacityOf(host3, false));
doAnswer(invocation -> {
- NodeResources totalHostResources = (NodeResources) invocation.getArguments()[0];
+ NodeResources totalHostResources = (NodeResources) invocation.getArguments()[1];
return totalHostResources.subtract(new NodeResources(1, 2, 3, 0.5, NodeResources.DiskSpeed.any));
- }).when(hostResourcesCalculator).availableCapacityOf(any());
+ }).when(hostResourcesCalculator).availableCapacityOf(any(), any());
assertEquals(new NodeResources(4, 2, 5, 1.5, NodeResources.DiskSpeed.fast, NodeResources.StorageType.remote),
capacity.freeCapacityOf(host1, false));
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImagesTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImagesTest.java
new file mode 100644
index 00000000000..70a57715d13
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerImagesTest.java
@@ -0,0 +1,51 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.provisioning;
+
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.DockerImage;
+import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author mpolden
+ */
+public class DockerImagesTest {
+
+ @Test
+ public void image_selection() {
+ var flagSource = new InMemoryFlagSource();
+ var tester = new ProvisioningTester.Builder().flagSource(flagSource).build();
+
+ // Host uses tenant default image (for preload purposes)
+ var defaultImage = DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa");
+ var hosts = tester.makeReadyNodes(2, "default", NodeType.host);
+ tester.deployZoneApp();
+ for (var host : hosts) {
+ assertEquals(defaultImage, tester.nodeRepository().dockerImages().dockerImageFor(host));
+ }
+
+ // Tenant node uses tenant default image
+ var resources = new NodeResources(2, 8, 50, 1);
+ for (var host : hosts) {
+ var nodes = tester.makeReadyVirtualDockerNodes(2, resources, host.hostname());
+ for (var node : nodes) {
+ assertEquals(defaultImage, tester.nodeRepository().dockerImages().dockerImageFor(node));
+ }
+ }
+
+ // Allocated containers uses overridden image when feature flag is set
+ var app = tester.makeApplicationId();
+ var nodes = tester.deploy(app, Capacity.fromCount(2, resources));
+ var customImage = DockerImage.fromString("docker.example.com/vespa/hosted");
+ flagSource.withStringFlag(Flags.DOCKER_IMAGE_OVERRIDE.id(), customImage.asString());
+ for (var node : nodes) {
+ assertEquals(customImage, tester.nodeRepository().dockerImages().dockerImageFor(node));
+ }
+ }
+
+}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
index 4e63d3cc79f..e464ed07472 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java
@@ -87,7 +87,7 @@ public class ProvisioningTester {
this.nodeFlavors = nodeFlavors;
this.clock = new ManualClock();
this.nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone, nameResolver,
- DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true);
+ DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"), true, flagSource);
this.orchestrator = orchestrator;
ProvisionServiceProvider provisionServiceProvider = new MockProvisionServiceProvider(loadBalancerService, hostProvisioner);
this.provisioner = new NodeRepositoryProvisioner(nodeRepository, zone, provisionServiceProvider, flagSource);
@@ -418,21 +418,20 @@ public class ProvisioningTester {
activate(applicationId, Set.copyOf(list));
}
+ public List<Node> deploy(ApplicationId application, Capacity capacity) {
+ ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("test"),
+ Version.fromString("6.42"), false);
+ List<HostSpec> prepared = prepare(application, cluster, capacity, 1);
+ activate(application, Set.copyOf(prepared));
+ return getNodes(application, Node.State.active).asList();
+ }
+
+
/** Returns the hosts from the input list which are not retired */
public List<HostSpec> nonRetired(Collection<HostSpec> hosts) {
return hosts.stream().filter(host -> ! host.membership().get().retired()).collect(Collectors.toList());
}
- public void assertNumberOfNodesWithFlavor(List<HostSpec> hostSpecs, String flavor, int expectedCount) {
- long actualNodesWithFlavor = hostSpecs.stream()
- .map(HostSpec::hostname)
- .map(this::getNodeFlavor)
- .map(Flavor::name)
- .filter(name -> name.equals(flavor))
- .count();
- assertEquals(expectedCount, actualNodesWithFlavor);
- }
-
public void assertAllocatedOn(String explanation, String hostFlavor, ApplicationId app) {
for (Node node : nodeRepository.getNodes(app)) {
Node parent = nodeRepository.getNode(node.parentHostname().get()).get();
@@ -440,17 +439,6 @@ public class ProvisioningTester {
}
}
- public void printFreeResources() {
- for (Node host : nodeRepository().getNodes(NodeType.host)) {
- NodeResources free = host.flavor().resources();
- for (Node child : nodeRepository().getNodes(NodeType.tenant)) {
- if (child.parentHostname().get().equals(host.hostname()))
- free = free.subtract(child.flavor().resources());
- }
- System.out.println(host.flavor().name() + " node. Free resources: " + free);
- }
- }
-
public int hostFlavorCount(String hostFlavor, ApplicationId app) {
return (int)nodeRepository().getNodes(app).stream()
.map(n -> nodeRepository().getNode(n.parentHostname().get()).get())
@@ -458,10 +446,6 @@ public class ProvisioningTester {
.count();
}
- private Flavor getNodeFlavor(String hostname) {
- return nodeRepository.getNode(hostname).map(Node::flavor).orElseThrow(() -> new RuntimeException("No flavor for host " + hostname));
- }
-
public static final class Builder {
private Curator curator;
private FlavorsConfig flavorsConfig;