aboutsummaryrefslogtreecommitdiffstats
path: root/config-model-api/src/main/java/com/yahoo/config/application
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-07-27 12:21:14 +0200
committerGitHub <noreply@github.com>2023-07-27 12:21:14 +0200
commit2921d5bc1358b094db2e131970c969dcad481502 (patch)
tree2ffff84602408dd610cc27b56bcca024ad33ccbf /config-model-api/src/main/java/com/yahoo/config/application
parent2b43a46817cc779dccedd82ea8460802367a448a (diff)
Revert "Remove global-service-id"
Diffstat (limited to 'config-model-api/src/main/java/com/yahoo/config/application')
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java21
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java10
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java29
3 files changed, 52 insertions, 8 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 4ca96453ad1..b6f934c8824 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
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.application.api;
+import ai.vespa.validation.Validation;
import com.yahoo.config.provision.AthenzService;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.CloudName;
@@ -57,6 +58,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
private final int maxRisk;
private final int maxIdleHours;
private final List<DeploymentSpec.ChangeBlocker> changeBlockers;
+ private final Optional<String> globalServiceId;
private final Optional<AthenzService> athenzService;
private final Map<CloudName, CloudAccount> cloudAccounts;
private final Optional<Duration> hostTTL;
@@ -74,6 +76,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
DeploymentSpec.UpgradeRollout upgradeRollout,
int minRisk, int maxRisk, int maxIdleHours,
List<DeploymentSpec.ChangeBlocker> changeBlockers,
+ Optional<String> globalServiceId,
Optional<AthenzService> athenzService,
Map<CloudName, CloudAccount> cloudAccounts,
Optional<Duration> hostTTL,
@@ -97,6 +100,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
this.maxRisk = require(maxRisk >= minRisk, maxRisk, "maximum risk cannot be less than minimum risk score");
this.maxIdleHours = requireInRange(maxIdleHours, "maximum idle hours", 0, 168);
this.changeBlockers = Objects.requireNonNull(changeBlockers);
+ this.globalServiceId = Objects.requireNonNull(globalServiceId);
this.athenzService = Objects.requireNonNull(athenzService);
this.cloudAccounts = Map.copyOf(cloudAccounts);
this.hostTTL = Objects.requireNonNull(hostTTL);
@@ -107,7 +111,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
this.zoneEndpoints = Collections.unmodifiableMap(zoneEndpointsCopy);
this.bcp = Objects.requireNonNull(bcp);
validateZones(new HashSet<>(), new HashSet<>(), this);
- validateEndpoints(this.endpoints);
+ validateEndpoints(globalServiceId, this.endpoints);
validateChangeBlockers(changeBlockers, now);
validateBcp(bcp);
hostTTL.filter(Duration::isNegative).ifPresent(ttl -> illegal("Host TTL cannot be negative"));
@@ -151,7 +155,11 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
}
/** Throw an IllegalArgumentException if an endpoint refers to a region that is not declared in 'prod' */
- private void validateEndpoints(List<Endpoint> endpoints) {
+ private void validateEndpoints(Optional<String> globalServiceId, List<Endpoint> endpoints) {
+ if (globalServiceId.isPresent() && ! endpoints.isEmpty()) {
+ throw new IllegalArgumentException("Providing both 'endpoints' and 'global-service-id'. Use only 'endpoints'.");
+ }
+
var regions = prodRegions();
for (var endpoint : endpoints){
for (var endpointRegion : endpoint.regions()) {
@@ -235,6 +243,9 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
/** Returns time windows where upgrades are disallowed for these instances */
public List<DeploymentSpec.ChangeBlocker> changeBlocker() { return changeBlockers; }
+ /** Returns the ID of the service to expose through global routing, if present */
+ public Optional<String> globalServiceId() { return globalServiceId; }
+
/** Returns whether the instances in this step can upgrade at the given instant */
public boolean canUpgradeAt(Instant instant) {
return changeBlockers.stream().filter(block -> block.blocksVersions())
@@ -312,7 +323,8 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DeploymentInstanceSpec other = (DeploymentInstanceSpec) o;
- return upgradePolicy == other.upgradePolicy &&
+ return globalServiceId.equals(other.globalServiceId) &&
+ upgradePolicy == other.upgradePolicy &&
revisionTarget == other.revisionTarget &&
upgradeRollout == other.upgradeRollout &&
changeBlockers.equals(other.changeBlockers) &&
@@ -327,7 +339,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
@Override
public int hashCode() {
- return Objects.hash(upgradePolicy, revisionTarget, upgradeRollout, changeBlockers, steps(), athenzService, notifications, endpoints, zoneEndpoints, bcp, tags);
+ return Objects.hash(globalServiceId, upgradePolicy, revisionTarget, upgradeRollout, changeBlockers, steps(), athenzService, notifications, endpoints, zoneEndpoints, bcp, tags);
}
int deployableHashCode() {
@@ -337,6 +349,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps {
toHash[i++] = name;
toHash[i++] = endpoints;
toHash[i++] = zoneEndpoints;
+ toHash[i++] = globalServiceId;
toHash[i++] = tags;
toHash[i++] = bcp;
toHash[i++] = cloudAccounts;
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 358744d40f7..797be652ebc 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
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.application.api;
+import ai.vespa.validation.Validation;
import com.yahoo.collections.Comparables;
import com.yahoo.config.application.api.xml.DeploymentSpecXmlReader;
import com.yahoo.config.provision.AthenzDomain;
@@ -433,16 +434,17 @@ public class DeploymentSpec {
private final Environment environment;
private final Optional<RegionName> region;
+ private final boolean active;
private final Optional<AthenzService> athenzService;
private final Optional<String> testerFlavor;
private final Map<CloudName, CloudAccount> cloudAccounts;
private final Optional<Duration> hostTTL;
public DeclaredZone(Environment environment) {
- this(environment, Optional.empty(), Optional.empty(), Optional.empty(), Map.of(), Optional.empty());
+ this(environment, Optional.empty(), false, Optional.empty(), Optional.empty(), Map.of(), Optional.empty());
}
- public DeclaredZone(Environment environment, Optional<RegionName> region,
+ public DeclaredZone(Environment environment, Optional<RegionName> region, boolean active,
Optional<AthenzService> athenzService, Optional<String> testerFlavor,
Map<CloudName, CloudAccount> cloudAccounts, Optional<Duration> hostTTL) {
if (environment != Environment.prod && region.isPresent())
@@ -452,6 +454,7 @@ public class DeploymentSpec {
hostTTL.filter(Duration::isNegative).ifPresent(ttl -> illegal("Host TTL cannot be negative"));
this.environment = Objects.requireNonNull(environment);
this.region = Objects.requireNonNull(region);
+ this.active = active;
this.athenzService = Objects.requireNonNull(athenzService);
this.testerFlavor = Objects.requireNonNull(testerFlavor);
this.cloudAccounts = Map.copyOf(cloudAccounts);
@@ -463,6 +466,9 @@ public class DeploymentSpec {
/** The region name, or empty if not declared */
public Optional<RegionName> region() { return region; }
+ /** Returns whether this zone should receive production traffic */
+ public boolean active() { return active; }
+
public Optional<String> testerFlavor() { return testerFlavor; }
Optional<AthenzService> athenzService() { return athenzService; }
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 4bfecabaf69..38562eefb03 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
@@ -93,6 +93,7 @@ public class DeploymentSpecXmlReader {
private static final String athenzDomainAttribute = "athenz-domain";
private static final String testerFlavorAttribute = "tester-flavor";
private static final String majorVersionAttribute = "major-version";
+ private static final String globalServiceIdAttribute = "global-service-id";
private static final String cloudAccountAttribute = "cloud-account";
private static final String hostTTLAttribute = "empty-host-ttl";
@@ -233,6 +234,7 @@ public class DeploymentSpecXmlReader {
upgradeRollout,
minRisk, maxRisk, maxIdleHours,
changeBlockers,
+ Optional.ofNullable(prodAttributes.get(globalServiceIdAttribute)),
athenzService,
cloudAccounts,
hostTTL,
@@ -266,6 +268,12 @@ public class DeploymentSpecXmlReader {
Optional<AthenzService> athenzService = mostSpecificAttribute(stepTag, athenzServiceAttribute).map(AthenzService::from);
Optional<String> testerFlavor = mostSpecificAttribute(stepTag, testerFlavorAttribute);
+ if (prodTag.equals(stepTag.getTagName())) {
+ readGlobalServiceId(stepTag).ifPresent(id -> prodAttributes.put(globalServiceIdAttribute, id));
+ } else {
+ if (readGlobalServiceId(stepTag).isPresent()) illegal("Attribute '" + globalServiceIdAttribute + "' is only valid on 'prod' tag");
+ }
+
switch (stepTag.getTagName()) {
case testTag:
if (Stream.iterate(stepTag, Objects::nonNull, Node::getParentNode)
@@ -273,7 +281,7 @@ public class DeploymentSpecXmlReader {
return List.of(new DeclaredTest(RegionName.from(XML.getValue(stepTag).trim()), readHostTTL(stepTag))); // A production test
}
case devTag, perfTag, stagingTag: // Intentional fallthrough from test tag.
- return List.of(new DeclaredZone(Environment.from(stepTag.getTagName()), Optional.empty(), athenzService, testerFlavor, readCloudAccounts(stepTag), readHostTTL(stepTag)));
+ return List.of(new DeclaredZone(Environment.from(stepTag.getTagName()), Optional.empty(), false, athenzService, testerFlavor, readCloudAccounts(stepTag), readHostTTL(stepTag)));
case prodTag: // regions, delay and parallel may be nested within, but we can flatten them
return XML.getChildren(stepTag).stream()
.flatMap(child -> readNonInstanceSteps(child, prodAttributes, stepTag, defaultBcp).stream())
@@ -682,7 +690,7 @@ public class DeploymentSpecXmlReader {
private DeclaredZone readDeclaredZone(Environment environment, Optional<AthenzService> athenzService,
Optional<String> testerFlavor, Element regionTag) {
return new DeclaredZone(environment, Optional.of(RegionName.from(XML.getValue(regionTag).trim())),
- athenzService, testerFlavor,
+ readActive(regionTag), athenzService, testerFlavor,
readCloudAccounts(regionTag), readHostTTL(regionTag));
}
@@ -706,6 +714,13 @@ public class DeploymentSpecXmlReader {
return mostSpecificAttribute(tag, hostTTLAttribute).map(s -> toDuration(s, "empty host TTL"));
}
+ private Optional<String> readGlobalServiceId(Element environmentTag) {
+ String globalServiceId = environmentTag.getAttribute(globalServiceIdAttribute);
+ if (globalServiceId.isEmpty()) return Optional.empty();
+ deprecate(environmentTag, List.of(globalServiceIdAttribute), 7, "See https://cloud.vespa.ai/en/reference/routing#deprecated-syntax");
+ return Optional.of(globalServiceId);
+ }
+
private List<DeploymentSpec.ChangeBlocker> readChangeBlockers(Element parent, Element globalBlockersParent) {
List<DeploymentSpec.ChangeBlocker> changeBlockers = new ArrayList<>();
if (globalBlockersParent != parent) {
@@ -784,6 +799,16 @@ public class DeploymentSpecXmlReader {
};
}
+ private boolean readActive(Element regionTag) {
+ String activeValue = regionTag.getAttribute("active");
+ if ("".equals(activeValue)) return true; // Default to active
+ deprecate(regionTag, List.of("active"), 7, "See https://cloud.vespa.ai/en/reference/routing#deprecated-syntax");
+ if ("true".equals(activeValue)) return true;
+ if ("false".equals(activeValue)) return false;
+ throw new IllegalArgumentException("Value of 'active' attribute in region tag must be 'true' or 'false' " +
+ "to control whether this region should receive traffic from the global endpoint of this application");
+ }
+
private void deprecate(Element element, List<String> attributes, int majorVersion, String message) {
deprecatedElements.add(new DeprecatedElement(majorVersion, element.getTagName(), attributes, message));
}