summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <freva@users.noreply.github.com>2023-01-18 18:34:50 +0100
committerGitHub <noreply@github.com>2023-01-18 18:34:50 +0100
commitc47ed544a31a6b56f518901247212a47d8eb9d31 (patch)
treebd83cefec54d52788217abddcac020dbc59ba0df
parente0191b4d49048f9398395dc8c1c60dfcb383f705 (diff)
parentce73e7681cf25865bf6f417f176eea1c85f5efba (diff)
Merge pull request #25624 from vespa-engine/revert-25617-jonmv/private-endpoints
Revert "Jonmv/private endpoints"
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java31
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java26
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java1
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java214
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationClusterEndpoint.java2
-rw-r--r--config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java282
-rw-r--r--config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecWithoutInstanceTest.java52
-rw-r--r--config-model-fat/pom.xml1
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java2
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/VespaDomBuilder.java30
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java25
-rw-r--r--config-model/src/main/resources/schema/containercluster.rnc13
-rw-r--r--config-model/src/main/resources/schema/deployment.rnc11
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java162
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java10
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java28
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java20
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java132
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java55
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java5
-rw-r--r--configserver/src/test/apps/hosted/services.xml5
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java53
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java11
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java88
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerInstance.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerServiceMock.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerSpec.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerService.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializer.java50
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java28
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java14
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerServiceTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/LoadBalancerSerializerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java30
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/load-balancers.json7
-rw-r--r--vespa-feed-client/src/test/java/ai/vespa/feed/client/impl/ApacheClusterTest.java4
46 files changed, 317 insertions, 1154 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java
index b36c1409459..fdde4c38fb8 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java
@@ -3,23 +3,17 @@ package com.yahoo.config.application.api;
import com.yahoo.config.provision.AthenzService;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Tags;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.zone.ZoneId;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -32,6 +26,7 @@ import static ai.vespa.validation.Validation.requireInRange;
import static com.yahoo.config.application.api.DeploymentSpec.RevisionChange.whenClear;
import static com.yahoo.config.application.api.DeploymentSpec.RevisionTarget.next;
import static com.yahoo.config.provision.Environment.prod;
+import static java.util.stream.Collectors.toList;
/**
* The deployment spec for an application instance
@@ -60,7 +55,6 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
private final Optional<CloudAccount> cloudAccount;
private final Notifications notifications;
private final List<Endpoint> endpoints;
- private final Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpoints;
public DeploymentInstanceSpec(InstanceName name,
Tags tags,
@@ -76,7 +70,6 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
Optional<CloudAccount> cloudAccount,
Notifications notifications,
List<Endpoint> endpoints,
- Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpoints,
Instant now) {
super(steps);
this.name = Objects.requireNonNull(name);
@@ -98,9 +91,6 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
this.cloudAccount = Objects.requireNonNull(cloudAccount);
this.notifications = Objects.requireNonNull(notifications);
this.endpoints = List.copyOf(Objects.requireNonNull(endpoints));
- Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpointsCopy = new HashMap<>();
- for (var entry : zoneEndpoints.entrySet()) zoneEndpointsCopy.put(entry.getKey(), Collections.unmodifiableMap(new HashMap<>(entry.getValue())));
- this.zoneEndpoints = Collections.unmodifiableMap(zoneEndpointsCopy);
validateZones(new HashSet<>(), new HashSet<>(), this);
validateEndpoints(steps(), globalServiceId, this.endpoints);
validateChangeBlockers(changeBlockers, now);
@@ -261,25 +251,6 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
return zones().stream().anyMatch(zone -> zone.concerns(environment, Optional.of(region)));
}
- /** Returns the zone endpoint specified for the given region, or empty. */
- Optional<ZoneEndpoint> zoneEndpoint(ZoneId zone, ClusterSpec.Id cluster) {
- return Optional.ofNullable(zoneEndpoints.get(cluster))
- .filter(__ -> deploysTo(zone.environment(), zone.region()))
- .map(zoneEndpoints -> zoneEndpoints.get(zoneEndpoints.containsKey(zone) ? zone : null));
- }
-
- /** Returns the zone endpoint data for this instance. */
- Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpoints() {
- return zoneEndpoints;
- }
-
- /** The zone endpoints in the given zone, possibly default values. */
- public Map<ClusterSpec.Id, ZoneEndpoint> zoneEndpoints(ZoneId zone) {
- return zoneEndpoints.keySet().stream()
- .collect(Collectors.toMap(cluster -> cluster,
- cluster -> zoneEndpoint(zone, cluster).orElse(ZoneEndpoint.defaultEndpoint)));
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
index d731e09d4e4..6c519a4656e 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
@@ -6,21 +6,16 @@ import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader;
import com.yahoo.config.provision.AthenzDomain;
import com.yahoo.config.provision.AthenzService;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.zone.ZoneId;
import java.io.Reader;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -52,7 +47,7 @@ public class DeploymentSpec {
private final List<Step> steps;
- // Attributes which can be set on the root tag and which must be available outside any particular instance
+ // Attributes which can be set on the root tag and which must be available outside of any particular instance
private final Optional<Integer> majorVersion;
private final Optional<AthenzDomain> athenzDomain;
private final Optional<AthenzService> athenzService;
@@ -150,10 +145,6 @@ public class DeploymentSpec {
illegal(prefix + "targets undeclared region '" + target.region() +
"' in instance '" + target.instance() + "'");
}
- if (instance.get().zoneEndpoint(ZoneId.from(Environment.prod, target.region()), ClusterSpec.Id.from(endpoint.containerId()))
- .map(zoneEndpoint -> ! zoneEndpoint.isPublicEndpoint()).orElse(false))
- illegal(prefix + "targets '" + target.region().value() + "' in '" + target.instance().value() +
- "', but its zone endpoint has 'enabled' set to 'false'");
}
}
}
@@ -184,21 +175,6 @@ public class DeploymentSpec {
/** Cloud account set on the deployment root; see discussion for {@link #athenzService}. */
public Optional<CloudAccount> cloudAccount() { return cloudAccount; }
- /**
- * Returns the most specific zone endpoint, where specificity is given, in decreasing order:
- * 1. The given instance has declared a zone endpoint for the cluster, for the given region.
- * 2. The given instance has declared a universal zone endpoint for the cluster.
- * 3. The application has declared a zone endpoint for the cluster, for the given region.
- * 4. The application has declared a universal zone endpoint for the cluster.
- * 5. None of the above apply, and the default of a publicly visible endpoint is used.
- */
- public ZoneEndpoint zoneEndpoint(InstanceName instance, ZoneId zone, ClusterSpec.Id cluster) {
- // TODO: look up endpoints from <dev> tag, or so, if we're to support non-prod settings.
- if (zone.environment() != Environment.prod) return ZoneEndpoint.defaultEndpoint;
- return instance(instance).flatMap(spec -> spec.zoneEndpoint(zone, cluster))
- .orElse(ZoneEndpoint.defaultEndpoint);
- }
-
/** Returns the XML form of this spec, or null if it was not created by fromXml, nor is empty */
public String xmlForm() { return xmlForm; }
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
index b4be99ad20b..571cc3c7d5c 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
@@ -24,7 +24,6 @@ public enum ValidationId {
skipOldConfigModels("skip-old-config-models"), // Internal use
accessControl("access-control"), // Internal use, used in zones where there should be no access-control
globalEndpointChange("global-endpoint-change"), // Changing global endpoints
- zoneEndpointChange("zone-endpoint-change"), // Changing zone (possibly private) endpoint settings
redundancyIncrease("redundancy-increase"), // Increasing redundancy - may easily cause feed blocked
redundancyOne("redundancy-one"), // redundancy=1 requires a validation override on first deployment
pagedSettingRemoval("paged-setting-removal"), // May cause content nodes to run out of memory
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
index fb6d834f783..8182e697e7e 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java
@@ -15,8 +15,6 @@ import com.yahoo.config.application.api.DeploymentSpec.Steps;
import com.yahoo.config.application.api.DeploymentSpec.UpgradePolicy;
import com.yahoo.config.application.api.DeploymentSpec.UpgradeRollout;
import com.yahoo.config.application.api.Endpoint;
-import com.yahoo.config.application.api.Endpoint.Level;
-import com.yahoo.config.application.api.Endpoint.Target;
import com.yahoo.config.application.api.Notifications;
import com.yahoo.config.application.api.Notifications.Role;
import com.yahoo.config.application.api.Notifications.When;
@@ -24,15 +22,10 @@ import com.yahoo.config.application.api.TimeWindow;
import com.yahoo.config.provision.AthenzDomain;
import com.yahoo.config.provision.AthenzService;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Tags;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.io.IOUtils;
import com.yahoo.text.XML;
import org.w3c.dom.Element;
@@ -46,20 +39,16 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
-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;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static java.util.Comparator.comparingInt;
-
/**
* @author bratseth
*/
@@ -134,7 +123,7 @@ public class DeploymentSpecXmlReader {
return DeploymentSpec.empty;
List<Step> steps = new ArrayList<>();
- List<Endpoint> applicationEndpoints = new ArrayList<>();
+ List<Endpoint> applicationEndpoints = List.of();
if ( ! containsTag(instanceTag, root)) { // deployment spec skipping explicit instance -> "default" instance
steps.addAll(readInstanceContent("default", root, new HashMap<>(), root));
}
@@ -152,7 +141,7 @@ public class DeploymentSpecXmlReader {
steps.addAll(readNonInstanceSteps(child, new HashMap<>(), root)); // (No global service id here)
}
}
- readEndpoints(root, Optional.empty(), steps, applicationEndpoints, Map.of());
+ applicationEndpoints = readEndpoints(root, Optional.empty(), steps);
}
return new DeploymentSpec(steps,
@@ -201,13 +190,11 @@ public class DeploymentSpecXmlReader {
Notifications notifications = readNotifications(instanceElement, parentTag);
// Values where there is no default
- Tags tags = XML.attribute(tagsTag, instanceElement).map(Tags::fromString).orElse(Tags.empty());
+ Tags tags = XML.attribute(tagsTag, instanceElement).map(value -> Tags.fromString(value)).orElse(Tags.empty());
List<Step> steps = new ArrayList<>();
for (Element instanceChild : XML.getChildren(instanceElement))
steps.addAll(readNonInstanceSteps(instanceChild, prodAttributes, instanceChild));
- List<Endpoint> endpoints = new ArrayList<>();
- Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpoints = new LinkedHashMap<>();
- readEndpoints(instanceElement, Optional.of(instanceNameString), steps, endpoints, zoneEndpoints);
+ List<Endpoint> endpoints = readEndpoints(instanceElement, Optional.of(instanceNameString), steps);
// Build and return instances with these values
Instant now = clock.instant();
@@ -227,7 +214,6 @@ public class DeploymentSpecXmlReader {
cloudAccount,
notifications,
endpoints,
- zoneEndpoints,
now))
.toList();
}
@@ -320,54 +306,19 @@ public class DeploymentSpecXmlReader {
return Notifications.of(emailAddresses, emailRoles);
}
- private void readEndpoints(Element parent, Optional<String> instance, List<Step> steps, List<Endpoint> endpoints,
- Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> zoneEndpoints) {
+ private List<Endpoint> readEndpoints(Element parent, Optional<String> instance, List<Step> steps) {
var endpointsElement = XML.getChild(parent, endpointsTag);
- if (endpointsElement == null) return;
+ if (endpointsElement == null) return List.of();
Endpoint.Level level = instance.isEmpty() ? Endpoint.Level.application : Endpoint.Level.instance;
- Map<String, Endpoint> endpointsById = new LinkedHashMap<>();
- Map<String, Map<RegionName, List<ZoneEndpoint>>> endpointsByZone = new LinkedHashMap<>();
- XML.getChildren(endpointsElement, endpointTag).stream() // Read zone settings first.
- .sorted(comparingInt(endpoint -> getZoneEndpointType(endpoint, level).isPresent() ? 0 : 1))
- .forEach(endpointElement -> {
+ Map<String, Endpoint> endpoints = new LinkedHashMap<>();
+ for (var endpointElement : XML.getChildren(endpointsElement, endpointTag)) {
+ String endpointId = stringAttribute("id", endpointElement).orElse(Endpoint.DEFAULT_ID);
String containerId = requireStringAttribute("container-id", endpointElement);
- Optional<String> endpointId = stringAttribute("id", endpointElement);
- Optional<String> zoneEndpointType = getZoneEndpointType(endpointElement, level);
String msgPrefix = (level == Endpoint.Level.application ? "Application-level" : "Instance-level") +
- " endpoint '" + endpointId.orElse(Endpoint.DEFAULT_ID) + "': ";
-
- if (zoneEndpointType.isPresent() && endpointId.isPresent())
- illegal(msgPrefix + "cannot declare 'id' with type 'zone' or 'private'");
-
+ " endpoint '" + endpointId + "': ";
String invalidChild = level == Endpoint.Level.application ? "region" : "instance";
- if ( ! XML.getChildren(endpointElement, invalidChild).isEmpty())
- illegal(msgPrefix + "invalid element '" + invalidChild + "'");
-
- boolean enabled = XML.attribute("enabled", endpointElement)
- .map(value -> {
- if (zoneEndpointType.isEmpty() || ! zoneEndpointType.get().equals("zone"))
- illegal(msgPrefix + "only endpoints of type 'zone' can specify 'enabled'");
-
- return switch (value) {
- case "true" -> true;
- case "false" -> false;
- default -> throw new IllegalArgumentException(msgPrefix + "invalid 'enabled' value; must be 'true' or 'false'");
- };
- }).orElse(true);
-
- List<AllowedUrn> allowedUrns = new ArrayList<>();
- for (var allow : XML.getChildren(endpointElement, "allow")) {
- if (zoneEndpointType.isEmpty() || ! zoneEndpointType.get().equals("private"))
- illegal(msgPrefix + "only endpoints of type 'private' can specify 'allow' children");
-
- switch (requireStringAttribute("with", allow)) {
- case "aws-private-link" -> allowedUrns.add(new AllowedUrn(AccessType.awsPrivateLink, requireStringAttribute("arn", allow)));
- case "gcp-service-connect" -> allowedUrns.add(new AllowedUrn(AccessType.gcpServiceConnect, requireStringAttribute("project", allow)));
- default -> illegal("Private endpoint for container-id '" + containerId + "': " +
- "invalid attribute 'with': '" + requireStringAttribute("with", allow) + "'");
- }
- }
+ if (!XML.getChildren(endpointElement, invalidChild).isEmpty()) illegal(msgPrefix + "invalid element '" + invalidChild + "'");
List<Endpoint.Target> targets = new ArrayList<>();
if (level == Endpoint.Level.application) {
@@ -394,132 +345,33 @@ public class DeploymentSpecXmlReader {
if (weightSum == 0) illegal(msgPrefix + "sum of all weights must be positive, got " + weightSum);
} else {
if (stringAttribute("region", endpointElement).isPresent()) illegal(msgPrefix + "invalid 'region' attribute");
- Set<RegionName> regions = new LinkedHashSet<>();
for (var regionElement : XML.getChildren(endpointElement, "region")) {
String region = regionElement.getTextContent();
- if (region == null || region.isBlank())
- illegal(msgPrefix + "empty 'region' element");
- if ( zoneEndpointType.isEmpty()
- && Stream.of(RegionName.from(region), null)
- .map(endpointsByZone.getOrDefault(containerId, new HashMap<>())::get)
- .flatMap(maybeEndpoints -> maybeEndpoints == null ? Stream.empty() : maybeEndpoints.stream())
- .anyMatch(endpoint -> ! endpoint.isPublicEndpoint()))
- illegal(msgPrefix + "targets zone endpoint in '" + region + "' with 'enabled' set to 'false'");
- if ( ! regions.add(RegionName.from(region)))
- illegal(msgPrefix + "duplicate 'region' element: '" + region + "'");
- }
-
- if (zoneEndpointType.isPresent()) {
- if (regions.isEmpty()) regions.add(null);
- ZoneEndpoint endpoint = switch (zoneEndpointType.get()) {
- case "zone" -> new ZoneEndpoint(enabled, false, List.of());
- case "private" -> new ZoneEndpoint(true, true, allowedUrns); // Doesn't turn off public visibility.
- default -> throw new IllegalArgumentException("unsupported zone endpoint type '" + zoneEndpointType.get() + "'");
- };
- for (RegionName region : regions) endpointsByZone.computeIfAbsent(containerId, __ -> new LinkedHashMap<>())
- .computeIfAbsent(region, __ -> new ArrayList<>())
- .add(endpoint);
- }
- else {
- if (regions.isEmpty()) {
- // No explicit targets given for instance level endpoint. Include all declared, enabled regions by default
- List<RegionName> declared =
- steps.stream()
- .filter(step -> step.concerns(Environment.prod))
- .flatMap(step -> step.zones().stream())
- .flatMap(zone -> zone.region().stream())
- .toList();
- if (declared.isEmpty()) illegal(msgPrefix + "no declared regions to target");
-
- declared.stream().filter(region -> Stream.of(region, null)
- .map(endpointsByZone.getOrDefault(containerId, new HashMap<>())::get)
- .flatMap(maybeEndpoints -> maybeEndpoints == null ? Stream.empty() : maybeEndpoints.stream())
- .allMatch(ZoneEndpoint::isPublicEndpoint))
- .forEach(regions::add);
- }
- if (regions.isEmpty()) illegal(msgPrefix + "all eligible zone endpoints have 'enabled' set to 'false'");
- InstanceName instanceName = instance.map(InstanceName::from).get();
- for (RegionName region : regions) targets.add(new Target(region, instanceName, 1));
- }
- }
-
- if (zoneEndpointType.isEmpty()) {
- Endpoint endpoint = new Endpoint(endpointId.orElse(Endpoint.DEFAULT_ID), containerId, level, targets);
- if (endpointsById.containsKey(endpoint.endpointId())) {
- illegal("Endpoint ID '" + endpoint.endpointId() + "' is specified multiple times");
+ if (region == null || region.isBlank()) illegal(msgPrefix + "empty 'region' element");
+ targets.add(new Endpoint.Target(RegionName.from(region),
+ InstanceName.from(instance.get()),
+ 1));
}
- endpointsById.put(endpoint.endpointId(), endpoint);
}
- });
- endpoints.addAll(endpointsById.values());
- validateAndConsolidate(endpointsByZone, zoneEndpoints);
- }
-
- static void validateAndConsolidate(Map<String, Map<RegionName, List<ZoneEndpoint>>> in, Map<ClusterSpec.Id, Map<ZoneId, ZoneEndpoint>> out) {
- in.forEach((cluster, regions) -> {
- List<ZoneEndpoint> wildcards = regions.remove(null);
- ZoneEndpoint wildcardZoneEndpoint = null;
- ZoneEndpoint wildcardPrivateEndpoint = null;
- if (wildcards != null) {
- for (ZoneEndpoint endpoint : wildcards) {
- if (endpoint.isPrivateEndpoint()) {
- if (wildcardPrivateEndpoint != null) illegal("Multiple private endpoints (for all regions) declared for " +
- "container id '" + cluster + "'");
- wildcardPrivateEndpoint = endpoint;
- }
- else {
- if (wildcardZoneEndpoint != null) illegal("Multiple zone endpoints (for all regions) declared " +
- "for container id '" + cluster + "'");
- wildcardZoneEndpoint = endpoint;
- }
- }
+ if (targets.isEmpty() && level == Endpoint.Level.instance) {
+ // No explicit targets given for instance level endpoint. Include all declared regions by default
+ InstanceName instanceName = instance.map(InstanceName::from).get();
+ steps.stream()
+ .filter(step -> step.concerns(Environment.prod))
+ .flatMap(step -> step.zones().stream())
+ .flatMap(zone -> zone.region().stream())
+ .distinct()
+ .map(region -> new Endpoint.Target(region, instanceName, 1))
+ .forEach(targets::add);
}
- for (RegionName region : regions.keySet()) {
- ZoneEndpoint zoneEndpoint = null;
- ZoneEndpoint privateEndpoint = null;
- for (ZoneEndpoint endpoint : regions.getOrDefault(region, List.of())) {
- if (endpoint.isPrivateEndpoint()) {
- if (privateEndpoint != null) illegal("Multiple private endpoints declared for " +
- "container id '" + cluster + "' in region '" + region + "'");
- privateEndpoint = endpoint;
- }
- else {
- if (zoneEndpoint != null) illegal("Multiple zone endpoints (without regions) declared " +
- "for container id '" + cluster + "' in region '" + region + "'");
- zoneEndpoint = endpoint;
- }
- }
- if (wildcardZoneEndpoint != null && zoneEndpoint != null) illegal("Zone endpoint for container id '" + cluster + "' declared " +
- "both with region '" + region + "', and for all regions.");
- if (wildcardPrivateEndpoint != null && privateEndpoint != null) illegal("Private endpoint for container id '" + cluster + "' declared " +
- "both with region '" + region + "', and for all regions.");
-
- if (zoneEndpoint == null) zoneEndpoint = wildcardZoneEndpoint;
- if (privateEndpoint == null) privateEndpoint = wildcardPrivateEndpoint;
-
- // Gosh, we made it here! Now we'll combine the settings for zone and private types into one ZoneEndpoint to rule them all.
- out.computeIfAbsent(ClusterSpec.Id.from(cluster), __ -> new LinkedHashMap<>())
- .put(ZoneId.from(Environment.prod, region), new ZoneEndpoint(zoneEndpoint == null || zoneEndpoint.isPublicEndpoint(),
- privateEndpoint != null,
- privateEndpoint != null ? privateEndpoint.allowedUrns() : List.of()));
+
+ Endpoint endpoint = new Endpoint(endpointId, containerId, level, targets);
+ if (endpoints.containsKey(endpoint.endpointId())) {
+ illegal("Endpoint ID '" + endpoint.endpointId() + "' is specified multiple times");
}
- out.computeIfAbsent(ClusterSpec.Id.from(cluster), __ -> new LinkedHashMap<>())
- .put(null, new ZoneEndpoint(wildcardZoneEndpoint == null || wildcardZoneEndpoint.isPublicEndpoint(),
- wildcardPrivateEndpoint != null,
- wildcardPrivateEndpoint != null ? wildcardPrivateEndpoint.allowedUrns() : List.of()));
- });
- }
-
- /** Returns endpoint type if a private or zone type endpoint, throws if invalid, or otherwise returns empty (global, application). */
- static Optional<String> getZoneEndpointType(Element endpoint, Level level) {
- Optional<String> type = XML.attribute("type", endpoint);
- if (type.isPresent() && ! List.of("zone", "private", "global", "application").contains(type.get()))
- illegal("Illegal endpoint type '" + type.get() + "'");
-
- String implied = switch (level) { case instance -> "global"; case application -> "application"; };
- if (type.isEmpty() || type.get().equals(implied)) return Optional.empty();
- if (level == Level.instance && (type.get().equals("zone") || type.get().equals("private"))) return type;
- throw new IllegalArgumentException("Endpoints at " + level + " level cannot be of type '" + type.get() + "'");
+ endpoints.put(endpoint.endpointId(), endpoint);
+ }
+ return List.copyOf(endpoints.values());
}
/**
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationClusterEndpoint.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationClusterEndpoint.java
index b7969267328..99bf768f67e 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationClusterEndpoint.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationClusterEndpoint.java
@@ -26,7 +26,7 @@ public class ApplicationClusterEndpoint {
", routingMethod=" + routingMethod +
", weight=" + weight +
", hostNames=" + hostNames +
- ", clusterId='" + clusterId + "'" +
+ ", clusterId='" + clusterId + '\'' +
'}';
}
diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
index 355ce651c34..96cd4810ec4 100644
--- a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
+++ b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java
@@ -6,14 +6,10 @@ import com.yahoo.config.application.api.Endpoint.Level;
import com.yahoo.config.application.api.Endpoint.Target;
import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Tags;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
import com.yahoo.test.ManualClock;
import org.junit.Test;
@@ -23,7 +19,6 @@ import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -32,12 +27,9 @@ import java.util.stream.Collectors;
import static com.yahoo.config.application.api.Notifications.Role.author;
import static com.yahoo.config.application.api.Notifications.When.failing;
import static com.yahoo.config.application.api.Notifications.When.failingCommit;
-import static com.yahoo.config.provision.zone.ZoneId.defaultId;
-import static com.yahoo.config.provision.zone.ZoneId.from;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -1191,16 +1183,15 @@ public class DeploymentSpecTest {
@Test
public void customTesterFlavor() {
- DeploymentSpec spec = DeploymentSpec.fromXml("""
- <deployment>
- <instance id='default'>
- <test tester-flavor="d-1-4-20" />
- <staging />
- <prod tester-flavor="d-2-8-50">
- <region active="false">us-north-7</region>
- </prod>
- </instance>
- </deployment>""");
+ DeploymentSpec spec = DeploymentSpec.fromXml("<deployment>" +
+ " <instance id='default'>" +
+ " <test tester-flavor=\"d-1-4-20\" />" +
+ " <staging />" +
+ " <prod tester-flavor=\"d-2-8-50\">" +
+ " <region active=\"false\">us-north-7</region>" +
+ " </prod>" +
+ " </instance>" +
+ "</deployment>");
assertEquals(Optional.of("d-1-4-20"), spec.requireInstance("default").steps().get(0).zones().get(0).testerFlavor());
assertEquals(Optional.empty(), spec.requireInstance("default").steps().get(1).zones().get(0).testerFlavor());
assertEquals(Optional.of("d-2-8-50"), spec.requireInstance("default").steps().get(2).zones().get(0).testerFlavor());
@@ -1208,55 +1199,39 @@ public class DeploymentSpecTest {
@Test
public void noEndpoints() {
- DeploymentSpec spec = DeploymentSpec.fromXml("""
- <deployment>
- <instance id='default'/>
- </deployment>
- """);
- assertEquals(Collections.emptyList(), spec.requireInstance("default").endpoints());
- assertEquals(ZoneEndpoint.defaultEndpoint, spec.zoneEndpoint(InstanceName.defaultName(),
- defaultId(),
- ClusterSpec.Id.from("cluster")));
+ assertEquals(Collections.emptyList(),
+ DeploymentSpec.fromXml("<deployment>" +
+ " <instance id='default'/>" +
+ "</deployment>").requireInstance("default").endpoints());
}
@Test
public void emptyEndpoints() {
- var spec = DeploymentSpec.fromXml("""
- <deployment>
- <instance id='default'>
- <endpoints/>
- </instance>
- </deployment>""");
+ var spec = DeploymentSpec.fromXml("<deployment>" +
+ " <instance id='default'>" +
+ " <endpoints/>" +
+ " </instance>" +
+ "</deployment>");
assertEquals(List.of(), spec.requireInstance("default").endpoints());
- assertEquals(ZoneEndpoint.defaultEndpoint, spec.zoneEndpoint(InstanceName.defaultName(),
- defaultId(),
- ClusterSpec.Id.from("cluster")));
}
@Test
public void someEndpoints() {
- var spec = DeploymentSpec.fromXml("""
- <deployment>
- <instance id='default'>
- <prod>
- <region active="true">us-east</region>
- </prod>
- <endpoints>
- <endpoint id="foo" container-id="bar">
- <region>us-east</region>
- </endpoint>
- <endpoint id="nalle" container-id="frosk" />
- <endpoint container-id="quux" />
- <endpoint container-id='bax' type='zone' enabled='true' />
- <endpoint container-id='froz' type='zone' enabled='false' />
- <endpoint container-id='froz' type='private'>
- <region>us-east</region>
- <allow with='aws-private-link' arn='barn' />
- <allow with='gcp-service-connect' project='nine' />
- </endpoint>
- </endpoints>
- </instance>
- </deployment>""");
+ var spec = DeploymentSpec.fromXml("" +
+ "<deployment>" +
+ " <instance id='default'>" +
+ " <prod>" +
+ " <region active=\"true\">us-east</region>" +
+ " </prod>" +
+ " <endpoints>" +
+ " <endpoint id=\"foo\" container-id=\"bar\">" +
+ " <region>us-east</region>" +
+ " </endpoint>" +
+ " <endpoint id=\"nalle\" container-id=\"frosk\" />" +
+ " <endpoint container-id=\"quux\" />" +
+ " </endpoints>" +
+ " </instance>" +
+ "</deployment>");
assertEquals(
List.of("foo", "nalle", "default"),
@@ -1269,59 +1244,18 @@ public class DeploymentSpecTest {
);
assertEquals(List.of(RegionName.from("us-east")), spec.requireInstance("default").endpoints().get(0).regions());
-
- var zone = from(Environment.prod, RegionName.from("us-east"));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("custom"), zone, ClusterSpec.Id.from("bax")));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("default"), defaultId(), ClusterSpec.Id.from("bax")));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("default"), zone, ClusterSpec.Id.from("bax")));
-
- assertEquals(new ZoneEndpoint(false, true, List.of(new AllowedUrn(AccessType.awsPrivateLink, "barn"),
- new AllowedUrn(AccessType.gcpServiceConnect, "nine"))),
- spec.zoneEndpoint(InstanceName.from("default"), zone, ClusterSpec.Id.from("froz")));
}
@Test
public void invalidEndpoints() {
- assertInvalidEndpoints("<endpoint id='FOO' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'FOO'");
- assertInvalidEndpoints("<endpoint id='123' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got '123'");
- assertInvalidEndpoints("<endpoint id='foo!' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'foo!'");
- assertInvalidEndpoints("<endpoint id='foo.bar' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'foo.bar'");
- assertInvalidEndpoints("<endpoint id='foo--bar' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'foo--bar'");
- assertInvalidEndpoints("<endpoint id='foo-' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'foo-'");
- assertInvalidEndpoints("<endpoint id='foooooooooooo' container-id='qrs'/>",
- "Endpoint ID must be all lowercase, alphanumeric, with no consecutive dashes, of length 1 to 12, and begin with a character; but got 'foooooooooooo'");
-
- assertInvalidEndpoints("<endpoint id='foo' container-id='qrs'/><endpoint id='foo' container-id='qrs'/>",
- "Endpoint ID 'foo' is specified multiple times");
- assertInvalidEndpoints("<endpoint id='default' type='zone' container-id='foo' />",
- "Instance-level endpoint 'default': cannot declare 'id' with type 'zone' or 'private'");
- assertInvalidEndpoints("<endpoint id='default' type='private' container-id='foo' />",
- "Instance-level endpoint 'default': cannot declare 'id' with type 'zone' or 'private'");
- assertInvalidEndpoints("<endpoint type='zone' />",
- "Missing required attribute 'container-id' in 'endpoint'");
- assertInvalidEndpoints("<endpoint type='private' />",
- "Missing required attribute 'container-id' in 'endpoint'");
- assertInvalidEndpoints("<endpoint container-id='foo' type='zone'><allow /></endpoint>",
- "Instance-level endpoint 'default': only endpoints of type 'private' can specify 'allow' children");
- assertInvalidEndpoints("<endpoint type='private' container-id='foo' enabled='true' />",
- "Instance-level endpoint 'default': only endpoints of type 'zone' can specify 'enabled'");
- assertInvalidEndpoints("<endpoint type='zone' container-id='qrs'/><endpoint type='zone' container-id='qrs'/>",
- "Multiple zone endpoints (for all regions) declared for container id 'qrs'");
- assertInvalidEndpoints("<endpoint type='private' container-id='qrs'><region>us</region></endpoint>" +
- "<endpoint type='private' container-id='qrs'><region>us</region></endpoint>",
- "Multiple private endpoints declared for container id 'qrs' in region 'us'");
- assertInvalidEndpoints("<endpoint type='zone' container-id='qrs' />" +
- "<endpoint type='zone' container-id='qrs'><region>us</region></endpoint>",
- "Zone endpoint for container id 'qrs' declared both with region 'us', and for all regions.");
+ assertInvalidEndpoints("<endpoint id='FOO' container-id='qrs'/>"); // Uppercase
+ assertInvalidEndpoints("<endpoint id='123' container-id='qrs'/>"); // Starting with non-character
+ assertInvalidEndpoints("<endpoint id='foo!' container-id='qrs'/>"); // Non-alphanumeric
+ assertInvalidEndpoints("<endpoint id='foo.bar' container-id='qrs'/>");
+ assertInvalidEndpoints("<endpoint id='foo--bar' container-id='qrs'/>"); // Multiple consecutive dashes
+ assertInvalidEndpoints("<endpoint id='foo-' container-id='qrs'/>"); // Trailing dash
+ assertInvalidEndpoints("<endpoint id='foooooooooooo' container-id='qrs'/>"); // Too long
+ assertInvalidEndpoints("<endpoint id='foo' container-id='qrs'/><endpoint id='foo' container-id='qrs'/>"); // Duplicate
}
@Test
@@ -1337,44 +1271,25 @@ public class DeploymentSpecTest {
@Test
public void endpointDefaultRegions() {
- var spec = DeploymentSpec.fromXml("""
- <deployment>
- <instance id='default'>
- <prod>
- <region>us-east</region>
- <region>us-west</region>
- </prod>
- <endpoints>
- <endpoint id="foo" container-id="bar">
- <region>us-east</region>
- </endpoint>
- <endpoint container-id="bar" type='private'>
- <region>us-east</region>
- </endpoint>
- <endpoint id="nalle" container-id="frosk" />
- <endpoint container-id="quux" />
- <endpoint container-id="quux" type='private' />
- </endpoints>
- </instance>
- </deployment>""");
+ var spec = DeploymentSpec.fromXml("<deployment>" +
+ " <instance id='default'>" +
+ " <prod>" +
+ " <region>us-east</region>" +
+ " <region>us-west</region>" +
+ " </prod>" +
+ " <endpoints>" +
+ " <endpoint id=\"foo\" container-id=\"bar\">" +
+ " <region>us-east</region>" +
+ " </endpoint>" +
+ " <endpoint id=\"nalle\" container-id=\"frosk\" />" +
+ " <endpoint container-id=\"quux\" />" +
+ " </endpoints>" +
+ " </instance>" +
+ "</deployment>");
assertEquals(Set.of("us-east"), endpointRegions("foo", spec));
assertEquals(Set.of("us-east", "us-west"), endpointRegions("nalle", spec));
assertEquals(Set.of("us-east", "us-west"), endpointRegions("default", spec));
- assertEquals(new ZoneEndpoint(true, true, List.of()),
- spec.zoneEndpoint(InstanceName.from("default"), from("prod", "us-east"), ClusterSpec.Id.from("bar")));
- assertEquals(new ZoneEndpoint(true, false, List.of()),
- spec.zoneEndpoint(InstanceName.from("default"), from("prod", "us-west"), ClusterSpec.Id.from("bar")));
- assertEquals(new ZoneEndpoint(true, true, List.of()),
- spec.zoneEndpoint(InstanceName.from("default"), from("prod", "us-east"), ClusterSpec.Id.from("quux")));
- assertEquals(new ZoneEndpoint(true, true, List.of()),
- spec.zoneEndpoint(InstanceName.from("default"), from("prod", "us-west"), ClusterSpec.Id.from("quux")));
- assertEquals(new HashSet<>() {{ add(null); add(from("prod", "us-east")); }},
- spec.requireInstance("default").zoneEndpoints().get(ClusterSpec.Id.from("bar")).keySet());
- assertEquals(new HashSet<>() {{ add(null); }},
- spec.requireInstance("default").zoneEndpoints().get(ClusterSpec.Id.from("quux")).keySet());
- assertEquals(Set.of(ClusterSpec.Id.from("bar"), ClusterSpec.Id.from("quux")),
- spec.requireInstance("default").zoneEndpoints().keySet());
}
@Test
@@ -1387,16 +1302,14 @@ public class DeploymentSpecTest {
<region active="true">us-west</region>
</prod>
<endpoints>
- <endpoint container-id="bar" %s>
+ <endpoint id="foo" container-id="bar" %s>
%s
</endpoint>
</endpoints>
</instance>
</deployment>""";
- assertInvalid(String.format(xmlForm, "id='foo' region='us-east'", "<region>us-east</region>"), "Instance-level endpoint 'foo': invalid 'region' attribute");
- assertInvalid(String.format(xmlForm, "id='foo'", "<instance>us-east</instance>"), "Instance-level endpoint 'foo': invalid element 'instance'");
- assertInvalid(String.format(xmlForm, "type='zone'", "<instance>us-east</instance>"), "Instance-level endpoint 'default': invalid element 'instance'");
- assertInvalid(String.format(xmlForm, "type='private'", "<instance>us-east</instance>"), "Instance-level endpoint 'default': invalid element 'instance'");
+ assertInvalid(String.format(xmlForm, "region='us-east'", "<region>us-east</region>"), "Instance-level endpoint 'foo': invalid 'region' attribute");
+ assertInvalid(String.format(xmlForm, "", "<instance>us-east</instance>"), "Instance-level endpoint 'foo': invalid element 'instance'");
}
@Test
@@ -1430,73 +1343,6 @@ public class DeploymentSpecTest {
assertInvalid(String.format(xmlForm, "region='us-west-1'", "weight='foo'", "", "main", ""), "Application-level endpoint 'foo': invalid weight value 'foo'");
assertInvalid(String.format(xmlForm, "region='us-west-1'", "weight='1'", "", "main", "<region>us-east-3</region>"), "Application-level endpoint 'foo': invalid element 'region'");
assertInvalid(String.format(xmlForm, "region='us-west-1'", "weight='0'", "", "main", ""), "Application-level endpoint 'foo': sum of all weights must be positive, got 0");
- assertInvalid(String.format(xmlForm, "type='zone'", "weight='1'", "", "main", ""), "Endpoints at application level cannot be of type 'zone'");
- assertInvalid(String.format(xmlForm, "type='private'", "weight='1'", "", "main", ""), "Endpoints at application level cannot be of type 'private'");
- }
-
- @Test
- public void cannotTargetDisabledEndpoints() {
- assertEquals("Instance-level endpoint 'default': all eligible zone endpoints have 'enabled' set to 'false'",
- assertThrows(IllegalArgumentException.class,
- () -> DeploymentSpec.fromXml("""
- <deployment>
- <instance id="default">
- <prod>
- <region>us</region>
- <region>eu</region>
- </prod>
- <endpoints>
- <endpoint container-id='id' />
- <endpoint type='zone' container-id='id' enabled='false' />
- </endpoints>
- </instance>
- </deployment>
- """))
- .getMessage());
-
- assertEquals("Instance-level endpoint 'default': targets zone endpoint in 'us' with 'enabled' set to 'false'",
- assertThrows(IllegalArgumentException.class,
- () -> DeploymentSpec.fromXml("""
- <deployment>
- <instance id="default">
- <prod>
- <region>us</region>
- <region>eu</region>
- </prod>
- <endpoints>
- <endpoint container-id='id'>
- <region>us</region>
- </endpoint>
- <endpoint type='zone' container-id='id' enabled='false' />
- </endpoints>
- </instance>
- </deployment>
- """))
- .getMessage());
-
- assertEquals("Application-level endpoint 'default': targets 'us' in 'default', but its zone endpoint has 'enabled' set to 'false'",
- assertThrows(IllegalArgumentException.class,
- () -> DeploymentSpec.fromXml("""
- <deployment>
- <instance id="default">
- <prod>
- <region>us</region>
- <region>eu</region>
- </prod>
- <endpoints>
- <endpoint type='zone' container-id='id' enabled='false'>
- <region>us</region>
- </endpoint>
- </endpoints>
- </instance>
- <endpoints>
- <endpoint container-id='id' region='us'>
- <instance weight='1'>default</instance>
- </endpoint>
- </endpoints>
- </deployment>
- """))
- .getMessage());
}
@Test
@@ -1802,11 +1648,11 @@ public class DeploymentSpecTest {
}
}
- private static void assertInvalidEndpoints(String endpointsBody, String error) {
- assertEquals(error,
- assertThrows(IllegalArgumentException.class,
- () -> endpointIds(endpointsBody))
- .getMessage());
+ private static void assertInvalidEndpoints(String endpointsBody) {
+ try {
+ endpointIds(endpointsBody);
+ fail("Expected exception for input '" + endpointsBody + "'");
+ } catch (IllegalArgumentException ignored) {}
}
private static Set<String> endpointRegions(String endpointId, DeploymentSpec spec) {
diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecWithoutInstanceTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecWithoutInstanceTest.java
index 38410cc5b37..6ff5616a80f 100644
--- a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecWithoutInstanceTest.java
+++ b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecWithoutInstanceTest.java
@@ -3,13 +3,8 @@ package com.yahoo.config.application.api;
import com.google.common.collect.ImmutableSet;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
import org.junit.Test;
import java.io.StringReader;
@@ -25,8 +20,6 @@ import java.util.stream.Collectors;
import static com.yahoo.config.application.api.Notifications.Role.author;
import static com.yahoo.config.application.api.Notifications.When.failing;
import static com.yahoo.config.application.api.Notifications.When.failingCommit;
-import static com.yahoo.config.provision.zone.ZoneId.defaultId;
-import static com.yahoo.config.provision.zone.ZoneId.from;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -661,26 +654,19 @@ public class DeploymentSpecWithoutInstanceTest {
@Test
public void someEndpoints() {
- var spec = DeploymentSpec.fromXml("""
- <deployment>
- <prod>
- <region active="true">us-east</region>
- </prod>
- <endpoints>
- <endpoint id="foo" container-id="bar">
- <region>us-east</region>
- </endpoint>
- <endpoint id="nalle" container-id="frosk" />
- <endpoint container-id="quux" />
- <endpoint container-id='bax' type='zone' enabled='true' />
- <endpoint container-id='froz' type='zone' enabled='false' />
- <endpoint container-id='froz' type='private'>
- <region>us-east</region>
- <allow with='aws-private-link' arn='barn' />
- <allow with='gcp-service-connect' project='nine' />
- </endpoint>
- </endpoints>
- </deployment>""");
+ var spec = DeploymentSpec.fromXml("" +
+ "<deployment>" +
+ " <prod>" +
+ " <region active=\"true\">us-east</region>" +
+ " </prod>" +
+ " <endpoints>" +
+ " <endpoint id=\"foo\" container-id=\"bar\">" +
+ " <region>us-east</region>" +
+ " </endpoint>" +
+ " <endpoint id=\"nalle\" container-id=\"frosk\" />" +
+ " <endpoint container-id=\"quux\" />" +
+ " </endpoints>" +
+ "</deployment>");
assertEquals(
List.of("foo", "nalle", "default"),
@@ -693,18 +679,6 @@ public class DeploymentSpecWithoutInstanceTest {
);
assertEquals(List.of(RegionName.from("us-east")), spec.requireInstance("default").endpoints().get(0).regions());
-
- var zone = from(Environment.prod, RegionName.from("us-east"));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("custom"), zone, ClusterSpec.Id.from("bax")));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("default"), defaultId(), ClusterSpec.Id.from("bax")));
- assertEquals(ZoneEndpoint.defaultEndpoint,
- spec.zoneEndpoint(InstanceName.from("default"), zone, ClusterSpec.Id.from("bax")));
-
- assertEquals(new ZoneEndpoint(false, true, List.of(new AllowedUrn(AccessType.awsPrivateLink, "barn"),
- new AllowedUrn(AccessType.gcpServiceConnect, "nine"))),
- spec.zoneEndpoint(InstanceName.from("default"), zone, ClusterSpec.Id.from("froz")));
}
@Test
diff --git a/config-model-fat/pom.xml b/config-model-fat/pom.xml
index 0dafb96d575..6da024c6705 100644
--- a/config-model-fat/pom.xml
+++ b/config-model-fat/pom.xml
@@ -79,7 +79,6 @@
com.yahoo.component.provider,
com.yahoo.config,
com.yahoo.config.application.api,
- com.yahoo.config.application.api.xml,
com.yahoo.config.model.api,
com.yahoo.config.model.api.container,
com.yahoo.config.provision,
diff --git a/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java b/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
index 756646beddb..95d97bc9e87 100644
--- a/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
+++ b/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
@@ -80,7 +80,7 @@ public class ConfigModelRepo implements ConfigModelRepoAdder, Serializable, Iter
ConfigModelRegistry configModelRegistry) throws IOException {
Element userServicesElement = getServicesFromApp(deployState.getApplicationPackage());
readConfigModels(root, userServicesElement, deployState, vespaModel, configModelRegistry);
- builder.postProc(deployState, root, this);
+ builder.postProc(deployState.getDeployLogger(), root, this);
}
private Element getServicesFromApp(ApplicationPackage applicationPackage) throws IOException {
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index 49194a5d1bb..7cb0672699f 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -37,7 +37,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private ApplicationId applicationId = ApplicationId.defaultId();
private List<ConfigServerSpec> configServerSpecs = Collections.emptyList();
private boolean hostedVespa = false;
- private Zone zone = Zone.defaultZone();
+ private Zone zone;
private final Set<ContainerEndpoint> endpoints = Collections.emptySet();
private boolean useDedicatedNodeForLogserver = false;
private double defaultTermwiseLimit = 1.0;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java
index 421e3a2902c..2cf32f1e8ff 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java
@@ -22,6 +22,6 @@ public abstract class VespaModelBuilder {
* @param producerRoot the root producer.
* @param configModelRepo a {@link com.yahoo.config.model.ConfigModelRepo instance}
*/
- public abstract void postProc(DeployState deployState, AbstractConfigProducer producerRoot, ConfigModelRepo configModelRepo);
+ public abstract void postProc(DeployLogger deployLogger, AbstractConfigProducer producerRoot, ConfigModelRepo configModelRepo);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
index aac968f9038..a31e3fcce71 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
@@ -4,7 +4,6 @@ package com.yahoo.vespa.model.builder.xml.dom;
import com.yahoo.collections.Pair;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeployLogger;
-import com.yahoo.config.provision.ZoneEndpoint;
import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.CloudAccount;
@@ -12,6 +11,7 @@ import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.DockerImage;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.text.XML;
import com.yahoo.vespa.model.HostResource;
@@ -256,13 +256,13 @@ public class NodesSpecification {
ClusterSpec.Id clusterId,
DeployLogger logger,
boolean stateful) {
- return provision(hostSystem, clusterType, clusterId, ZoneEndpoint.defaultEndpoint, logger, stateful);
+ return provision(hostSystem, clusterType, clusterId, LoadBalancerSettings.empty, logger, stateful);
}
public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem,
ClusterSpec.Type clusterType,
ClusterSpec.Id clusterId,
- ZoneEndpoint zoneEndpoint,
+ LoadBalancerSettings loadBalancerSettings,
DeployLogger logger,
boolean stateful) {
if (combinedId.isPresent())
@@ -272,7 +272,7 @@ public class NodesSpecification {
.exclusive(exclusive)
.combinedId(combinedId.map(ClusterSpec.Id::from))
.dockerImageRepository(dockerImageRepo)
- .loadBalancerSettings(zoneEndpoint)
+ .loadBalancerSettings(loadBalancerSettings)
.stateful(stateful)
.build();
return hostSystem.allocateHosts(cluster, Capacity.from(min, max, required, canFail, cloudAccount), logger);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/VespaDomBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/VespaDomBuilder.java
index e4e56dcaaca..cb3c43074fc 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/VespaDomBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/VespaDomBuilder.java
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.builder.xml.dom;
-import ai.vespa.validation.Validation;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.ApplicationConfigProducerRoot;
import com.yahoo.config.model.ConfigModelRepo;
@@ -23,15 +22,8 @@ import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
import com.yahoo.vespa.model.content.Content;
import com.yahoo.vespa.model.search.SearchCluster;
import org.w3c.dom.Element;
-
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.regex.Pattern;
/**
* Builds Vespa model components using the w3c dom api
@@ -51,12 +43,10 @@ public class VespaDomBuilder extends VespaModelBuilder {
public static final String VESPAMALLOC = "vespamalloc"; // Intended for vespa engineers
public static final String VESPAMALLOC_DEBUG = "vespamalloc-debug"; // Intended for vespa engineers
public static final String VESPAMALLOC_DEBUG_STACKTRACE = "vespamalloc-debug-stacktrace"; // Intended for vespa engineers
+ private static final String CPU_SOCKET_ATTRIB_NAME = "cpu-socket";
public static final String CPU_SOCKET_AFFINITY_ATTRIB_NAME = "cpu-socket-affinity";
public static final String Allocated_MEMORY_ATTRIB_NAME = "allocated-memory";
- private static final String CPU_SOCKET_ATTRIB_NAME = "cpu-socket";
- private static final Pattern clusterPattern = Pattern.compile("([a-z0-9]|[a-z0-9][a-z0-9_-]{0,61}[a-z0-9])");
-
public static final Logger log = Logger.getLogger(VespaDomBuilder.class.getPackage().toString());
@@ -242,14 +232,13 @@ public class VespaDomBuilder extends VespaModelBuilder {
* @param root root config producer
* @param configModelRepo a {@link ConfigModelRepo}
*/
- public void postProc(DeployState deployState, AbstractConfigProducer root, ConfigModelRepo configModelRepo) {
+ public void postProc(DeployLogger deployLogger, AbstractConfigProducer root, ConfigModelRepo configModelRepo) {
setContentSearchClusterIndexes(configModelRepo);
createDocprocMBusServersAndClients(configModelRepo);
- if (deployState.isHosted()) validateContainerClusterIds(configModelRepo);
}
private void createDocprocMBusServersAndClients(ConfigModelRepo pc) {
- for (ContainerCluster<?> cluster: ContainerModel.containerClusters(pc)) {
+ for (ContainerCluster cluster: ContainerModel.containerClusters(pc)) {
addServerAndClientsForChains(cluster.getDocproc());
}
}
@@ -259,19 +248,6 @@ public class VespaDomBuilder extends VespaModelBuilder {
docproc.getChains().addServersAndClientsForChains();
}
- private void validateContainerClusterIds(ConfigModelRepo pc) {
- Map<String, String> normalizedClusterIds = new LinkedHashMap<>();
- for (ContainerCluster<?> cluster: ContainerModel.containerClusters(pc)) {
- if (cluster.getHttp() == null) continue;
- String name = cluster.getName();
- Validation.requireMatch(name, "container cluster name", clusterPattern);
- String clashing = normalizedClusterIds.put(name.replaceAll("_", "-"), name);
- if (clashing != null) throw new IllegalArgumentException("container clusters '" + clashing + "' and '" + name +
- "' have clashing endpoint names, when '_' is replaced " +
- "with '-' to form valid domain names");
- }
- }
-
/**
* For some reason, search clusters need to be enumerated.
* @param configModelRepo a {@link ConfigModelRepo}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 4c7bad575d2..d0a03be2869 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -11,8 +11,6 @@ import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader;
import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.model.api.ApplicationClusterEndpoint;
import com.yahoo.config.model.api.ConfigServerSpec;
@@ -31,11 +29,10 @@ import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Zone;
-import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.container.logging.FileConnectionLog;
import com.yahoo.io.IOUtils;
@@ -850,14 +847,11 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
}
- private ZoneEndpoint zoneEndpoint(ConfigModelContext context, ClusterSpec.Id cluster) {
- InstanceName instance = context.properties().applicationId().instance();
- ZoneId zone = ZoneId.from(context.properties().zone().environment(),
- context.properties().zone().region());
- DeploymentSpec spec = context.getApplicationPackage().getDeployment()
- .map(new DeploymentSpecXmlReader(false)::read)
- .orElse(DeploymentSpec.empty);
- return spec.zoneEndpoint(instance, zone, cluster);
+ private LoadBalancerSettings loadBalancerSettings(Element loadBalancerElement) {
+ List<String> allowedUrnElements = XML.getChildren(XML.getChild(loadBalancerElement, "private-access"),
+ "allow-urn")
+ .stream().map(XML::getValue).toList();
+ return new LoadBalancerSettings(allowedUrnElements);
}
private static Map<String, String> getEnvironmentVariables(Element environmentVariables) {
@@ -946,12 +940,11 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private List<ApplicationContainer> createNodesFromNodeCount(ApplicationContainerCluster cluster, Element containerElement, Element nodesElement, ConfigModelContext context) {
NodesSpecification nodesSpecification = NodesSpecification.from(new ModelElement(nodesElement), context);
- ClusterSpec.Id clusterId = ClusterSpec.Id.from(cluster.name());
- ZoneEndpoint zoneEndpoint = zoneEndpoint(context, clusterId);
+ LoadBalancerSettings loadBalancerSettings = loadBalancerSettings(XML.getChild(containerElement, "load-balancer"));
Map<HostResource, ClusterMembership> hosts = nodesSpecification.provision(cluster.getRoot().hostSystem(),
ClusterSpec.Type.container,
- clusterId,
- zoneEndpoint,
+ ClusterSpec.Id.from(cluster.getName()),
+ loadBalancerSettings,
log,
getZooKeeper(containerElement) != null);
return createNodesFromHosts(hosts, cluster, context.getDeployState());
diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc
index 81455084ad2..933ec528c42 100644
--- a/config-model/src/main/resources/schema/containercluster.rnc
+++ b/config-model/src/main/resources/schema/containercluster.rnc
@@ -6,7 +6,8 @@ ContainerCluster = element container {
ContainerServices &
DocumentBinding* &
NodesOfContainerCluster? &
- ClientAuthorize?
+ ClientAuthorize? &
+ LoadBalancer?
}
ContainerServices =
@@ -311,6 +312,16 @@ NodesOfContainerCluster = element nodes {
)
}
+LoadBalancer = element load-balancer {
+ element private-access {
+ element allow-urn {
+ xsd:string
+ }*
+ }?
+}
+
+
+
#DOCUMENT BINDINGS:
DocumentBinding = element document {
diff --git a/config-model/src/main/resources/schema/deployment.rnc b/config-model/src/main/resources/schema/deployment.rnc
index d63b8885a57..444f66a92ab 100644
--- a/config-model/src/main/resources/schema/deployment.rnc
+++ b/config-model/src/main/resources/schema/deployment.rnc
@@ -150,21 +150,12 @@ EndpointInstance = element instance {
text
}
-AllowedUrn = element allow {
- attribute with { xsd:string } &
- attribute arn { xsd:string }? &
- attribute project { xsd:string }?
-}
-
Endpoint = element endpoint {
attribute id { xsd:string }? &
attribute container-id { xsd:string } &
attribute region { xsd:string }? &
- attribute type { xsd:string }? &
- attribute enabled { xsd:boolean }? &
EndpointRegion* &
- EndpointInstance* &
- AllowedUrn*
+ EndpointInstance*
}
Endpoints = element endpoints {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
index f0c39ecc920..addf4dffde2 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
@@ -22,9 +22,6 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Zone;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
import com.yahoo.config.provisioning.FlavorsConfig;
import com.yahoo.container.ComponentsConfig;
import com.yahoo.container.QrConfig;
@@ -60,6 +57,7 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;
+import java.util.stream.Collectors;
import static com.yahoo.config.model.test.TestUtil.joinLines;
import static com.yahoo.test.LinePatternMatcher.containsLineWithPattern;
@@ -181,63 +179,6 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
}
@Test
- void container_cluster_with_invalid_name_throws_exception_when_hosted() throws IOException, SAXException {
- String servicesXml = """
- <services version='1.0'>
- <container id='C-1' version='1.0'>
- <nodes count='1' />
- </container>
- </services>
- """;
-
- assertEquals("container cluster name must match '([a-z0-9]|[a-z0-9][a-z0-9_-]{0,61}[a-z0-9])', but got: 'C-1'",
- assertThrows(IllegalArgumentException.class,
- () ->
- new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
- .modelHostProvisioner(new InMemoryProvisioner(4, false))
- .applicationPackage(new MockApplicationPackage.Builder().withServices(servicesXml).build())
- .properties(new TestProperties().setHostedVespa(true))
- .build()))
- .getMessage());
-
- new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
- .modelHostProvisioner(new InMemoryProvisioner(4, false))
- .applicationPackage(new MockApplicationPackage.Builder().withServices(servicesXml).build())
- .properties(new TestProperties().setHostedVespa(false))
- .build());
- }
-
- @Test
- void two_clusters_with_clashing_cluster_names_throws_exception_when_hosted() throws IOException, SAXException {
- String servicesXml = """
- <services version='1.0'>
- <container id='c-1' version='1.0'>
- <nodes count='1' />
- </container>
- <container id='c_1' version='1.0'>
- <nodes count='1' />
- </container>
- </services>
- """;
-
- assertEquals("container clusters 'c-1' and 'c_1' have clashing endpoint names, when '_' is replaced with '-' to form valid domain names",
- assertThrows(IllegalArgumentException.class,
- () ->
- new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
- .modelHostProvisioner(new InMemoryProvisioner(4, false))
- .applicationPackage(new MockApplicationPackage.Builder().withServices(servicesXml).build())
- .properties(new TestProperties().setHostedVespa(true))
- .build()))
- .getMessage());
-
- new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
- .modelHostProvisioner(new InMemoryProvisioner(4, false))
- .applicationPackage(new MockApplicationPackage.Builder().withServices(servicesXml).build())
- .properties(new TestProperties().setHostedVespa(false))
- .build());
- }
-
- @Test
void two_clusters_without_explicit_port_throws_exception() {
Element cluster1Elem = DomBuilderTest.parse(
"<container id='cluster1' version='1.0'>",
@@ -257,96 +198,53 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
@Test
void load_balancers_can_be_set() throws IOException, SAXException {
- // No endpoints
- verifyAllowedUrns("", Environment.prod, "eu", ZoneEndpoint.defaultEndpoint);
+ // No load-balancer or nodes elements
+ verifyAllowedUrns("");
- // No non-default settings
- verifyAllowedUrns("""
- <endpoint type='zone' container-id='default' />
- """,
- Environment.prod,
- "eu",
- ZoneEndpoint.defaultEndpoint);
+ // No load-balancer element
+ verifyAllowedUrns("<nodes count='2' />");
- // No allowed urns
+ // No nodes element
verifyAllowedUrns("""
- <endpoint type='private' container-id='default' />
- """,
- Environment.prod,
- "eu",
- new ZoneEndpoint(true, true, List.of()));
-
- // Various settings
- verifyAllowedUrns("""
- <endpoint type='zone' container-id='default' enabled='false' />
- <endpoint type='private' container-id='default'>
- <region>eu</region>
- <allow with='aws-private-link' arn='barn' />
- <allow with='gcp-service-connect' project='nine' />
- </endpoint>
- """,
- Environment.prod,
- "eu",
- new ZoneEndpoint(false, true, List.of(new AllowedUrn(AccessType.awsPrivateLink, "barn"),
- new AllowedUrn(AccessType.gcpServiceConnect, "nine"))));
-
- // Various settings, but wrong region
+ <load-balancer>
+ <private-access>
+ <allow-urn>foo</allow-urn>
+ <allow-urn>bar</allow-urn>
+ </private-access>
+ </load-balancer>
+ """);
+
+ // Both load-balancer and nodes
verifyAllowedUrns("""
- <endpoint type='zone' container-id='default' enabled='false' />
- <endpoint type='private' container-id='default'>
- <region>eu</region>
- <allow with='aws-private-link' arn='barn' />
- <allow with='gcp-service-connect' project='nine' />
- </endpoint>
+ <load-balancer>
+ <private-access>
+ <allow-urn>foo</allow-urn>
+ <allow-urn>bar</allow-urn>
+ </private-access>
+ </load-balancer>
+ <nodes count='2' />
""",
- Environment.prod,
- "us",
- ZoneEndpoint.defaultEndpoint);
-
- // Various settings, but wrong environment
- verifyAllowedUrns("""
- <endpoint type='zone' container-id='default' enabled='false' />
- <endpoint type='private' container-id='default'>
- <region>eu</region>
- <allow with='aws-private-link' arn='barn' />
- <allow with='gcp-service-connect' project='nine' />
- </endpoint>
- """,
- Environment.dev,
- "eu",
- ZoneEndpoint.defaultEndpoint);
+ "foo", "bar");
}
- private void verifyAllowedUrns(String endpointsTag, Environment environment, String region, ZoneEndpoint expected) throws IOException, SAXException {
+ private void verifyAllowedUrns(String containerXml, String... expectedAllowedUrns) throws IOException, SAXException {
String servicesXml = """
<container id='default' version='1.0'>
- <nodes count='2' />
+ %s
</container>
- """;
- String deploymentXml = """
- <deployment version='1.0'>
- <prod>
- <region>eu</region>
- </prod>
- <endpoints>
- %s
- </endpoints>
- </deployment>
- """.formatted(endpointsTag);
- ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).withDeploymentSpec(deploymentXml).build();
+ """.formatted(containerXml);
+ ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).build();
InMemoryProvisioner provisioner = new InMemoryProvisioner(true, false, "host1.yahoo.com", "host2.yahoo.com");
VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
.modelHostProvisioner(provisioner)
.provisioned(provisioner.startProvisionedRecording())
.applicationPackage(applicationPackage)
- .properties(new TestProperties().setMultitenant(true)
- .setHostedVespa(true)
- .setZone(new Zone(environment, RegionName.from(region))))
+ .properties(new TestProperties().setMultitenant(true).setHostedVespa(true))
.build());
assertEquals(2, model.hostSystem().getHosts().size());
assertEquals(1, provisioner.provisionedClusters().size());
- assertEquals(expected,
- provisioner.provisionedClusters().iterator().next().zoneEndpoint());
+ assertEquals(List.of(expectedAllowedUrns),
+ provisioner.provisionedClusters().iterator().next().loadBalancerSettings().allowedUrns());
}
@Test
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
index 9e8388b6442..213166447ca 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
@@ -20,7 +20,7 @@ public class ClusterMembership {
private final String stringValue;
private ClusterMembership(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo,
- ZoneEndpoint zoneEndpoint) {
+ LoadBalancerSettings loadBalancerSettings) {
String[] components = stringValue.split("/");
if (components.length < 4)
throw new RuntimeException("Could not parse '" + stringValue + "' to a cluster membership. " +
@@ -49,7 +49,7 @@ public class ClusterMembership {
.exclusive(exclusive)
.combinedId(combinedId.map(ClusterSpec.Id::from))
.dockerImageRepository(dockerImageRepo)
- .loadBalancerSettings(zoneEndpoint)
+ .loadBalancerSettings(loadBalancerSettings)
.stateful(stateful)
.build();
this.index = Integer.parseInt(components[3]);
@@ -125,12 +125,12 @@ public class ClusterMembership {
public String toString() { return stringValue(); }
public static ClusterMembership from(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo) {
- return from(stringValue, vespaVersion, dockerImageRepo, ZoneEndpoint.defaultEndpoint);
+ return from(stringValue, vespaVersion, dockerImageRepo, LoadBalancerSettings.empty);
}
public static ClusterMembership from(String stringValue, Version vespaVersion, Optional<DockerImage> dockerImageRepo,
- ZoneEndpoint zoneEndpoint) {
- return new ClusterMembership(stringValue, vespaVersion, dockerImageRepo, zoneEndpoint);
+ LoadBalancerSettings loadBalancerSettings) {
+ return new ClusterMembership(stringValue, vespaVersion, dockerImageRepo, loadBalancerSettings);
}
public static ClusterMembership from(ClusterSpec cluster, int index) {
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 196255a8342..153b305dc01 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -24,12 +24,12 @@ public final class ClusterSpec {
private final boolean exclusive;
private final Optional<Id> combinedId;
private final Optional<DockerImage> dockerImageRepo;
- private final ZoneEndpoint zoneEndpoint;
+ private final LoadBalancerSettings loadBalancerSettings;
private final boolean stateful;
private ClusterSpec(Type type, Id id, Optional<Group> groupId, Version vespaVersion, boolean exclusive,
Optional<Id> combinedId, Optional<DockerImage> dockerImageRepo,
- ZoneEndpoint zoneEndpoint, boolean stateful) {
+ LoadBalancerSettings loadBalancerSettings, boolean stateful) {
this.type = type;
this.id = id;
this.groupId = groupId;
@@ -47,7 +47,7 @@ public final class ClusterSpec {
if (type.isContent() && !stateful) {
throw new IllegalArgumentException("Cluster of type " + type + " must be stateful");
}
- this.zoneEndpoint = Objects.requireNonNull(zoneEndpoint);
+ this.loadBalancerSettings = Objects.requireNonNull(loadBalancerSettings);
this.stateful = stateful;
}
@@ -63,8 +63,8 @@ public final class ClusterSpec {
/** Returns the docker image (repository + vespa version) we want this cluster to run */
public Optional<String> dockerImage() { return dockerImageRepo.map(repo -> repo.withTag(vespaVersion).asString()); }
- /** Returns any additional zone endpoint settings for application container clusters. */
- public ZoneEndpoint zoneEndpoint() { return zoneEndpoint; }
+ /** Returns any additional load balancer settings for application container clusters. */
+ public LoadBalancerSettings loadBalancerSettings() { return loadBalancerSettings; }
/** Returns the version of Vespa that we want this cluster to run */
public Version vespaVersion() { return vespaVersion; }
@@ -87,15 +87,15 @@ public final class ClusterSpec {
public boolean isStateful() { return stateful; }
public ClusterSpec with(Optional<Group> newGroup) {
- return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
+ return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
}
public ClusterSpec withExclusivity(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
}
public ClusterSpec exclusive(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
}
/** Creates a ClusterSpec when requesting a cluster */
@@ -119,7 +119,7 @@ public final class ClusterSpec {
private Version vespaVersion;
private boolean exclusive = false;
private Optional<Id> combinedId = Optional.empty();
- private ZoneEndpoint zoneEndpoint = ZoneEndpoint.defaultEndpoint;
+ private LoadBalancerSettings loadBalancerSettings = LoadBalancerSettings.empty;
private boolean stateful;
private Builder(Type type, Id id, boolean specification) {
@@ -135,7 +135,7 @@ public final class ClusterSpec {
if (vespaVersion == null) throw new IllegalArgumentException("vespaVersion is required to be set when creating a ClusterSpec with specification()");
} else
if (groupId.isPresent()) throw new IllegalArgumentException("groupId is not allowed to be set when creating a ClusterSpec with request()");
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
}
public Builder group(Group groupId) {
@@ -168,8 +168,8 @@ public final class ClusterSpec {
return this;
}
- public Builder loadBalancerSettings(ZoneEndpoint zoneEndpoint) {
- this.zoneEndpoint = zoneEndpoint;
+ public Builder loadBalancerSettings(LoadBalancerSettings loadBalancerSettings) {
+ this.loadBalancerSettings = loadBalancerSettings;
return this;
}
@@ -198,12 +198,12 @@ public final class ClusterSpec {
vespaVersion.equals(that.vespaVersion) &&
combinedId.equals(that.combinedId) &&
dockerImageRepo.equals(that.dockerImageRepo) &&
- zoneEndpoint.equals(that.zoneEndpoint);
+ loadBalancerSettings.equals(that.loadBalancerSettings);
}
@Override
public int hashCode() {
- return Objects.hash(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, zoneEndpoint, stateful);
+ return Objects.hash(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, loadBalancerSettings, stateful);
}
/**
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java b/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java
new file mode 100644
index 00000000000..723de25fa87
--- /dev/null
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/LoadBalancerSettings.java
@@ -0,0 +1,20 @@
+package com.yahoo.config.provision;
+
+import java.util.List;
+
+/**
+ * Settings for a load balancer provisioned for an application container cluster.
+ *
+ * @author jonmv
+ */
+public record LoadBalancerSettings(List<String> allowedUrns) {
+
+ public static final LoadBalancerSettings empty = new LoadBalancerSettings(List.of());
+
+ public LoadBalancerSettings(List<String> allowedUrns) {
+ this.allowedUrns = List.copyOf(allowedUrns);
+ }
+
+ public boolean isEmpty() { return allowedUrns.isEmpty(); }
+
+}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java
deleted file mode 100644
index 10e22f8df06..00000000000
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ZoneEndpoint.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.yahoo.config.provision;
-
-import ai.vespa.validation.Validation;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Settings for a zone endpoint of a deployment.
- *
- * TODO: Fix isEmpty
- * Inline empty and constructor
- *
- * @author jonmv
- */
-public class ZoneEndpoint {
-
- public static final ZoneEndpoint defaultEndpoint = new ZoneEndpoint(true, false, List.of());
-
- private final boolean isPublicEndpoint;
- private final boolean isPrivateEndpoint;
- private final List<AllowedUrn> allowedUrns;
-
- public ZoneEndpoint(List<String> allowedUrns) {
- this(true, true, allowedUrns.stream().map(arn -> new AllowedUrn(AccessType.awsPrivateLink, arn)).toList());
- }
-
- public ZoneEndpoint(boolean isPublicEndpoint, boolean isPrivateEndpoint, List<AllowedUrn> allowedUrns) {
- if ( ! allowedUrns.isEmpty() && ! isPrivateEndpoint)
- throw new IllegalArgumentException("cannot list allowed urns, without also enabling private visibility");
- this.isPublicEndpoint = isPublicEndpoint;
- this.isPrivateEndpoint = isPrivateEndpoint;
- this.allowedUrns = List.copyOf(allowedUrns);
- }
-
- /** Whether this has an endpoint which is visible from the public internet. */
- public boolean isPublicEndpoint() {
- return isPublicEndpoint;
- }
-
- /** Whether this has an endpoint which is visible through private DNS of the cloud. */
- public boolean isPrivateEndpoint() {
- return isPrivateEndpoint;
- }
-
- /** List of allowed URNs, for specified private access types. */
- public List<AllowedUrn> allowedUrns() {
- return allowedUrns;
- }
-
- /** List of URNs for the given access type. */
- public List<String> allowedUrnsWith(AccessType type) {
- return allowedUrns.stream().filter(urn -> urn.type == type).map(AllowedUrn::urn).toList();
- }
-
- public boolean isDefault() {
- return equals(defaultEndpoint);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ZoneEndpoint that = (ZoneEndpoint) o;
- return isPublicEndpoint == that.isPublicEndpoint && isPrivateEndpoint == that.isPrivateEndpoint && allowedUrns.equals(that.allowedUrns);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(isPublicEndpoint, isPrivateEndpoint, allowedUrns);
- }
-
- @Override
- public String toString() {
- return "ZoneEndpoint{" +
- "isPublicEndpoint=" + isPublicEndpoint +
- ", isPrivateEndpoint=" + isPrivateEndpoint +
- ", allowedUrns=" + allowedUrns +
- '}';
- }
-
- public enum AccessType {
- awsPrivateLink,
- gcpServiceConnect,
- }
-
- /** A URN allowed to access this (private) endpoint, through a {@link AccessType} method. */
- public static class AllowedUrn {
-
- private final AccessType type;
- private final String urn;
-
- public AllowedUrn(AccessType type, String urn) {
- this.type = Objects.requireNonNull(type);
- this.urn = Validation.requireNonBlank(urn, "URN");
- }
-
- /** Type of private connection. */
- public AccessType type() {
- return type;
- }
-
- /** URN allowed to access this private endpoint. */
- public String urn() {
- return urn;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- AllowedUrn that = (AllowedUrn) o;
- return type == that.type && urn.equals(that.urn);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(type, urn);
- }
-
- @Override
- public String toString() {
- return "'" + urn + "' through '" +
- switch (type) {
- case awsPrivateLink -> "aws-private-link";
- case gcpServiceConnect -> "gcp-service-connect";
- } + "'";
- }
-
- }
-
-}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
index 64e8a7feb94..01bb0ca45ff 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
@@ -6,10 +6,8 @@ import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeResources;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
@@ -42,12 +40,8 @@ public class AllocatedHostsSerializer {
private static final String hostSpecKey = "hostSpec";
private static final String hostSpecHostNameKey = "hostName";
private static final String hostSpecMembershipKey = "membership";
- private static final String loadBalancerSettingsKey = "zoneEndpoint";
- private static final String publicField = "public";
- private static final String privateField = "private";
- private static final String allowedUrnsField = "allowedUrns";
- private static final String accessTypeField = "type";
- private static final String urnField = "urn";
+ private static final String loadBalancerSettingsKey = "loadBalancerSettings";
+ private static final String allowedUrnsKey = "allowedUrns";
private static final String realResourcesKey = "realResources";
private static final String advertisedResourcesKey = "advertisedResources";
@@ -91,8 +85,9 @@ public class AllocatedHostsSerializer {
host.membership().ifPresent(membership -> {
object.setString(hostSpecMembershipKey, membership.stringValue());
object.setString(hostSpecVespaVersionKey, membership.cluster().vespaVersion().toFullString());
- if ( ! membership.cluster().zoneEndpoint().isDefault())
- toSlime(object.setObject(loadBalancerSettingsKey), membership.cluster().zoneEndpoint());
+ if ( ! membership.cluster().loadBalancerSettings().isEmpty())
+ membership.cluster().loadBalancerSettings().allowedUrns()
+ .forEach(object.setObject(loadBalancerSettingsKey).setArray(allowedUrnsKey)::addString);
membership.cluster().dockerImageRepo().ifPresent(repo -> object.setString(hostSpecDockerImageRepoKey, repo.untagged()));
});
toSlime(host.realResources(), object.setObject(realResourcesKey));
@@ -227,41 +222,13 @@ public class AllocatedHostsSerializer {
object.field(hostSpecDockerImageRepoKey).valid()
? Optional.of(DockerImage.fromString(object.field(hostSpecDockerImageRepoKey).asString()))
: Optional.empty(),
- zoneEndpoint(object.field(loadBalancerSettingsKey)));
+ object.field(loadBalancerSettingsKey).valid()
+ ? new LoadBalancerSettings(SlimeUtils.entriesStream(object.field(loadBalancerSettingsKey).field(allowedUrnsKey))
+ .map(Inspector::asString)
+ .toList())
+ : LoadBalancerSettings.empty);
}
- private static void toSlime(Cursor settingsObject, ZoneEndpoint settings) {
- settingsObject.setBool(publicField, settings.isPublicEndpoint());
- settingsObject.setBool(privateField, settings.isPrivateEndpoint());
- if (settings.isPrivateEndpoint()) {
- Cursor allowedUrnsArray = settingsObject.setArray(allowedUrnsField);
- for (AllowedUrn urn : settings.allowedUrns()) {
- Cursor urnObject = allowedUrnsArray.addObject();
- urnObject.setString(urnField, urn.urn());
- urnObject.setString(accessTypeField,
- switch (urn.type()) {
- case awsPrivateLink -> "awsPrivateLink";
- case gcpServiceConnect -> "gcpServiceConnect";
- });
- }
- }
- }
-
- private static ZoneEndpoint zoneEndpoint(Inspector settingsObject) {
- if ( ! settingsObject.valid()) return ZoneEndpoint.defaultEndpoint;
- return new ZoneEndpoint(settingsObject.field(publicField).asBool(),
- settingsObject.field(privateField).asBool(),
- SlimeUtils.entriesStream(settingsObject.field(allowedUrnsField))
- .map(urnObject -> new AllowedUrn(switch (urnObject.field(accessTypeField).asString()) {
- case "awsPrivateLink" -> AccessType.awsPrivateLink;
- case "gcpServiceConnect" -> AccessType.gcpServiceConnect;
- default -> throw new IllegalArgumentException("unknown service access type in '" + urnObject + "'");
- },
- urnObject.field(urnField).asString()))
- .toList());
- }
-
-
private static Optional<String> optionalString(Inspector inspector) {
if ( ! inspector.valid()) return Optional.empty();
return Optional.of(inspector.asString());
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
index 3404d7ed55e..bcb3b8cd4aa 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
@@ -6,9 +6,9 @@ import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NetworkPorts;
import com.yahoo.config.provision.NodeResources;
-import com.yahoo.config.provision.ZoneEndpoint;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -20,6 +20,7 @@ import java.util.Set;
import static com.yahoo.config.provision.serialization.AllocatedHostsSerializer.fromJson;
import static com.yahoo.config.provision.serialization.AllocatedHostsSerializer.toJson;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
/**
* @author bratseth
@@ -68,7 +69,7 @@ public class AllocatedHostsSerializerTest {
bigSlowDiskSpeedNode,
anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
- Optional.empty(), new ZoneEndpoint(List.of("burn"))),
+ Optional.empty(), new LoadBalancerSettings(List.of("burn"))),
Optional.empty(),
Optional.empty(),
Optional.empty()));
diff --git a/configserver/src/test/apps/hosted/services.xml b/configserver/src/test/apps/hosted/services.xml
index f1435d8cc4f..22bccee9f5a 100644
--- a/configserver/src/test/apps/hosted/services.xml
+++ b/configserver/src/test/apps/hosted/services.xml
@@ -15,6 +15,11 @@
</http>
<search/>
<nodes count='1'/>
+ <load-balancer>
+ <private-access>
+ <allow-urn>burn</allow-urn>
+ </private-access>
+ </load-balancer>
</container>
<content id="music" version="1.0">
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
index 26330f11d65..a4e26fbe7b3 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/LoadBalancer.java
@@ -5,7 +5,6 @@ import ai.vespa.http.DomainName;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
import java.util.List;
import java.util.Objects;
@@ -85,6 +84,6 @@ public class LoadBalancer {
unknown
}
- public record PrivateServiceInfo(String id, List<AllowedUrn> allowedUrns) { }
+ public record PrivateServiceInfo(String id, List<String> allowedUrns) { }
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index 2693fdcbd7c..4159b099387 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -946,7 +946,7 @@ public class ApplicationController {
// Either the user is member of the domain admin role, or is given the "launch" privilege on the service.
Optional<AthenzUser> athenzUser = getUser(deployer);
if (athenzUser.isPresent()) {
- // We only need to validate the root and instance in deployment.xml. Dev/perf entries are found at the instance level as well.
+ // We only need to validate the root and instance in deployment.xml. Not possible to add dev or perf tags to deployment.xml
var zone = zoneId.orElseThrow(() -> new IllegalArgumentException("Unable to evaluate access, no zone provided in deployment"));
var serviceToLaunch = instanceName
.flatMap(instance -> applicationPackage.deploymentSpec().instance(instance))
@@ -954,7 +954,7 @@ public class ApplicationController {
.or(() -> applicationPackage.deploymentSpec().athenzService())
.map(service -> new AthenzService(identityDomain.get(), service.value()));
- if (serviceToLaunch.isPresent()) {
+ if(serviceToLaunch.isPresent()) {
if (
! ((AthenzFacade) accessControl).canLaunch(athenzUser.get(), serviceToLaunch.get()) && // launch privilege
! ((AthenzFacade) accessControl).hasTenantAdminAccess(athenzUser.get(), identityDomain.get()) // tenant admin
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
index 842d99abe71..bce9d44f8c6 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
@@ -4,28 +4,26 @@ package com.yahoo.vespa.hosted.controller.application.pkg;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
-import com.yahoo.config.application.api.DeploymentSpec.DeclaredZone;
import com.yahoo.config.application.api.Endpoint;
import com.yahoo.config.application.api.Endpoint.Level;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.CloudName;
-import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.application.EndpointId;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -152,10 +150,10 @@ public class ApplicationPackageValidator {
/** Verify endpoint configuration of given application package */
private void validateEndpointChange(Application application, ApplicationPackage applicationPackage, Instant instant) {
- for (DeploymentInstanceSpec instance : applicationPackage.deploymentSpec().instances()) {
- validateGlobalEndpointChanges(application, instance.name(), applicationPackage, instant);
- validateZoneEndpointChanges(application, instance.name(), applicationPackage, instant);
- }
+ applicationPackage.deploymentSpec().instances().forEach(instance -> validateEndpointChange(application,
+ instance.name(),
+ applicationPackage,
+ instant));
}
/** Verify that compactable endpoint parts (instance name and endpoint ID) do not clash */
@@ -178,7 +176,7 @@ public class ApplicationPackageValidator {
}
/** Verify changes to endpoint configuration by comparing given application package to the existing one, if any */
- private void validateGlobalEndpointChanges(Application application, InstanceName instanceName, ApplicationPackage applicationPackage, Instant instant) {
+ private void validateEndpointChange(Application application, InstanceName instanceName, ApplicationPackage applicationPackage, Instant instant) {
var validationId = ValidationId.globalEndpointChange;
if (applicationPackage.validationOverrides().allows(validationId, instant)) return;
@@ -202,43 +200,6 @@ public class ApplicationPackageValidator {
". " + ValidationOverrides.toAllowMessage(validationId));
}
- /** Verify changes to endpoint configuration by comparing given application package to the existing one, if any */
- private void validateZoneEndpointChanges(Application application, InstanceName instance, ApplicationPackage applicationPackage, Instant now) {
- ValidationId validationId = ValidationId.zoneEndpointChange;
- if (applicationPackage.validationOverrides().allows(validationId, now)) return;;
-
- String prefix = validationId + ": application '" + application.id() +
- (instance.isDefault() ? "" : "." + instance.value()) + "' ";
- DeploymentInstanceSpec spec = applicationPackage.deploymentSpec().requireInstance(instance);
- for (DeclaredZone zone : spec.zones()) {
- if (zone.environment() == Environment.prod) {
- Map<ClusterSpec.Id, ZoneEndpoint> newEndpoints = spec.zoneEndpoints(ZoneId.from(zone.environment(), zone.region().get()));
- application.deploymentSpec().instance(instance) // If old spec has this instance ...
- .filter(oldSpec -> oldSpec.concerns(zone.environment(), zone.region())) // ... and deploys to this zone ...
- .map(oldSpec -> oldSpec.zoneEndpoints(ZoneId.from(zone.environment(), zone.region().get())))
- .ifPresent(oldEndpoints -> { // ... then we compare the endpoints present in both.
- oldEndpoints.forEach((cluster, oldEndpoint) -> {
- ZoneEndpoint newEndpoint = newEndpoints.getOrDefault(cluster, ZoneEndpoint.defaultEndpoint);
- if ( ! newEndpoint.allowedUrns().containsAll(oldEndpoint.allowedUrns()))
- throw new IllegalArgumentException(prefix + "allows access to cluster '" + cluster.value() +
- "' in '" + zone.region().get().value() + "' to " +
- oldEndpoint.allowedUrns().stream().map(AllowedUrn::toString).collect(joining(", ", "[", "]")) +
- ", but does not include all these in the new deployment spec. " +
- "Deploying with the new settings will allow access to " +
- (newEndpoint.allowedUrns().isEmpty() ? "no one" : newEndpoint.allowedUrns().stream().map(AllowedUrn::toString).collect(joining(", ", "[", "]"))));
- });
- newEndpoints.forEach((cluster, newEndpoint) -> {
- ZoneEndpoint oldEndpoint = oldEndpoints.getOrDefault(cluster, ZoneEndpoint.defaultEndpoint);
- if (oldEndpoint.isPublicEndpoint() && ! newEndpoint.isPublicEndpoint())
- throw new IllegalArgumentException(prefix + "has a public endpoint for cluster '" + cluster.value() +
- "' in '" + zone.region().get().value() + "', but the new deployment spec " +
- "disables this");
- });
- });
- }
- }
- }
-
/** Returns whether newEndpoints contains all destinations in endpoints */
private static boolean containsAllDestinationsOf(List<Endpoint> endpoints, List<Endpoint> newEndpoints) {
var containsAllRegions = true;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 73c64be3e47..674d71001e3 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -619,7 +619,7 @@ public class JobController {
submission.applicationPackage().deploymentSpec().majorVersion().ifPresent(explicitMajor -> {
if ( ! controller.readVersionStatus().isOnCurrentMajor(new Version(explicitMajor)))
controller.notificationsDb().setNotification(NotificationSource.from(id), Type.submission, Notification.Level.warning,
- "Vespa " + explicitMajor + " will soon reach end of life, upgrade to Vespa " + (explicitMajor + 1) + " now: " +
+ "Vespa " + explicitMajor + " will soon be end of life, upgrade to Vespa " + (explicitMajor + 1) + " now: " +
"https://cloud.vespa.ai/en/vespa" + (explicitMajor + 1) + "-release-notes.html"); // ∠( ᐛ 」∠)_
});
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 3f68be611eb..c9ad34b5082 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -23,7 +23,6 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.handler.metrics.JsonResponse;
@@ -1979,15 +1978,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
lbObject.setString("cluster", lb.cluster().value());
lb.service().ifPresent(service -> {
lbObject.setString("serviceId", service.id()); // Really the "serviceName", but this is what the user needs >_<
- Cursor urnsArray = lbObject.setArray("allowedUrns");
- for (AllowedUrn urn : service.allowedUrns()) {
- Cursor urnObject = urnsArray.addObject();
- urnObject.setString("type", switch (urn.type()) {
- case awsPrivateLink -> "aws-private-link";
- case gcpServiceConnect -> "gcp-service-connect";
- });
- urnObject.setString("urn", urn.urn());
- }
+ service.allowedUrns().forEach(lbObject.setArray("allowedUrns")::addString);
Cursor endpointsArray = lbObject.setArray("endpoints");
controller.serviceRegistry().vpcEndpointService()
.getConnections(new ClusterId(id, lb.cluster()),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
index db96c265363..95b81dffaed 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
@@ -1118,94 +1118,6 @@ public class ControllerTest {
}
@Test
- void testZoneEndpointChanges() {
- DeploymentContext app = tester.newDeploymentContext();
- // Set up app with default settings.
- app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- </deployment>"""));
-
- assertEquals("zone-endpoint-change: application 'tenant.application' has a public endpoint for cluster 'foo' in 'us-east-3', but the new deployment spec disables this",
- assertThrows(IllegalArgumentException.class,
- () -> app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- <endpoints>
- <endpoint type='zone' container-id='foo' enabled='false' />
- </endpoints>
- </deployment>""")))
- .getMessage());
-
- // Disabling endpoints is OK with override.
- app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- <endpoints>
- <endpoint type='zone' container-id='foo' enabled='false' />
- </endpoints>
- </deployment>""",
- ValidationId.zoneEndpointChange));
-
- // Enabling endpoints again is OK, as is adding a private endpoint with some URN.
- app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- <endpoints>
- <endpoint type='private' container-id='foo'>
- <allow with='aws-private-link' arn='yarn' />
- </endpoint>
- </endpoints>
- </deployment>""",
- ValidationId.zoneEndpointChange));
-
- // Changing URNs is guarded.
- assertEquals("zone-endpoint-change: application 'tenant.application' allows access to cluster 'foo' in 'us-east-3' to " +
- "['yarn' through 'aws-private-link'], but does not include all these in the new deployment spec. " +
- "Deploying with the new settings will allow access to ['yarn' through 'gcp-service-connect']",
- assertThrows(IllegalArgumentException.class,
- () -> app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- <endpoints>
- <endpoint type='private' container-id='foo'>
- <allow with='gcp-service-connect' project='yarn' />
- </endpoint>
- </endpoints>
- </deployment>""")))
- .getMessage());
-
- // Changing cluster, effectively removing old URNs, is also guarded.
- assertEquals("zone-endpoint-change: application 'tenant.application' allows access to cluster 'foo' in 'us-east-3' to " +
- "['yarn' through 'aws-private-link'], but does not include all these in the new deployment spec. " +
- "Deploying with the new settings will allow access to no one",
- assertThrows(IllegalArgumentException.class,
- () -> app.submit(ApplicationPackageBuilder.fromDeploymentXml("""
- <deployment>
- <prod>
- <region>us-east-3</region>
- </prod>
- <endpoints>
- <endpoint type='private' container-id='bar'>
- <allow with='aws-private-link' arn='yarn' />
- </endpoint>
- </endpoints>
- </deployment>""")))
- .getMessage());
- }
-
-
- @Test
void testReadableApplications() {
var db = new MockCuratorDb(tester.controller().system());
var tester = new DeploymentTester(new ControllerTester(db));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
index 6f859ff3d15..93b804805c3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
@@ -16,8 +16,6 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.flags.json.FlagData;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.ClusterMetrics;
@@ -419,7 +417,7 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
LoadBalancer.State.active,
Optional.of("dns-zone-1"),
Optional.empty(),
- Optional.of(new PrivateServiceInfo("service", List.of(new AllowedUrn(AccessType.awsPrivateLink, "arne")))))));
+ Optional.of(new PrivateServiceInfo("service", List.of("arne"))))));
}
Application application = applications.get(id);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index be405c7b876..d40485ff5c0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -701,7 +701,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/private-service", GET)
.userIdentity(USER_ID),
"""
- {"loadBalancers":[{"cluster":"default","serviceId":"service","allowedUrns":[{"type":"aws-private-link","urn":"arne"}],"endpoints":[{"endpointId":"endpoint-1","state":"available"}]}]}""");
+ {"loadBalancers":[{"cluster":"default","serviceId":"service","allowedUrns":["arne"],"endpoints":[{"endpointId":"endpoint-1","state":"available"}]}]}""");
// GET service/state/v1
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/service/storagenode/host.com/state/v1/?foo=bar", GET)
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 2856a38075b..33c9edf694d 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
@@ -4,7 +4,7 @@ package com.yahoo.vespa.hosted.provision.lb;
import ai.vespa.http.DomainName;
import com.google.common.collect.ImmutableSortedSet;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ZoneEndpoint;
+import com.yahoo.config.provision.LoadBalancerSettings;
import java.util.Objects;
import java.util.Optional;
@@ -24,12 +24,12 @@ public class LoadBalancerInstance {
private final Set<Integer> ports;
private final Set<String> networks;
private final Set<Real> reals;
- private final ZoneEndpoint settings;
+ private final LoadBalancerSettings settings;
private final Optional<PrivateServiceId> serviceId;
private final CloudAccount cloudAccount;
public LoadBalancerInstance(Optional<DomainName> hostname, Optional<String> ipAddress, Optional<DnsZone> dnsZone,
- Set<Integer> ports, Set<String> networks, Set<Real> reals, ZoneEndpoint settings,
+ Set<Integer> ports, Set<String> networks, Set<Real> reals, LoadBalancerSettings settings,
Optional<PrivateServiceId> serviceId, CloudAccount cloudAccount) {
this.hostname = Objects.requireNonNull(hostname, "hostname must be non-null");
this.ipAddress = Objects.requireNonNull(ipAddress, "ip must be non-null");
@@ -78,7 +78,7 @@ public class LoadBalancerInstance {
}
/** Static user-configured settings of this load balancer */
- public ZoneEndpoint settings() {
+ public LoadBalancerSettings settings() {
return settings;
}
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 c19aebcda6e..e0dd41f9008 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,8 +4,8 @@ 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 com.yahoo.config.provision.ZoneEndpoint;
import java.util.Collections;
import java.util.HashMap;
@@ -62,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().orElse(ZoneEndpoint.defaultEndpoint),
+ spec.settings().orElse(LoadBalancerSettings.empty),
spec.settings().map(__ -> PrivateServiceId.of("service")),
spec.cloudAccount());
instances.put(id, instance);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerSpec.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerSpec.java
index e0ef6739542..dca6d434330 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerSpec.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerSpec.java
@@ -5,7 +5,7 @@ import com.google.common.collect.ImmutableSortedSet;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.ZoneEndpoint;
+import com.yahoo.config.provision.LoadBalancerSettings;
import java.util.Objects;
import java.util.Optional;
@@ -21,11 +21,11 @@ public class LoadBalancerSpec {
private final ApplicationId application;
private final ClusterSpec.Id cluster;
private final Set<Real> reals;
- private final Optional<ZoneEndpoint> settings;
+ private final Optional<LoadBalancerSettings> settings;
private final CloudAccount cloudAccount;
public LoadBalancerSpec(ApplicationId application, ClusterSpec.Id cluster, Set<Real> reals,
- ZoneEndpoint settings, CloudAccount cloudAccount) {
+ LoadBalancerSettings settings, CloudAccount cloudAccount) {
this.application = Objects.requireNonNull(application);
this.cluster = Objects.requireNonNull(cluster);
this.reals = ImmutableSortedSet.copyOf(Objects.requireNonNull(reals));
@@ -49,7 +49,7 @@ public class LoadBalancerSpec {
}
/** Static user-configured settings for this load balancer. */
- public Optional<ZoneEndpoint> settings() {
+ public Optional<LoadBalancerSettings> settings() {
return settings;
}
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 5dc099460a4..c8fb1226b81 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
@@ -3,8 +3,8 @@ package com.yahoo.vespa.hosted.provision.lb;
import ai.vespa.http.DomainName;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.ZoneEndpoint;
import java.util.Objects;
import java.util.Optional;
@@ -29,15 +29,15 @@ public class SharedLoadBalancerService implements LoadBalancerService {
@Override
public LoadBalancerInstance create(LoadBalancerSpec spec, boolean force) {
- if (spec.settings().isPresent() && ! spec.settings().get().isDefault())
- throw new IllegalArgumentException("custom zone endpoint settings are not supported with " + getClass());
+ if (spec.settings().isPresent() && ! spec.settings().get().isEmpty())
+ throw new IllegalArgumentException("custom load balancer settings are not supported with " + getClass());
return new LoadBalancerInstance(Optional.of(DomainName.of(vipHostname)),
Optional.empty(),
Optional.empty(),
Set.of(4443),
Set.of(),
spec.reals(),
- spec.settings().orElse(ZoneEndpoint.defaultEndpoint),
+ spec.settings().orElse(LoadBalancerSettings.empty),
Optional.empty(),
spec.cloudAccount());
}
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 6bac1dab3dd..3d352f5596b 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
@@ -3,9 +3,7 @@ package com.yahoo.vespa.hosted.provision.persistence;
import ai.vespa.http.DomainName;
import com.yahoo.config.provision.CloudAccount;
-import com.yahoo.config.provision.ZoneEndpoint;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
-import com.yahoo.config.provision.ZoneEndpoint.AccessType;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Inspector;
@@ -54,11 +52,7 @@ public class LoadBalancerSerializer {
private static final String serviceIdField = "serviceId";
private static final String cloudAccountField = "cloudAccount";
private static final String settingsField = "settings";
- private static final String publicField = "public";
- private static final String privateField = "private";
private static final String allowedUrnsField = "allowedUrns";
- private static final String accessTypeField = "type";
- private static final String urnField = "urn";
public static byte[] toJson(LoadBalancer loadBalancer) {
Slime slime = new Slime();
@@ -83,13 +77,15 @@ public class LoadBalancerSerializer {
}));
loadBalancer.instance()
.map(LoadBalancerInstance::settings)
- .ifPresent(settings -> toSlime(root.setObject(settingsField), settings));
+ .filter(settings -> ! settings.isEmpty())
+ .ifPresent(settings -> settings.allowedUrns().forEach(root.setObject(settingsField)
+ .setArray(allowedUrnsField)::addString));
loadBalancer.instance()
.flatMap(LoadBalancerInstance::serviceId)
.ifPresent(serviceId -> root.setString(serviceIdField, serviceId.value()));
loadBalancer.instance()
.map(LoadBalancerInstance::cloudAccount)
- .filter(cloudAccount -> ! cloudAccount.isUnspecified())
+ .filter(cloudAccount -> !cloudAccount.isUnspecified())
.ifPresent(cloudAccount -> root.setString(cloudAccountField, cloudAccount.value()));
try {
return SlimeUtils.toJsonBytes(slime);
@@ -118,7 +114,7 @@ public class LoadBalancerSerializer {
Optional<DomainName> hostname = optionalString(object.field(hostnameField), Function.identity()).filter(s -> !s.isEmpty()).map(DomainName::of);
Optional<String> ipAddress = optionalString(object.field(lbIpAddressField), Function.identity()).filter(s -> !s.isEmpty());
Optional<DnsZone> dnsZone = optionalString(object.field(dnsZoneField), DnsZone::new);
- ZoneEndpoint settings = zoneEndpoint(object.field(settingsField));
+ LoadBalancerSettings settings = loadBalancerSettings(object.field(settingsField));
Optional<PrivateServiceId> serviceId = optionalString(object.field(serviceIdField), PrivateServiceId::of);
CloudAccount cloudAccount = optionalString(object.field(cloudAccountField), CloudAccount::from).orElse(CloudAccount.empty);
Optional<LoadBalancerInstance> instance = hostname.isEmpty() && ipAddress.isEmpty() ? Optional.empty() :
@@ -130,35 +126,11 @@ public class LoadBalancerSerializer {
Instant.ofEpochMilli(object.field(changedAtField).asLong()));
}
- private static void toSlime(Cursor settingsObject, ZoneEndpoint settings) {
- settingsObject.setBool(publicField, settings.isPublicEndpoint());
- settingsObject.setBool(privateField, settings.isPrivateEndpoint());
- if (settings.isPrivateEndpoint()) {
- Cursor allowedUrnsArray = settingsObject.setArray(allowedUrnsField);
- for (AllowedUrn urn : settings.allowedUrns()) {
- Cursor urnObject = allowedUrnsArray.addObject();
- urnObject.setString(urnField, urn.urn());
- urnObject.setString(accessTypeField,
- switch (urn.type()) {
- case awsPrivateLink -> "awsPrivateLink";
- case gcpServiceConnect -> "gcpServiceConnect";
- });
- }
- }
- }
-
- private static ZoneEndpoint zoneEndpoint(Inspector settingsObject) {
- if ( ! settingsObject.valid()) return ZoneEndpoint.defaultEndpoint;
- return new ZoneEndpoint(settingsObject.field(publicField).asBool(),
- settingsObject.field(privateField).asBool(),
- SlimeUtils.entriesStream(settingsObject.field(allowedUrnsField))
- .map(urnObject -> new AllowedUrn(switch (urnObject.field(accessTypeField).asString()) {
- case "awsPrivateLink" -> AccessType.awsPrivateLink;
- case "gcpServiceConnect" -> AccessType.gcpServiceConnect;
- default -> throw new IllegalArgumentException("unknown service access type in '" + urnObject + "'");
- },
- urnObject.field(urnField).asString()))
- .toList());
+ private static LoadBalancerSettings loadBalancerSettings(Inspector settingsObject) {
+ if ( ! settingsObject.valid()) return LoadBalancerSettings.empty;
+ return new LoadBalancerSettings(SlimeUtils.entriesStream(settingsObject.field(allowedUrnsField))
+ .map(Inspector::asString)
+ .toList());
}
private static <T> Optional<T> optionalValue(Inspector field, Function<Inspector, T> fieldMapper) {
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 92fdb1d2e52..3e8124d5309 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
@@ -7,9 +7,9 @@ import com.yahoo.config.provision.ApplicationTransaction;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.ZoneEndpoint;
import com.yahoo.config.provision.exception.LoadBalancerServiceException;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.flags.BooleanFlag;
@@ -108,13 +108,11 @@ 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) {
- Map<ClusterSpec.Id, ZoneEndpoint> activatingClusters = clusters.stream()
- // .collect(Collectors.toMap(ClusterSpec::id, ClusterSpec::zoneEndpoint));
- // TODO: this dies with combined clusters Ü
- .collect(groupingBy(LoadBalancerProvisioner::effectiveId,
- reducing(ZoneEndpoint.defaultEndpoint,
- ClusterSpec::zoneEndpoint,
- (o, n) -> o.isDefault() ? n : o)));
+ 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.containsKey(cluster.getKey()))
continue;
@@ -211,7 +209,7 @@ public class LoadBalancerProvisioner {
requireInstance(id, instance, cloudAccount);
}
- private void activate(ApplicationTransaction transaction, ClusterSpec.Id cluster, ZoneEndpoint settings, 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);
@@ -228,7 +226,7 @@ public class LoadBalancerProvisioner {
/** Provision or reconfigure a load balancer instance, if necessary */
private Optional<LoadBalancerInstance> provisionInstance(LoadBalancerId id, NodeList nodes,
Optional<LoadBalancer> currentLoadBalancer,
- ZoneEndpoint zoneEndpoint,
+ LoadBalancerSettings loadBalancerSettings,
CloudAccount cloudAccount) {
boolean shouldDeactivateRouting = deactivateRouting.with(FetchVector.Dimension.APPLICATION_ID,
id.application().serializedForm())
@@ -239,13 +237,13 @@ public class LoadBalancerProvisioner {
} else {
reals = realsOf(nodes);
}
- if (isUpToDate(currentLoadBalancer, reals, zoneEndpoint))
+ if (isUpToDate(currentLoadBalancer, reals, loadBalancerSettings))
return currentLoadBalancer.get().instance();
log.log(Level.INFO, () -> "Provisioning instance for " + id + ", targeting: " + reals);
try {
// Override settings at activation, otherwise keep existing ones.
- ZoneEndpoint settings = zoneEndpoint != null ? zoneEndpoint
- : currentLoadBalancer.flatMap(LoadBalancer::instance)
+ LoadBalancerSettings settings = loadBalancerSettings != null ? loadBalancerSettings
+ : currentLoadBalancer.flatMap(LoadBalancer::instance)
.map(LoadBalancerInstance::settings)
.orElse(null);
LoadBalancerInstance created = service.create(new LoadBalancerSpec(id.application(), id.cluster(), reals, settings, cloudAccount),
@@ -308,11 +306,11 @@ public class LoadBalancerProvisioner {
}
/** Returns whether load balancer has given reals, and settings if specified*/
- private static boolean isUpToDate(Optional<LoadBalancer> loadBalancer, Set<Real> reals, ZoneEndpoint zoneEndpoint) {
+ private static boolean isUpToDate(Optional<LoadBalancer> loadBalancer, Set<Real> reals, LoadBalancerSettings loadBalancerSettings) {
if (loadBalancer.isEmpty()) return false;
if (loadBalancer.get().instance().isEmpty()) return false;
return loadBalancer.get().instance().get().reals().equals(reals)
- && (zoneEndpoint == null || loadBalancer.get().instance().get().settings().equals(zoneEndpoint));
+ && (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/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
index 15a799c06d8..fdf69b60690 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LoadBalancersResponse.java
@@ -2,7 +2,6 @@
package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.ZoneEndpoint.AllowedUrn;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.restapi.SlimeJsonResponse;
import com.yahoo.slime.Cursor;
@@ -77,17 +76,8 @@ public class LoadBalancersResponse extends SlimeJsonResponse {
});
});
lb.instance().ifPresent(instance -> {
- if ( ! instance.settings().isDefault()) {
- Cursor urnsArray = lbObject.setObject("settings").setArray("allowedUrns");
- for (AllowedUrn urn : instance.settings().allowedUrns()) {
- Cursor urnObject = urnsArray.addObject();
- urnObject.setString("type", switch (urn.type()) {
- case awsPrivateLink -> "aws-private-link";
- case gcpServiceConnect -> "gcp-service-connect";
- });
- urnObject.setString("urn", urn.urn());
- }
- }
+ if ( ! instance.settings().isEmpty())
+ instance.settings().allowedUrns().forEach(lbObject.setObject("settings").setArray("allowedUrns")::addString);
instance.serviceId().ifPresent(serviceId -> lbObject.setString("serviceId", serviceId.value()));
});
lb.instance()
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 92ffe9828c3..91c8f803429 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
@@ -14,12 +14,12 @@ import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Zone;
-import com.yahoo.config.provision.ZoneEndpoint;
import com.yahoo.transaction.Mutex;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.curator.mock.MockCurator;
@@ -189,7 +189,7 @@ public class MockNodeRepository extends NodeRepository {
activate(provisioner.prepare(zoneApp, zoneCluster, Capacity.fromRequiredNodeType(NodeType.host), null), zoneApp, provisioner);
ApplicationId app1Id = ApplicationId.from(TenantName.from("tenant1"), ApplicationName.from("application1"), InstanceName.from("instance1"));
- ClusterSpec cluster1Id = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id1")).vespaVersion("6.42").loadBalancerSettings(new ZoneEndpoint(List.of("arne"))).build();
+ ClusterSpec cluster1Id = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id1")).vespaVersion("6.42").loadBalancerSettings(new LoadBalancerSettings(List.of("arne"))).build();
activate(provisioner.prepare(app1Id,
cluster1Id,
Capacity.from(new ClusterResources(2, 1, new NodeResources(2, 8, 50, 1)),
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerServiceTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerServiceTest.java
index a646d26ea29..92c7ba7fe27 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerServiceTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/lb/SharedLoadBalancerServiceTest.java
@@ -5,7 +5,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.ZoneEndpoint;
+import com.yahoo.config.provision.LoadBalancerSettings;
import org.junit.Test;
import java.util.Optional;
@@ -29,7 +29,7 @@ public class SharedLoadBalancerServiceTest {
@Test
public void test_create_lb() {
var lb = loadBalancerService.create(new LoadBalancerSpec(applicationId, clusterId, reals,
- ZoneEndpoint.defaultEndpoint, CloudAccount.empty),
+ LoadBalancerSettings.empty, CloudAccount.empty),
false);
assertEquals(Optional.of(HostName.of("vip.example.com")), lb.hostname());
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 dee895b02d2..d5722a59f3e 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
@@ -6,7 +6,7 @@ import com.google.common.collect.ImmutableSet;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.ZoneEndpoint;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.vespa.hosted.provision.lb.DnsZone;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId;
@@ -46,7 +46,7 @@ public class LoadBalancerSerializerTest {
new Real(DomainName.of("real-2"),
"127.0.0.2",
4080)),
- new ZoneEndpoint(List.of("123")),
+ new LoadBalancerSettings(List.of("123")),
Optional.of(PrivateServiceId.of("foo")),
CloudAccount.from("012345678912"))),
LoadBalancer.State.active,
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 3653e20d848..e32643860f5 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,9 +9,9 @@ import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.LoadBalancerSettings;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.ZoneEndpoint;
import com.yahoo.config.provision.exception.LoadBalancerServiceException;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.flags.InMemoryFlagSource;
@@ -215,7 +215,7 @@ public class LoadBalancerProvisionerTest {
public void provision_load_balancer_combined_cluster() {
Supplier<List<LoadBalancer>> lbs = () -> tester.nodeRepository().loadBalancers().list(app1).asList();
var combinedId = ClusterSpec.Id.from("container1");
- var nodes = prepare(app1, clusterRequest(ClusterSpec.Type.combined, ClusterSpec.Id.from("content1"), Optional.of(combinedId), ZoneEndpoint.defaultEndpoint));
+ var nodes = prepare(app1, clusterRequest(ClusterSpec.Type.combined, ClusterSpec.Id.from("content1"), Optional.of(combinedId), LoadBalancerSettings.empty));
assertEquals(1, lbs.get().size());
assertEquals("Prepare provisions load balancer with reserved nodes", 2, lbs.get().get(0).instance().get().reals().size());
tester.activate(app1, nodes);
@@ -320,10 +320,10 @@ 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(ZoneEndpoint.defaultEndpoint, loadBalancers.first().get().instance().get().settings());
+ assertEquals(LoadBalancerSettings.empty, loadBalancers.first().get().instance().get().settings());
// Next deployment contains new settings
- ZoneEndpoint settings = new ZoneEndpoint(List.of("alice", "bob"));
+ 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());
@@ -430,10 +430,10 @@ public class LoadBalancerProvisionerTest {
}
private static ClusterSpec clusterRequest(ClusterSpec.Type type, ClusterSpec.Id id) {
- return clusterRequest(type, id, Optional.empty(), ZoneEndpoint.defaultEndpoint);
+ return clusterRequest(type, id, Optional.empty(), LoadBalancerSettings.empty);
}
- private static ClusterSpec clusterRequest(ClusterSpec.Type type, ClusterSpec.Id id, Optional<ClusterSpec.Id> combinedId, ZoneEndpoint settings) {
+ private static ClusterSpec clusterRequest(ClusterSpec.Type type, ClusterSpec.Id id, Optional<ClusterSpec.Id> combinedId, LoadBalancerSettings settings) {
return ClusterSpec.request(type, id).vespaVersion("6.42").combinedId(combinedId).loadBalancerSettings(settings).build();
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
index 086df4d0c33..5143aa91f56 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
@@ -49,8 +49,8 @@ public class VirtualNodeProvisioningTest {
private static final NodeResources resources1 = new NodeResources(4, 8, 100, 1);
private static final NodeResources resources2 = new NodeResources(1, 4, 100, 1,
NodeResources.DiskSpeed.fast, NodeResources.StorageType.local);
- private static final ClusterSpec contentClusterSpec = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion("6.42").build();
- private static final ClusterSpec containerClusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-container")).vespaVersion("6.42").build();
+ private static final ClusterSpec contentClusterSpec = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion("6.42").build();
+ private static final ClusterSpec containerClusterSpec = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer")).vespaVersion("6.42").build();
private final ApplicationId applicationId = ProvisioningTester.applicationId("test");
@@ -242,7 +242,7 @@ public class VirtualNodeProvisioningTest {
Version wantedVespaVersion = Version.fromString("6.39");
int nodeCount = 7;
List<HostSpec> hosts = tester.prepare(application1,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
nodeCount, 1, resources2);
tester.activate(application1, new HashSet<>(hosts));
@@ -253,7 +253,7 @@ public class VirtualNodeProvisioningTest {
// Upgrade Vespa version on nodes
Version upgradedWantedVespaVersion = Version.fromString("6.40");
List<HostSpec> upgradedHosts = tester.prepare(application1,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion(upgradedWantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(upgradedWantedVespaVersion).build(),
nodeCount, 1, resources2);
tester.activate(application1, new HashSet<>(upgradedHosts));
NodeList upgradedNodes = tester.getNodes(application1, Node.State.active);
@@ -275,7 +275,7 @@ public class VirtualNodeProvisioningTest {
int nodeCount = 7;
try {
List<HostSpec> nodes = tester.prepare(application1,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
nodeCount, 1, resources2);
fail("Expected the allocation to fail due to parent hosts not being active yet");
} catch (NodeAllocationException expected) { }
@@ -285,7 +285,7 @@ public class VirtualNodeProvisioningTest {
// Try allocating tenants again
List<HostSpec> nodes = tester.prepare(application1,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
nodeCount, 1, resources2);
tester.activate(application1, new HashSet<>(nodes));
@@ -309,14 +309,14 @@ public class VirtualNodeProvisioningTest {
Version wantedVespaVersion = Version.fromString("6.39");
List<HostSpec> nodes = tester.prepare(application2_1,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
6, 1, resources);
assertHostSpecParentReservation(nodes, Optional.empty(), tester); // We do not get nodes on hosts reserved to tenant1
tester.activate(application2_1, nodes);
try {
tester.prepare(application2_2,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
5, 1, resources);
fail("Expected exception");
}
@@ -325,7 +325,7 @@ public class VirtualNodeProvisioningTest {
}
nodes = tester.prepare(application1_1,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
10, 1, resources);
assertHostSpecParentReservation(nodes, Optional.of(tenant1), tester);
tester.activate(application1_1, nodes);
@@ -346,14 +346,14 @@ public class VirtualNodeProvisioningTest {
try {
// No capacity for 'container' nodes
tester.prepare(applicationId,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
6, 1, resources);
fail("Expected to fail node allocation");
} catch (NodeAllocationException ignored) { }
// Same cluster, but content type is now 'content'
List<HostSpec> nodes = tester.prepare(applicationId,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion(wantedVespaVersion).build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion(wantedVespaVersion).build(),
6, 1, resources);
tester.activate(applicationId, nodes);
@@ -445,7 +445,7 @@ public class VirtualNodeProvisioningTest {
assertEquals("No room for 3 nodes as 2 of 4 hosts are exclusive",
"Could not satisfy request for 3 nodes with " +
"[vcpu: 1.0, memory: 4.0 Gb, disk 100.0 Gb, bandwidth: 1.0 Gbps, architecture: x86_64] " +
- "in tenant2.app2 container cluster 'my-container' 6.39: " +
+ "in tenant2.app2 container cluster 'myContainer' 6.39: " +
"Node allocation failure on group 0: " +
"Not enough suitable nodes available due to host exclusivity constraints",
e.getMessage());
@@ -465,14 +465,14 @@ public class VirtualNodeProvisioningTest {
tester.makeReadyChildren(1, resources2, "host2");
tester.prepare(application1,
- ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("my-content")).vespaVersion("6.42").build(),
+ ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("myContent")).vespaVersion("6.42").build(),
2, 1,
resources2.with(NodeResources.StorageType.remote));
}
catch (NodeAllocationException e) {
assertEquals("Could not satisfy request for 2 nodes with " +
"[vcpu: 1.0, memory: 4.0 Gb, disk 100.0 Gb, bandwidth: 1.0 Gbps, storage type: remote, architecture: x86_64] " +
- "in tenant.app1 content cluster 'my-content'" +
+ "in tenant.app1 content cluster 'myContent'" +
" 6.42: Node allocation failure on group 0",
e.getMessage());
}
@@ -672,7 +672,7 @@ public class VirtualNodeProvisioningTest {
private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, NodeResources resources, ProvisioningTester tester) {
Set<HostSpec> hosts = new HashSet<>(tester.prepare(application,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("my-container")).vespaVersion("6.39").exclusive(exclusive).build(),
+ ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer")).vespaVersion("6.39").exclusive(exclusive).build(),
Capacity.from(new ClusterResources(nodeCount, 1, resources), false, true)));
tester.activate(application, hosts);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/load-balancers.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/load-balancers.json
index becca98a913..bbccc72c7f9 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/load-balancers.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/load-balancers.json
@@ -30,12 +30,7 @@
}
],
"settings": {
- "allowedUrns": [
- {
- "type": "aws-private-link",
- "urn": "arne"
- }
- ]
+ "allowedUrns": [ "arne" ]
},
"serviceId": "service"
},
diff --git a/vespa-feed-client/src/test/java/ai/vespa/feed/client/impl/ApacheClusterTest.java b/vespa-feed-client/src/test/java/ai/vespa/feed/client/impl/ApacheClusterTest.java
index 30ed8dcfdd4..f45f7f9d246 100644
--- a/vespa-feed-client/src/test/java/ai/vespa/feed/client/impl/ApacheClusterTest.java
+++ b/vespa-feed-client/src/test/java/ai/vespa/feed/client/impl/ApacheClusterTest.java
@@ -48,9 +48,9 @@ class ApacheClusterTest {
Map.of("name1", () -> "value1",
"name2", () -> "value2"),
"content".getBytes(UTF_8),
- Duration.ofSeconds(10)),
+ Duration.ofSeconds(5)),
vessel);
- HttpResponse response = vessel.get(15, TimeUnit.SECONDS);
+ HttpResponse response = vessel.get(5, TimeUnit.SECONDS);
assertEquals("{}", new String(response.body(), UTF_8));
assertEquals(200, response.code());