summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--node-repository/src/main/config/node-repository.xml1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabase.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java28
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java43
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java20
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockProvisioner.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java4
-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/NodeRetirerTester.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OperatorChangeApplicationMaintainerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java56
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java2
18 files changed, 102 insertions, 90 deletions
diff --git a/node-repository/src/main/config/node-repository.xml b/node-repository/src/main/config/node-repository.xml
index c10da86d2a8..2abd3f890fc 100644
--- a/node-repository/src/main/config/node-repository.xml
+++ b/node-repository/src/main/config/node-repository.xml
@@ -3,6 +3,7 @@
<component id="com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner" bundle="node-repository" />
<component id="NodeRepository" class="com.yahoo.vespa.hosted.provision.NodeRepository" bundle="node-repository"/>
<component id="com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance" bundle="node-repository"/>
+<component id="com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceProvider" bundle="node-repository"/>
<component id="com.yahoo.config.provision.NodeFlavors" bundle="config-provisioning" />
<handler id="com.yahoo.vespa.hosted.provision.restapi.v2.NodesApiHandler" bundle="node-repository">
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
index 398f3fceca8..ed6d1744af4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
@@ -52,13 +52,6 @@ public class NodeList {
return new NodeList(nodes.stream().filter(node -> node.allocation().get().membership().cluster().type().equals(type)).collect(Collectors.toList()));
}
- /** Returns the subset of nodes that are in the given state */
- public NodeList in(Node.State state) {
- return nodes.stream()
- .filter(node -> node.state() == state)
- .collect(collectingAndThen(Collectors.toList(), NodeList::new));
- }
-
/** Returns the subset of nodes owned by the given application */
public NodeList owner(ApplicationId application) {
return nodes.stream()
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabase.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabase.java
index d03c4b8dd09..d8c1323151d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabase.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabase.java
@@ -99,6 +99,11 @@ public class CuratorDatabase {
curator.create(path);
}
+ /** Returns whether given path exists */
+ public boolean exists(Path path) {
+ return curator.exists(path);
+ }
+
// --------- Read operations -------------------------------------------------------------------------------
// These can read from the memory file system, which accurately mirrors the ZooKeeper content IF
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
index 0fc5626241f..fb3f801cf65 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
@@ -11,6 +11,7 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.log.LogLevel;
import com.yahoo.path.Path;
import com.yahoo.transaction.NestedTransaction;
+import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.curator.transaction.CuratorOperations;
@@ -26,6 +27,7 @@ import com.yahoo.vespa.hosted.provision.node.Status;
import java.time.Clock;
import java.time.Duration;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -86,6 +88,7 @@ public class CuratorDatabaseClient {
curatorDatabase.create(infrastructureVersionsPath());
curatorDatabase.create(osVersionsPath());
curatorDatabase.create(loadBalancersRoot);
+ curatorDatabase.create(flagsRoot);
}
/**
@@ -432,15 +435,19 @@ public class CuratorDatabaseClient {
}
public void writeLoadBalancer(LoadBalancer loadBalancer) {
- Path path = loadBalancerPath(loadBalancer.id());
- curatorDatabase.create(path);
NestedTransaction transaction = new NestedTransaction();
- CuratorTransaction curatorTransaction = curatorDatabase.newCuratorTransactionIn(transaction);
- curatorTransaction.add(CuratorOperations.setData(path.getAbsolute(),
- LoadBalancerSerializer.toJson(loadBalancer)));
+ writeLoadBalancers(Collections.singletonList(loadBalancer), transaction);
transaction.commit();
}
+ public void writeLoadBalancers(Collection<LoadBalancer> loadBalancers, NestedTransaction transaction) {
+ CuratorTransaction curatorTransaction = curatorDatabase.newCuratorTransactionIn(transaction);
+ loadBalancers.forEach(loadBalancer -> {
+ curatorTransaction.add(createOrSet(loadBalancerPath(loadBalancer.id()),
+ LoadBalancerSerializer.toJson(loadBalancer)));
+ });
+ }
+
public void removeLoadBalancer(LoadBalancer loadBalancer) {
NestedTransaction transaction = new NestedTransaction();
CuratorTransaction curatorTransaction = curatorDatabase.newCuratorTransactionIn(transaction);
@@ -458,11 +465,9 @@ public class CuratorDatabaseClient {
public void writeFlag(Flag flag) {
Path path = flagPath(flag.id());
- curatorDatabase.create(path);
NestedTransaction transaction = new NestedTransaction();
CuratorTransaction curatorTransaction = curatorDatabase.newCuratorTransactionIn(transaction);
- curatorTransaction.add(CuratorOperations.setData(path.getAbsolute(),
- FlagSerializer.toJson(flag)));
+ curatorTransaction.add(createOrSet(path, FlagSerializer.toJson(flag)));
transaction.commit();
}
@@ -478,4 +483,11 @@ public class CuratorDatabaseClient {
return flagsRoot.append(id.serializedValue());
}
+ private Transaction.Operation createOrSet(Path path, byte[] data) {
+ if (curatorDatabase.exists(path)) {
+ return CuratorOperations.setData(path.getAbsolute(), data);
+ }
+ return CuratorOperations.create(path.getAbsolute(), data);
+ }
+
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
index cc2bdad70c2..27ab25be3d5 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
@@ -1,11 +1,11 @@
// Copyright 2018 Yahoo Holdings. 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.google.common.net.InetAddresses;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
import com.yahoo.transaction.Mutex;
+import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
@@ -13,10 +13,9 @@ import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService;
import com.yahoo.vespa.hosted.provision.lb.Real;
+import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -43,6 +42,11 @@ public class LoadBalancerProvisioner {
this.service = service;
}
+ /** Get load balancers assigned to given application */
+ public List<LoadBalancer> get(ApplicationId application) {
+ return db.readLoadBalancers(application);
+ }
+
/**
* Provision load balancer(s) for given application.
*
@@ -62,17 +66,17 @@ public class LoadBalancerProvisioner {
}
}
- /** Deactivate all load balancers assigned to given application */
- public void deactivate(ApplicationId application) {
+ /**
+ * Deactivate all load balancers assigned to given application. This is a no-op if an application does not have any
+ * load balancer(s)
+ */
+ public void deactivate(ApplicationId application, NestedTransaction transaction) {
try (Mutex applicationLock = nodeRepository.lock(application)) {
try (Mutex loadBalancersLock = db.lockLoadBalancers()) {
- if (!activeContainers(application).isEmpty()) {
- throw new IllegalArgumentException(application + " has active containers, refusing to deactivate load balancers");
- }
- db.readLoadBalancers(application)
- .stream()
- .map(LoadBalancer::deactivate)
- .forEach(db::writeLoadBalancer);
+ List<LoadBalancer> deactivatedLoadBalancers = db.readLoadBalancers(application).stream()
+ .map(LoadBalancer::deactivate)
+ .collect(Collectors.toList());
+ db.writeLoadBalancers(deactivatedLoadBalancers, transaction);
}
}
}
@@ -90,9 +94,8 @@ public class LoadBalancerProvisioner {
/** Returns a list of active containers for given application, grouped by cluster ID */
private Map<ClusterSpec.Id, List<Node>> activeContainers(ApplicationId application) {
- return new NodeList(nodeRepository.getNodes())
+ return new NodeList(nodeRepository.getNodes(Node.State.active))
.owner(application)
- .in(Node.State.active)
.type(ClusterSpec.Type.container)
.asList()
.stream()
@@ -105,21 +108,13 @@ public class LoadBalancerProvisioner {
// Remove addresses unreachable by the load balancer service
switch (service.protocol()) {
case ipv4:
- reachable.removeIf(this::isIpv6);
+ reachable.removeIf(IP::isV6);
break;
case ipv6:
- reachable.removeIf(this::isIpv4);
+ reachable.removeIf(IP::isV4);
break;
}
return reachable;
}
- private boolean isIpv4(String ipAddress) {
- return InetAddresses.forString(ipAddress) instanceof Inet4Address;
- }
-
- private boolean isIpv6(String ipAddress) {
- return InetAddresses.forString(ipAddress) instanceof Inet6Address;
- }
-
}
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 09f8fc41239..c02bba79698 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
@@ -20,6 +20,7 @@ import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.flag.FlagId;
+import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService;
import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeHostFilter;
@@ -47,13 +48,15 @@ public class NodeRepositoryProvisioner implements Provisioner {
private final Zone zone;
private final Preparer preparer;
private final Activator activator;
+ private final LoadBalancerProvisioner loadBalancerProvisioner;
int getSpareCapacityProd() {
return SPARE_CAPACITY_PROD;
}
@Inject
- public NodeRepositoryProvisioner(NodeRepository nodeRepository, NodeFlavors flavors, Zone zone) {
+ public NodeRepositoryProvisioner(NodeRepository nodeRepository, NodeFlavors flavors, Zone zone,
+ LoadBalancerService loadBalancerService) {
this.nodeRepository = nodeRepository;
this.capacityPolicies = new CapacityPolicies(zone, flavors);
this.zone = zone;
@@ -61,6 +64,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
? SPARE_CAPACITY_PROD
: SPARE_CAPACITY_NONPROD);
this.activator = new Activator(nodeRepository);
+ this.loadBalancerProvisioner = new LoadBalancerProvisioner(nodeRepository, loadBalancerService);
}
/**
@@ -105,9 +109,16 @@ public class NodeRepositoryProvisioner implements Provisioner {
public void activate(NestedTransaction transaction, ApplicationId application, Collection<HostSpec> hosts) {
validate(hosts);
activator.activate(application, hosts, transaction);
- if (nodeRepository.flags().get(FlagId.exclusiveLoadBalancer).isEnabled(application)) {
- // TODO: Provision load balancer
- }
+ transaction.onCommitted(() -> {
+ if (nodeRepository.flags().get(FlagId.exclusiveLoadBalancer).isEnabled(application)) {
+ try {
+ loadBalancerProvisioner.provision(application);
+ } catch (Exception e) {
+ log.log(LogLevel.ERROR, "Failed to provision load balancer for application " +
+ application.toShortString(), e);
+ }
+ }
+ });
}
@Override
@@ -118,6 +129,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
@Override
public void remove(NestedTransaction transaction, ApplicationId application) {
nodeRepository.deactivate(application, transaction);
+ loadBalancerProvisioner.deactivate(application, transaction);
}
private List<HostSpec> asSortedHosts(List<Node> nodes) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
index 46c144a1758..27215529cf4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
@@ -23,6 +23,7 @@ public class ContainerConfig {
" <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceProvider'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance'/>\n" +
" <component id='com.yahoo.config.provision.Zone'/>\n" +
" <handler id='com.yahoo.vespa.hosted.provision.restapi.v2.NodesApiHandler'>\n" +
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 e3fca286830..5d8f342d6bf 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
@@ -57,7 +57,7 @@ public class MockNodeRepository extends NodeRepository {
}
private void populate() {
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(this, flavors, Zone.defaultZone());
+ NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(this, flavors, Zone.defaultZone(), new LoadBalancerServiceMock());
List<Node> nodes = new ArrayList<>();
// Regular nodes
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockProvisioner.java
index af0ca7b6b75..a0defcd0dfa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockProvisioner.java
@@ -10,6 +10,7 @@ import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.ProvisionLogger;
import com.yahoo.config.provision.Provisioner;
import com.yahoo.transaction.NestedTransaction;
+import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService;
import java.util.Collection;
import java.util.Collections;
@@ -21,7 +22,9 @@ import java.util.List;
public class MockProvisioner implements Provisioner {
@Inject
- public MockProvisioner() {}
+ public MockProvisioner(LoadBalancerService loadBalancerService) {
+ // Tests that we can inject a default instance using LoadBalancerServiceProvider
+ }
@Override
public List<HostSpec> prepare(ApplicationId applicationId, ClusterSpec cluster, Capacity capacity, int groups, ProvisionLogger logger) {
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 a5f1dbb03cb..c98d53da874 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
@@ -26,6 +26,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.junit.Test;
@@ -34,7 +35,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -238,7 +238,7 @@ public class FailedExpirerTest {
new MockNameResolver().mockAnyLookup(),
new DockerImage("docker-image"),
true);
- this.provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, Zone.defaultZone());
+ this.provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, Zone.defaultZone(), new LoadBalancerServiceMock());
this.expirer = new FailedExpirer(nodeRepository, zone, clock, Duration.ofMinutes(30),
new JobControl(nodeRepository.database()));
}
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 c29f26ef1f6..3c7d634b495 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
@@ -29,6 +29,7 @@ import com.yahoo.vespa.hosted.provision.monitoring.MetricsReporterTest;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock;
@@ -84,7 +85,7 @@ public class NodeFailTester {
curator = new MockCurator();
nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone, new MockNameResolver().mockAnyLookup(),
new DockerImage("docker-registry.domain.tld:8080/dist/vespa"), true);
- provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone);
+ provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone, new LoadBalancerServiceMock());
hostLivenessTracker = new TestHostLivenessTracker(clock);
orchestrator = new OrchestratorMock();
this.configserverConfig = configserverConfig;
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
index 2bf4f831072..5cb0adc8718 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRetirerTester.java
@@ -22,6 +22,7 @@ import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorSpareChecker;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import com.yahoo.vespa.orchestrator.OrchestrationException;
@@ -74,7 +75,7 @@ public class NodeRetirerTester {
nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone, new MockNameResolver().mockAnyLookup(),
new DockerImage("docker-registry.domain.tld:8080/dist/vespa"), true);
jobControl = new JobControl(nodeRepository.database());
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone);
+ NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone, new LoadBalancerServiceMock());
deployer = new MockDeployer(provisioner, clock, apps);
flavors = nodeFlavors.getFlavors().stream().sorted(Comparator.comparing(Flavor::name)).collect(Collectors.toList());
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 961e9991d71..55fdd1dadb4 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
@@ -26,6 +26,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.junit.Test;
@@ -122,7 +123,7 @@ public class OperatorChangeApplicationMaintainerTest {
Fixture(Zone zone, NodeRepository nodeRepository, NodeFlavors flavors, Curator curator) {
this.nodeRepository = nodeRepository;
this.curator = curator;
- this.provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, zone);
+ this.provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, zone, new LoadBalancerServiceMock());
}
void activate() {
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 7e48edfc805..87b98f7c002 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
@@ -27,6 +27,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.junit.After;
@@ -247,7 +248,7 @@ public class PeriodicApplicationMaintainerTest {
Fixture(Zone zone, NodeRepository nodeRepository, NodeFlavors flavors, Curator curator) {
this.nodeRepository = nodeRepository;
this.curator = curator;
- this.provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, zone);
+ this.provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, zone, new LoadBalancerServiceMock());
Map<ApplicationId, MockDeployer.ApplicationContext> apps = new HashMap<>();
apps.put(app1, new MockDeployer.ApplicationContext(app1, clusterApp1,
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 0301c570ad1..fba1bead42f 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
@@ -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.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import org.junit.Test;
@@ -44,7 +45,7 @@ public class ReservationExpirerTest {
new MockNameResolver().mockAnyLookup(),
new DockerImage("docker-registry.domain.tld:8080/dist/vespa"),
true);
- NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, Zone.defaultZone());
+ NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, Zone.defaultZone(), new LoadBalancerServiceMock());
List<Node> nodes = new ArrayList<>(2);
nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant));
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 03f82e5c3d7..3f21e6b74ae 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
@@ -26,6 +26,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import com.yahoo.vespa.hosted.provision.testutils.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import com.yahoo.vespa.orchestrator.OrchestrationException;
@@ -60,7 +61,7 @@ public class RetiredExpirerTest {
private final NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, clock, zone,
new MockNameResolver().mockAnyLookup(),
new DockerImage("docker-registry.domain.tld:8080/dist/vespa"), true);
- private final NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone);
+ private final NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone, new LoadBalancerServiceMock());
private final Orchestrator orchestrator = mock(Orchestrator.class);
private static final Duration RETIRED_EXPIRATION = Duration.ofHours(12);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
index ab7fda20889..ba8fad1f3c5 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
@@ -9,8 +9,8 @@ import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.Zone;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.flag.FlagId;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
-import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService;
import com.yahoo.vespa.hosted.provision.lb.Real;
import com.yahoo.vespa.hosted.provision.node.Agent;
@@ -20,13 +20,11 @@ import org.junit.Test;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
/**
* @author mpolden
@@ -51,6 +49,7 @@ public class LoadBalancerProvisionerTest {
public void provision_load_balancer() {
ClusterSpec.Id containerCluster1 = ClusterSpec.Id.from("qrs1");
ClusterSpec.Id contentCluster = ClusterSpec.Id.from("content");
+ tester.nodeRepository().flags().setEnabled(FlagId.exclusiveLoadBalancer, true);
tester.activate(app1, prepare(app1,
clusterRequest(ClusterSpec.Type.container, containerCluster1),
clusterRequest(ClusterSpec.Type.content, contentCluster)));
@@ -58,40 +57,32 @@ public class LoadBalancerProvisionerTest {
clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("qrs"))));
// Provision a load balancer for each application
- Map<LoadBalancerId, LoadBalancer> loadBalancers = loadBalancerProvisioner.provision(app1);
- loadBalancerProvisioner.provision(app2);
+ List<LoadBalancer> loadBalancers = loadBalancerProvisioner.get(app1);
assertEquals(1, loadBalancers.size());
- LoadBalancer loadBalancer = loadBalancers.values().iterator().next();
- assertEquals(loadBalancer.id().application(), app1);
- assertEquals(loadBalancer.id().cluster(), containerCluster1);
- assertEquals(loadBalancer.ports(), Collections.singletonList(4443));
- assertEquals(loadBalancer.reals().get(0).ipAddress(), "127.0.0.1");
- assertEquals(loadBalancer.reals().get(0).port(), 4443);
- assertEquals(loadBalancer.reals().get(1).ipAddress(), "127.0.0.2");
- assertEquals(loadBalancer.reals().get(1).port(), 4443);
+ assertEquals(loadBalancers.get(0).id().application(), app1);
+ assertEquals(loadBalancers.get(0).id().cluster(), containerCluster1);
+ assertEquals(loadBalancers.get(0).ports(), Collections.singletonList(4443));
+ assertEquals(loadBalancers.get(0).reals().get(0).ipAddress(), "127.0.0.1");
+ assertEquals(loadBalancers.get(0).reals().get(0).port(), 4443);
+ assertEquals(loadBalancers.get(0).reals().get(1).ipAddress(), "127.0.0.2");
+ assertEquals(loadBalancers.get(0).reals().get(1).port(), 4443);
// A container is failed
List<Node> containers = tester.getNodes(app1).type(ClusterSpec.Type.container).asList();
- Node container1 = containers.get(0);
- Node container2 = containers.get(1);
- tester.nodeRepository().fail(container1.hostname(), Agent.system, "Failed by unit test");
-
- // Reprovisioning load balancer removes failed container
- loadBalancer = loadBalancerProvisioner.provision(app1).values().iterator().next();
- assertEquals(1, loadBalancer.reals().size());
- assertEquals(container2.hostname(), loadBalancer.reals().get(0).hostname().value());
+ tester.nodeRepository().fail(containers.get(0).hostname(), Agent.system, "Failed by unit test");
// Redeploying replaces failed node
tester.activate(app1, prepare(app1,
clusterRequest(ClusterSpec.Type.container, containerCluster1),
clusterRequest(ClusterSpec.Type.content, contentCluster)));
- // Reprovisioning load balancer adds the new node
- Node container3 = tester.getNodes(app1).type(ClusterSpec.Type.container).asList().get(1);
- loadBalancer = loadBalancerProvisioner.provision(app1).values().iterator().next();
+ // Redeploy removed replaced failed node in load balancer
+ containers = tester.getNodes(app1).type(ClusterSpec.Type.container).asList();
+ LoadBalancer loadBalancer = loadBalancerProvisioner.get(app1).get(0);
assertEquals(2, loadBalancer.reals().size());
- assertEquals(container3.hostname(), loadBalancer.reals().get(1).hostname().value());
+ assertEquals(containers.get(0).hostname(), loadBalancer.reals().get(0).hostname().value());
+ assertEquals(containers.get(1).hostname(), loadBalancer.reals().get(1).hostname().value());
// Add another container cluster
ClusterSpec.Id containerCluster2 = ClusterSpec.Id.from("qrs2");
@@ -101,7 +92,7 @@ public class LoadBalancerProvisionerTest {
clusterRequest(ClusterSpec.Type.content, contentCluster)));
// Load balancer is provisioned for second container cluster
- loadBalancers = loadBalancerProvisioner.provision(app1);
+ loadBalancers = loadBalancerProvisioner.get(app1);
assertEquals(2, loadBalancers.size());
List<HostName> activeContainers = tester.getNodes(app1, Node.State.active)
.type(ClusterSpec.Type.container).asList()
@@ -110,28 +101,21 @@ public class LoadBalancerProvisionerTest {
.map(HostName::from)
.sorted()
.collect(Collectors.toList());
- List<HostName> reals = loadBalancers.values().stream()
+ List<HostName> reals = loadBalancers.stream()
.flatMap(lb -> lb.reals().stream())
.map(Real::hostname)
.sorted()
.collect(Collectors.toList());
assertEquals(activeContainers, reals);
- // Removing load balancer with active containers fails
- try {
- loadBalancerProvisioner.deactivate(app1);
- fail("Expected exception");
- } catch (IllegalArgumentException ignored) {}
-
- // Application and load balancer is removed
+ // Application is removed and load balancer is deactivated
NestedTransaction removeTransaction = new NestedTransaction();
tester.provisioner().remove(removeTransaction, app1);
removeTransaction.commit();
- loadBalancerProvisioner.deactivate(app1);
List<LoadBalancer> assignedLoadBalancer = tester.nodeRepository().database().readLoadBalancers(app1);
assertEquals(2, loadBalancers.size());
- assertTrue("Load balancers marked for deletion", assignedLoadBalancer.stream().allMatch(LoadBalancer::inactive));
+ assertTrue("Deactivated load balancers", assignedLoadBalancer.stream().allMatch(LoadBalancer::inactive));
}
private ClusterSpec clusterRequest(ClusterSpec.Type type, ClusterSpec.Id id) {
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 8c0937d34b8..27b592b0d55 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
@@ -91,8 +91,8 @@ public class ProvisioningTester {
new DockerImage("docker-registry.domain.tld:8080/dist/vespa"), true);
this.orchestrator = mock(Orchestrator.class);
doThrow(new RuntimeException()).when(orchestrator).acquirePermissionToRemove(any());
- this.provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone);
this.loadBalancerService = new LoadBalancerServiceMock();
+ this.provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone, loadBalancerService);
this.capacityPolicies = new CapacityPolicies(zone, nodeFlavors);
this.provisionLogger = new NullProvisionLogger();
}