summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorjonmv <venstad@gmail.com>2022-12-01 14:12:33 +0100
committerjonmv <venstad@gmail.com>2022-12-01 14:12:33 +0100
commit4226f2d67552c31e07a5be772691be213770a1b7 (patch)
tree8ae23d295a385dd286a6b2b080fc7a8715ab39c8 /node-repository
parent2925f225b34ad7fa3eb515bbddcc8c774e514131 (diff)
Write new settings only on activation
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java13
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java50
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java4
8 files changed, 42 insertions, 42 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
index 36e42fcf541..fde3c85bdab 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java
@@ -24,11 +24,11 @@ public class LoadBalancerInstance {
private final Set<Integer> ports;
private final Set<String> networks;
private final Set<Real> reals;
- private final Optional<LoadBalancerSettings> settings;
+ private final LoadBalancerSettings settings;
private final CloudAccount cloudAccount;
public LoadBalancerInstance(Optional<DomainName> hostname, Optional<String> ipAddress, Optional<DnsZone> dnsZone, Set<Integer> ports,
- Set<String> networks, Set<Real> reals, Optional<LoadBalancerSettings> settings, CloudAccount cloudAccount) {
+ Set<String> networks, Set<Real> reals, LoadBalancerSettings settings, CloudAccount cloudAccount) {
this.hostname = Objects.requireNonNull(hostname, "hostname must be non-null");
this.ipAddress = Objects.requireNonNull(ipAddress, "ip must be non-null");
this.dnsZone = Objects.requireNonNull(dnsZone, "dnsZone must be non-null");
@@ -74,8 +74,8 @@ public class LoadBalancerInstance {
return reals;
}
- /** Static user-configured settings of this load balancer, if set */
- public Optional<LoadBalancerSettings> settings() {
+ /** Static user-configured settings of this load balancer */
+ public LoadBalancerSettings settings() {
return settings;
}
@@ -89,11 +89,6 @@ public class LoadBalancerInstance {
return new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, settings, cloudAccount);
}
- /** Returns a copy of this with the given settings */
- public LoadBalancerInstance withSettings(LoadBalancerSettings settings) {
- return new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, Optional.of(settings), cloudAccount);
- }
-
private static Set<Integer> requirePorts(Set<Integer> ports) {
Objects.requireNonNull(ports, "ports must be non-null");
if (ports.isEmpty()) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
index 2b6f64012b1..a756c1fc01a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.lb;
import ai.vespa.http.DomainName;
import com.google.common.collect.ImmutableSet;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeType;
import java.util.Collections;
@@ -61,7 +62,7 @@ public class LoadBalancerServiceMock implements LoadBalancerService {
Collections.singleton(4443),
ImmutableSet.of("10.2.3.0/24", "10.4.5.0/24"),
spec.reals(),
- spec.settings(),
+ spec.settings().orElse(LoadBalancerSettings.empty),
spec.cloudAccount());
instances.put(id, instance);
return instance;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
index 13407a83f53..97e466827a6 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java
@@ -37,7 +37,7 @@ public class SharedLoadBalancerService implements LoadBalancerService {
Set.of(4443),
Set.of(),
spec.reals(),
- spec.settings(),
+ spec.settings().orElse(LoadBalancerSettings.empty),
spec.cloudAccount());
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java
index 0344c05c1c1..0264d0df837 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/LoadBalancerExpirer.java
@@ -112,9 +112,9 @@ public class LoadBalancerExpirer extends NodeRepositoryMaintainer {
attempts.add(1);
LOG.log(Level.INFO, () -> "Removing reals from inactive load balancer " + lb.id() + ": " + Sets.difference(lb.instance().get().reals(), reals));
service.create(new LoadBalancerSpec(lb.id().application(), lb.id().cluster(), reals,
- null, lb.instance().get().cloudAccount()),
+ lb.instance().get().settings(), lb.instance().get().cloudAccount()),
true);
- db.writeLoadBalancer(lb.with(lb.instance().map(instance -> instance.withReals(reals).withSettings(lb.instance().get().settings().get()))), lb.state());
+ db.writeLoadBalancer(lb.with(lb.instance().map(instance -> instance.withReals(reals))), lb.state());
} catch (Exception e) {
failed.add(lb.id());
lastException.set(e);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
index 22f6ec97107..9eccb21b756 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java
@@ -75,8 +75,8 @@ public class LoadBalancerSerializer {
}));
loadBalancer.instance()
.map(LoadBalancerInstance::settings)
- .filter(settings -> ! settings.get().isEmpty())
- .ifPresent(settings -> settings.get().allowedUrns().forEach(root.setObject(settingsField)
+ .filter(settings -> ! settings.isEmpty())
+ .ifPresent(settings -> settings.allowedUrns().forEach(root.setObject(settingsField)
.setArray(allowedUrnsField)::addString));
loadBalancer.instance()
.map(LoadBalancerInstance::cloudAccount)
@@ -112,7 +112,7 @@ public class LoadBalancerSerializer {
LoadBalancerSettings settings = loadBalancerSettings(object.field(settingsField));
CloudAccount cloudAccount = optionalString(object.field(cloudAccountField), CloudAccount::from).orElse(CloudAccount.empty);
Optional<LoadBalancerInstance> instance = hostname.isEmpty() && ipAddress.isEmpty() ? Optional.empty() :
- Optional.of(new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, Optional.of(settings), cloudAccount));
+ Optional.of(new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, settings, cloudAccount));
return new LoadBalancer(LoadBalancerId.fromSerializedForm(object.field(idField).asString()),
instance,
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 17fc83bce80..26a3f231a31 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
@@ -34,6 +34,7 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
@@ -41,6 +42,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import static java.util.Objects.requireNonNullElse;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.reducing;
@@ -94,7 +96,7 @@ public class LoadBalancerProvisioner {
ClusterSpec.Id clusterId = effectiveId(cluster);
LoadBalancerId loadBalancerId = requireNonClashing(new LoadBalancerId(application, clusterId));
NodeList nodes = nodesOf(clusterId, application);
- prepare(loadBalancerId, nodes, cluster.loadBalancerSettings(), requestedNodes.cloudAccount());
+ prepare(loadBalancerId, nodes, requestedNodes.cloudAccount());
}
}
@@ -109,18 +111,21 @@ public class LoadBalancerProvisioner {
* Calling this when no load balancer has been prepared for given cluster is a no-op.
*/
public void activate(Set<ClusterSpec> clusters, NodeList newActive, ApplicationTransaction transaction) {
- Set<ClusterSpec.Id> activatingClusters = clusters.stream()
- .map(LoadBalancerProvisioner::effectiveId)
- .collect(Collectors.toSet());
+ Map<ClusterSpec.Id, LoadBalancerSettings> activatingClusters = clusters.stream()
+ .collect(groupingBy(LoadBalancerProvisioner::effectiveId,
+ reducing(LoadBalancerSettings.empty,
+ ClusterSpec::loadBalancerSettings,
+ (o, n) -> o.isEmpty() ? n : o)));
for (var cluster : loadBalancedClustersOf(newActive).entrySet()) {
- if ( ! activatingClusters.contains(cluster.getKey())) continue;
+ if ( ! activatingClusters.containsKey(cluster.getKey()))
+ continue;
Node clusterNode = cluster.getValue().first().get();
if ( ! shouldProvision(transaction.application(), clusterNode.type(), clusterNode.allocation().get().membership().cluster().type())) continue;
- activate(transaction, cluster.getKey(), cluster.getValue());
+ activate(transaction, cluster.getKey(), activatingClusters.get(cluster.getKey()), cluster.getValue());
}
// Deactivate any surplus load balancers, i.e. load balancers for clusters that have been removed
- var surplusLoadBalancers = surplusLoadBalancersOf(transaction.application(), activatingClusters);
+ var surplusLoadBalancers = surplusLoadBalancersOf(transaction.application(), activatingClusters.keySet());
deactivate(surplusLoadBalancers, transaction.nested());
}
@@ -185,10 +190,10 @@ public class LoadBalancerProvisioner {
return loadBalancerId;
}
- private void prepare(LoadBalancerId id, NodeList nodes, LoadBalancerSettings loadBalancerSettings, CloudAccount cloudAccount) {
+ private void prepare(LoadBalancerId id, NodeList nodes, CloudAccount cloudAccount) {
Instant now = nodeRepository.clock().instant();
Optional<LoadBalancer> loadBalancer = db.readLoadBalancer(id);
- Optional<LoadBalancerInstance> instance = provisionInstance(id, nodes, loadBalancer, loadBalancerSettings, cloudAccount, false);
+ Optional<LoadBalancerInstance> instance = provisionInstance(id, nodes, loadBalancer, null, cloudAccount);
LoadBalancer newLoadBalancer;
LoadBalancer.State fromState = null;
if (loadBalancer.isEmpty()) {
@@ -207,17 +212,14 @@ public class LoadBalancerProvisioner {
requireInstance(id, instance, cloudAccount);
}
- private void activate(ApplicationTransaction transaction, ClusterSpec.Id cluster, NodeList nodes) {
+ private void activate(ApplicationTransaction transaction, ClusterSpec.Id cluster, LoadBalancerSettings settings, NodeList nodes) {
Instant now = nodeRepository.clock().instant();
LoadBalancerId id = new LoadBalancerId(transaction.application(), cluster);
Optional<LoadBalancer> loadBalancer = db.readLoadBalancer(id);
if (loadBalancer.isEmpty()) throw new IllegalArgumentException("Could not activate load balancer that was never prepared: " + id);
if (loadBalancer.get().instance().isEmpty()) throw new IllegalArgumentException("Activating " + id + ", but prepare never provisioned a load balancer instance");
- Optional<LoadBalancerInstance> instance = provisionInstance(id, nodes, loadBalancer,
- loadBalancer.get().instance().get().settings().orElseThrow(),
- loadBalancer.get().instance().get().cloudAccount(),
- true);
+ Optional<LoadBalancerInstance> instance = provisionInstance(id, nodes, loadBalancer, settings, loadBalancer.get().instance().get().cloudAccount());
LoadBalancer.State state = instance.isPresent() ? LoadBalancer.State.active : loadBalancer.get().state();
LoadBalancer newLoadBalancer = loadBalancer.get().with(instance).with(state, now);
db.writeLoadBalancers(List.of(newLoadBalancer), loadBalancer.get().state(), transaction.nested());
@@ -228,8 +230,7 @@ public class LoadBalancerProvisioner {
private Optional<LoadBalancerInstance> provisionInstance(LoadBalancerId id, NodeList nodes,
Optional<LoadBalancer> currentLoadBalancer,
LoadBalancerSettings loadBalancerSettings,
- CloudAccount cloudAccount,
- boolean activate) {
+ CloudAccount cloudAccount) {
boolean shouldDeactivateRouting = deactivateRouting.with(FetchVector.Dimension.APPLICATION_ID,
id.application().serializedForm())
.value();
@@ -239,14 +240,17 @@ public class LoadBalancerProvisioner {
} else {
reals = realsOf(nodes);
}
- LoadBalancerSettings settingsToUse = activate ? loadBalancerSettings : null;
- if (isUpToDate(currentLoadBalancer, reals, settingsToUse))
- return currentLoadBalancer.get().instance().map(instance -> instance.withSettings(loadBalancerSettings));
+ if (isUpToDate(currentLoadBalancer, reals, loadBalancerSettings))
+ return currentLoadBalancer.get().instance();
log.log(Level.INFO, () -> "Provisioning instance for " + id + ", targeting: " + reals);
try {
- return Optional.of(service.create(new LoadBalancerSpec(id.application(), id.cluster(), reals, settingsToUse, cloudAccount),
- shouldDeactivateRouting || allowEmptyReals(currentLoadBalancer))
- .withSettings(loadBalancerSettings));
+ // Override settings at activation, otherwise keep existing ones.
+ LoadBalancerSettings settings = loadBalancerSettings != null ? loadBalancerSettings
+ : currentLoadBalancer.flatMap(LoadBalancer::instance)
+ .map(LoadBalancerInstance::settings)
+ .orElse(null);
+ return Optional.of(service.create(new LoadBalancerSpec(id.application(), id.cluster(), reals, settings, cloudAccount),
+ shouldDeactivateRouting || allowEmptyReals(currentLoadBalancer)));
} catch (Exception e) {
log.log(Level.WARNING, e, () -> "Could not (re)configure " + id + ", targeting: " +
reals + ". The operation will be retried on next deployment");
@@ -306,7 +310,7 @@ public class LoadBalancerProvisioner {
if (loadBalancer.isEmpty()) return false;
if (loadBalancer.get().instance().isEmpty()) return false;
return loadBalancer.get().instance().get().reals().equals(reals)
- && (loadBalancerSettings == null || loadBalancer.get().instance().get().settings().get().equals(loadBalancerSettings));
+ && (loadBalancerSettings == null || loadBalancer.get().instance().get().settings().equals(loadBalancerSettings));
}
/** Returns whether to allow given load balancer to have no reals */
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java
index 307c9db38c6..1e0385d152a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java
@@ -45,7 +45,7 @@ public class LoadBalancerSerializerTest {
new Real(DomainName.of("real-2"),
"127.0.0.2",
4080)),
- Optional.of(new LoadBalancerSettings(List.of("123"))),
+ new LoadBalancerSettings(List.of("123")),
CloudAccount.from("012345678912"))),
LoadBalancer.State.active,
now);
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 a19f986a177..c7a2c94783b 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
@@ -320,14 +320,14 @@ public class LoadBalancerProvisionerTest {
tester.activate(app1, prepare(app1, capacity, clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("c1"))));
LoadBalancerList loadBalancers = tester.nodeRepository().loadBalancers().list();
assertEquals(1, loadBalancers.size());
- assertEquals(LoadBalancerSettings.empty, loadBalancers.first().get().instance().get().settings().get());
+ assertEquals(LoadBalancerSettings.empty, loadBalancers.first().get().instance().get().settings());
// Next deployment contains new settings
LoadBalancerSettings settings = new LoadBalancerSettings(List.of("alice", "bob"));
tester.activate(app1, prepare(app1, capacity, clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("c1"), Optional.empty(), settings)));
loadBalancers = tester.nodeRepository().loadBalancers().list();
assertEquals(1, loadBalancers.size());
- assertEquals(settings, loadBalancers.first().get().instance().get().settings().get());
+ assertEquals(settings, loadBalancers.first().get().instance().get().settings());
}