diff options
37 files changed, 237 insertions, 183 deletions
diff --git a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java index 3c4c99e0337..4f8d42e895b 100644 --- a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java +++ b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java @@ -34,7 +34,7 @@ public class FlagsHandlerTest { "id1", false, List.of("joe"), "2010-01-01", "2030-01-01", "desc1", "mod1"); private static final UnboundBooleanFlag FLAG2 = Flags.defineFeatureFlag( "id2", true, List.of("joe"), "2010-01-01", "2030-01-01", "desc2", "mod2", - FetchVector.Dimension.HOSTNAME, FetchVector.Dimension.APPLICATION_ID); + FetchVector.Dimension.HOSTNAME, FetchVector.Dimension.INSTANCE_ID); private final FlagsDb flagsDb = new FlagsDbImpl(new MockCurator()); private final FlagsHandler handler = new FlagsHandler(FlagsHandler.testContext(), flagsDb); @@ -111,7 +111,7 @@ public class FlagsHandlerTest { }, { "type": "blacklist", - "dimension": "application", + "dimension": "instance", "values": [ "app1", "app2" ] } ], @@ -127,7 +127,7 @@ public class FlagsHandlerTest { // GET on id2 should now return what was put verifySuccessfulRequest(Method.GET, "/data/" + FLAG2.id(), "", - "{\"id\":\"id2\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"hostname\",\"values\":[\"host1\",\"host2\"]},{\"type\":\"blacklist\",\"dimension\":\"application\",\"values\":[\"app1\",\"app2\"]}],\"value\":true}],\"attributes\":{\"zone\":\"zone1\"}}"); + "{\"id\":\"id2\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"hostname\",\"values\":[\"host1\",\"host2\"]},{\"type\":\"blacklist\",\"dimension\":\"instance\",\"values\":[\"app1\",\"app2\"]}],\"value\":true}],\"attributes\":{\"zone\":\"zone1\"}}"); // The list of flag data should return id1 and id2 verifySuccessfulRequest(Method.GET, "/data", @@ -153,7 +153,7 @@ public class FlagsHandlerTest { // Get all recursivelly displays all flag data verifySuccessfulRequest(Method.GET, "/data?recursive=true", "", - "{\"flags\":[{\"id\":\"id1\",\"rules\":[{\"value\":false}]},{\"id\":\"id2\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"hostname\",\"values\":[\"host1\",\"host2\"]},{\"type\":\"blacklist\",\"dimension\":\"application\",\"values\":[\"app1\",\"app2\"]}],\"value\":true}],\"attributes\":{\"zone\":\"zone1\"}}]}"); + "{\"flags\":[{\"id\":\"id1\",\"rules\":[{\"value\":false}]},{\"id\":\"id2\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"hostname\",\"values\":[\"host1\",\"host2\"]},{\"type\":\"blacklist\",\"dimension\":\"instance\",\"values\":[\"app1\",\"app2\"]}],\"value\":true}],\"attributes\":{\"zone\":\"zone1\"}}]}"); // Deleting both flags verifySuccessfulRequest(Method.DELETE, "/data/" + FLAG1.id(), "", ""); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java index 296e31ce801..693252da43a 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java @@ -50,7 +50,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import static com.yahoo.vespa.curator.Curator.CompletionWaiter; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static java.util.stream.Collectors.toSet; /** @@ -418,7 +418,7 @@ public class TenantApplications implements RequestHandler, HostValidator { if (vespaVersion.isEmpty()) return true; Version wantedVersion = applicationMapper.getForVersion(application, Optional.empty(), clock.instant()) .getModel().wantedNodeVersion(); - return VersionCompatibility.fromVersionList(incompatibleVersions.with(APPLICATION_ID, application.serializedForm()).value()) + return VersionCompatibility.fromVersionList(incompatibleVersions.with(INSTANCE_ID, application.serializedForm()).value()) .accept(vespaVersion.get(), wantedVersion); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index bab2e666d0a..142f98e13e3 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -296,7 +296,7 @@ public class ModelContextImpl implements ModelContext { private static <V> V flagValue(FlagSource source, ApplicationId appId, Version vespaVersion, UnboundFlag<? extends V, ?, ?> flag) { return flag.bindTo(source) - .with(FetchVector.Dimension.APPLICATION_ID, appId.serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm()) .with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString()) .with(FetchVector.Dimension.TENANT_ID, appId.tenant().value()) .boxedValue(); @@ -308,7 +308,7 @@ public class ModelContextImpl implements ModelContext { ClusterSpec.Type clusterType, UnboundFlag<? extends V, ?, ?> flag) { return flag.bindTo(source) - .with(FetchVector.Dimension.APPLICATION_ID, appId.serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm()) .with(FetchVector.Dimension.CLUSTER_TYPE, clusterType.name()) .with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString()) .boxedValue(); @@ -320,7 +320,7 @@ public class ModelContextImpl implements ModelContext { ClusterSpec.Id clusterId, UnboundFlag<? extends V, ?, ?> flag) { return flag.bindTo(source) - .with(FetchVector.Dimension.APPLICATION_ID, appId.serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm()) .with(FetchVector.Dimension.CLUSTER_ID, clusterId.value()) .with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString()) .boxedValue(); @@ -397,21 +397,21 @@ public class ModelContextImpl implements ModelContext { this.tenantSecretStores = tenantSecretStores; this.secretStore = secretStore; this.jvmGCOptionsFlag = PermanentFlags.JVM_GC_OPTIONS.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()); this.allowDisableMtls = PermanentFlags.ALLOW_DISABLE_MTLS.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); this.operatorCertificates = operatorCertificates; this.tlsCiphersOverride = PermanentFlags.TLS_CIPHERS_OVERRIDE.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); this.zoneDnsSuffixes = configserverConfig.zoneDnsSuffixes(); this.environmentVariables = PermanentFlags.ENVIRONMENT_VARIABLES.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); this.cloudAccount = cloudAccount; this.allowUserFilters = PermanentFlags.ALLOW_USER_FILTERS.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); this.endpointConnectionTtl = Duration.ofSeconds( PermanentFlags.ENDPOINT_CONNECTION_TTL.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value()); + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value()); this.dataplaneTokens = dataplaneTokens; } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java index 44a656a1579..3b57945b21d 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java @@ -82,7 +82,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import static com.yahoo.vespa.curator.Curator.CompletionWaiter; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static java.nio.file.Files.readAttributes; /** @@ -728,7 +728,7 @@ public class SessionRepository { } catch (IllegalArgumentException e) { if (configserverConfig.hostedVespa()) { UnboundStringFlag flag = PermanentFlags.APPLICATION_FILES_WITH_UNKNOWN_EXTENSION; - String value = flag.bindTo(flagSource).with(APPLICATION_ID, applicationId.serializedForm()).value(); + String value = flag.bindTo(flagSource).with(INSTANCE_ID, applicationId.serializedForm()).value(); switch (value) { case "FAIL" -> throw new InvalidApplicationException(e); case "LOG" -> deployLogger.ifPresent(logger -> logger.logApplicationPackage(Level.WARNING, e.getMessage())); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java index fa8a0ddcba1..856af9f4132 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.CloudAccount; @@ -190,7 +191,7 @@ public class SystemFlagsDataArchive { flagData.rules().forEach(rule -> rule.conditions().forEach(condition -> { int force_switch_expression_dummy = switch (condition.type()) { case RELATIONAL -> switch (condition.dimension()) { - case APPLICATION_ID, CLOUD, CLOUD_ACCOUNT, CLUSTER_ID, CLUSTER_TYPE, CONSOLE_USER_EMAIL, + case INSTANCE_ID, CLOUD, CLOUD_ACCOUNT, CLUSTER_ID, CLUSTER_TYPE, CONSOLE_USER_EMAIL, ENVIRONMENT, HOSTNAME, NODE_TYPE, SYSTEM, TENANT_ID, ZONE_ID -> throw new FlagValidationException(condition.type().toWire() + " " + DimensionHelper.toWire(condition.dimension()) + @@ -205,7 +206,7 @@ public class SystemFlagsDataArchive { }; case WHITELIST, BLACKLIST -> switch (condition.dimension()) { - case APPLICATION_ID -> validateConditionValues(condition, ApplicationId::fromSerializedForm); + case INSTANCE_ID -> validateConditionValues(condition, ApplicationId::fromSerializedForm); case CONSOLE_USER_EMAIL -> validateConditionValues(condition, email -> { if (!email.contains("@")) throw new FlagValidationException("Invalid email address: " + email); @@ -255,6 +256,17 @@ public class SystemFlagsDataArchive { final JsonNode root; try { root = mapper.readTree(fileContent); + // TODO (mortent): Remove this after completing migration of APPLICATION_ID dimension + // replace "application" with "instance" for all dimension fields + List<JsonNode> dimensionParents = root.findParents("dimension"); + for (JsonNode parentNode : dimensionParents) { + JsonNode dimension = parentNode.get("dimension"); + if (dimension.isTextual() && "application".equals(dimension.textValue())) { + ObjectNode parent = (ObjectNode) parentNode; + parent.remove("dimension"); + parent.put("dimension", "instance"); + } + } } catch (JsonProcessingException e) { throw new FlagValidationException("Invalid JSON: " + e.getMessage()); } diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java index 759f21579d4..373f8ba9de2 100644 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java @@ -245,7 +245,7 @@ public class SystemFlagsDataArchiveTest { "conditions": [ { "type": "whitelist", - "dimension": "application", + "dimension": "instance", "values": [ "f:o:o" ] } ], @@ -287,7 +287,7 @@ public class SystemFlagsDataArchiveTest { { "comment": "bar", "type": "whitelist", - "dimension": "application", + "dimension": "instance", "values": [ "f:o:o" ] } ], @@ -308,6 +308,7 @@ public class SystemFlagsDataArchiveTest { @Test void normalize_json_succeed_on_valid_values() { addFile(Condition.Type.WHITELIST, "application", "a:b:c"); + addFile(Condition.Type.WHITELIST, "instance", "a:b:c"); addFile(Condition.Type.WHITELIST, "cloud", "yahoo"); addFile(Condition.Type.WHITELIST, "cloud", "aws"); addFile(Condition.Type.WHITELIST, "cloud", "gcp"); @@ -361,7 +362,7 @@ public class SystemFlagsDataArchiveTest { @Test void normalize_json_fail_on_invalid_values() { - failAddFile(Condition.Type.WHITELIST, "application", "a.b.c", "In file flags/temporary/foo/default.json: Invalid application 'a.b.c' in whitelist condition: Application ids must be on the form tenant:application:instance, but was a.b.c"); + failAddFile(Condition.Type.WHITELIST, "application", "a.b.c", "In file flags/temporary/foo/default.json: Invalid instance 'a.b.c' in whitelist condition: Application ids must be on the form tenant:application:instance, but was a.b.c"); failAddFile(Condition.Type.WHITELIST, "cloud", "foo", "In file flags/temporary/foo/default.json: Unknown cloud: foo"); // cluster-id: any String is valid failAddFile(Condition.Type.WHITELIST, "cluster-type", "foo", "In file flags/temporary/foo/default.json: Invalid cluster-type 'foo' in whitelist condition: Illegal cluster type 'foo'"); 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 2f7b9f92316..90653d85aed 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 @@ -113,7 +113,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.active; import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.reserved; import static com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence.broken; @@ -676,7 +676,7 @@ public class ApplicationController { Optional<DockerImage> dockerImageRepo = Optional.ofNullable( dockerImageRepoFlag .with(FetchVector.Dimension.ZONE_ID, zone.value()) - .with(APPLICATION_ID, application.serializedForm()) + .with(INSTANCE_ID, application.serializedForm()) .value()) .filter(s -> !s.isBlank()) .map(DockerImage::fromString); @@ -962,7 +962,7 @@ public class ApplicationController { } public VersionCompatibility versionCompatibility(ApplicationId id) { - return VersionCompatibility.fromVersionList(incompatibleVersions.with(APPLICATION_ID, id.serializedForm()).value()); + return VersionCompatibility.fromVersionList(incompatibleVersions.with(INSTANCE_ID, id.serializedForm()).value()); } /** diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java index b50915253fb..3917fb23971 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java @@ -521,7 +521,7 @@ public class RoutingController { } public boolean generatedEndpointsEnabled(ApplicationId instance) { - return randomizedEndpoints.with(FetchVector.Dimension.APPLICATION_ID, instance.serializedForm()).value(); + return randomizedEndpoints.with(FetchVector.Dimension.INSTANCE_ID, instance.serializedForm()).value(); } private static void requireGeneratedEndpoints(GeneratedEndpointList generatedEndpoints, boolean declared) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificates.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificates.java index b16d09f974f..e01da00a27e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificates.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificates.java @@ -234,8 +234,8 @@ public class EndpointCertificates { .forEach(requiredNames::addAll); log.log(Level.INFO, String.format("Requesting new endpoint certificate from Cameo for application %s", deployment.applicationId().serializedForm())); - String algo = this.endpointCertificateAlgo.with(FetchVector.Dimension.APPLICATION_ID, deployment.applicationId().serializedForm()).value(); - boolean useAlternativeProvider = useAlternateCertProvider.with(FetchVector.Dimension.APPLICATION_ID, deployment.applicationId().serializedForm()).value(); + String algo = this.endpointCertificateAlgo.with(FetchVector.Dimension.INSTANCE_ID, deployment.applicationId().serializedForm()).value(); + boolean useAlternativeProvider = useAlternateCertProvider.with(FetchVector.Dimension.INSTANCE_ID, deployment.applicationId().serializedForm()).value(); String keyPrefix = deployment.applicationId().toFullString(); var t0 = Instant.now(); EndpointCertificate endpointCertificate = certificateProvider.requestCaSignedCertificate(keyPrefix, List.copyOf(requiredNames), currentCert, algo, useAlternativeProvider); 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 0773c95e1f2..1c417e750e3 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 @@ -155,7 +155,7 @@ public class JobController { } public boolean isDisabled(JobId id) { - return disabledZones.with(Dimension.APPLICATION_ID, id.application().serializedForm()).value().contains(id.type().zone().value()); + return disabledZones.with(Dimension.INSTANCE_ID, id.application().serializedForm()).value().contains(id.type().zone().value()); } /** Returns all entries currently logged for the given run. */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainer.java index e130e73cef1..c90fcb81c71 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EndpointCertificateMaintainer.java @@ -283,7 +283,7 @@ public class EndpointCertificateMaintainer extends ControllerMaintainer { assignedCertificates.stream() .filter(c -> c.instance().isPresent()) .filter(c -> c.certificate().randomizedId().isEmpty()) - .filter(c -> assignRandomizedId.with(FetchVector.Dimension.APPLICATION_ID, c.application().instance(c.instance().get()).serializedForm()).value()) + .filter(c -> assignRandomizedId.with(FetchVector.Dimension.INSTANCE_ID, c.application().instance(c.instance().get()).serializedForm()).value()) .filter(c -> controller().applications().getApplication(c.application()).isPresent()) // In case application has been deleted, but certificate is pending deletion .limit(assignRandomizedIdRate.value()) .forEach(c -> assignRandomizedId(c.application(), c.instance().get())); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/certificate/EndpointCertificatesHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/certificate/EndpointCertificatesHandler.java index 2835c36c320..912bd051a31 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/certificate/EndpointCertificatesHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/certificate/EndpointCertificatesHandler.java @@ -80,8 +80,8 @@ public class EndpointCertificatesHandler extends ThreadedHttpRequestHandler { AssignedCertificate assignedCertificate = curator.readAssignedCertificate(applicationId) .orElseThrow(() -> new RestApiException.NotFound("No certificate found for application " + applicationId.serializedForm())); - String algo = this.endpointCertificateAlgo.with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); - boolean useAlternativeProvider = useAlternateCertProvider.with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); + String algo = this.endpointCertificateAlgo.with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); + boolean useAlternativeProvider = useAlternateCertProvider.with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value(); String keyPrefix = applicationId.toFullString(); EndpointCertificate cert = endpointCertificateProvider.requestCaSignedCertificate( diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializer.java index 54a24360b5a..c3acf01a53e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializer.java @@ -20,7 +20,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -72,7 +71,7 @@ public class UserFlagsSerializer { // For the other dimensions, filter the values down to an allowed subset switch (condition.dimension()) { case TENANT_ID: return valueSubset(condition, tenant -> isOperator || authorizedForTenantNames.contains(TenantName.from(tenant))); - case APPLICATION_ID: return valueSubset(condition, appId -> isOperator || authorizedForTenantNames.stream().anyMatch(tenant -> appId.startsWith(tenant.value() + ":"))); + case INSTANCE_ID: return valueSubset(condition, appId -> isOperator || authorizedForTenantNames.stream().anyMatch(tenant -> appId.startsWith(tenant.value() + ":"))); default: throw new IllegalArgumentException("Dimension " + condition.dimension() + " is not supported for user flags"); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializerTest.java index ed7d02d0047..eb3f9daef53 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserFlagsSerializerTest.java @@ -26,7 +26,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL; import static com.yahoo.vespa.flags.FetchVector.Dimension.TENANT_ID; @@ -42,7 +42,7 @@ public class UserFlagsSerializerTest { try (Flags.Replacer ignored = Flags.clearFlagsForTesting()) { Flags.defineStringFlag("string-id", "default value", List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod", CONSOLE_USER_EMAIL); - Flags.defineIntFlag("int-id", 123, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod", CONSOLE_USER_EMAIL, TENANT_ID, APPLICATION_ID); + Flags.defineIntFlag("int-id", 123, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod", CONSOLE_USER_EMAIL, TENANT_ID, INSTANCE_ID); Flags.defineDoubleFlag("double-id", 3.14d, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"); Flags.defineListFlag("list-id", List.of("a"), String.class, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod", CONSOLE_USER_EMAIL); Flags.defineJacksonFlag("jackson-id", new ExampleJacksonClass(123, "abc"), ExampleJacksonClass.class, @@ -52,9 +52,9 @@ public class UserFlagsSerializerTest { flagData("string-id", rule("\"value1\"", condition(CONSOLE_USER_EMAIL, Condition.Type.WHITELIST, email1))), flagData("int-id", rule("456")), flagData("list-id", - rule("[\"value1\"]", condition(CONSOLE_USER_EMAIL, Condition.Type.WHITELIST, email1), condition(APPLICATION_ID, Condition.Type.BLACKLIST, "tenant1:video:default", "tenant1:video:default", "tenant2:music:default")), + rule("[\"value1\"]", condition(CONSOLE_USER_EMAIL, Condition.Type.WHITELIST, email1), condition(INSTANCE_ID, Condition.Type.BLACKLIST, "tenant1:video:default", "tenant1:video:default", "tenant2:music:default")), rule("[\"value2\"]", condition(CONSOLE_USER_EMAIL, Condition.Type.WHITELIST, email2)), - rule("[\"value1\",\"value3\"]", condition(APPLICATION_ID, Condition.Type.BLACKLIST, "tenant1:video:default", "tenant1:video:default", "tenant2:music:default"))), + rule("[\"value1\",\"value3\"]", condition(INSTANCE_ID, Condition.Type.BLACKLIST, "tenant1:video:default", "tenant1:video:default", "tenant2:music:default"))), flagData("jackson-id", rule("{\"integer\":456,\"string\":\"xyz\"}", condition(CONSOLE_USER_EMAIL, Condition.Type.WHITELIST, email1), condition(TENANT_ID, Condition.Type.WHITELIST, "tenant1", "tenant3"))) ).collect(Collectors.toMap(FlagData::id, fd -> fd)); @@ -63,7 +63,7 @@ public class UserFlagsSerializerTest { "{\"id\":\"int-id\",\"rules\":[{\"value\":456}]}," + // Default from DB "{\"id\":\"jackson-id\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"tenant\"}],\"value\":{\"integer\":456,\"string\":\"xyz\"}},{\"value\":{\"integer\":123,\"string\":\"abc\"}}]}," + // Resolved for email // Resolved for email, but conditions are empty since this user is not authorized for any tenants - "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"application\"}],\"value\":[\"value1\"]},{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"application\"}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + + "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"instance\"}],\"value\":[\"value1\"]},{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"instance\"}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + "{\"id\":\"string-id\",\"rules\":[{\"value\":\"value1\"}]}]}", // resolved for email flagData, Set.of(), false, email1); @@ -72,7 +72,7 @@ public class UserFlagsSerializerTest { "{\"id\":\"int-id\",\"rules\":[{\"value\":456}]}," + // Default from DB "{\"id\":\"jackson-id\",\"rules\":[{\"conditions\":[{\"type\":\"whitelist\",\"dimension\":\"tenant\",\"values\":[\"tenant1\"]}],\"value\":{\"integer\":456,\"string\":\"xyz\"}},{\"value\":{\"integer\":123,\"string\":\"abc\"}}]}," + // Resolved for email // Resolved for email, but conditions have filtered out tenant2 - "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"application\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\"]}],\"value\":[\"value1\"]},{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"application\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\"]}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + + "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"instance\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\"]}],\"value\":[\"value1\"]},{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"instance\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\"]}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + "{\"id\":\"string-id\",\"rules\":[{\"value\":\"value1\"}]}]}", // resolved for email flagData, Set.of("tenant1"), false, email1); @@ -81,7 +81,7 @@ public class UserFlagsSerializerTest { "{\"id\":\"int-id\",\"rules\":[{\"value\":456}]}," + // Default from DB "{\"id\":\"jackson-id\",\"rules\":[{\"value\":{\"integer\":123,\"string\":\"abc\"}}]}," + // Default from code, no DB values match // Includes last value from DB which is not conditioned on email and the default from code - "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"application\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\",\"tenant2:music:default\"]}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + + "{\"id\":\"list-id\",\"rules\":[{\"conditions\":[{\"type\":\"blacklist\",\"dimension\":\"instance\",\"values\":[\"tenant1:video:default\",\"tenant1:video:default\",\"tenant2:music:default\"]}],\"value\":[\"value1\",\"value3\"]},{\"value\":[\"a\"]}]}," + "{\"id\":\"string-id\",\"rules\":[{\"value\":\"default value\"}]}]}", // Default from code flagData, Set.of(), true, "operator@domain.tld"); } diff --git a/flags/src/main/java/com/yahoo/vespa/flags/FetchVector.java b/flags/src/main/java/com/yahoo/vespa/flags/FetchVector.java index 7af1661cf0c..b16d26a04a4 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/FetchVector.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/FetchVector.java @@ -22,9 +22,6 @@ public class FetchVector { * Note: If this enum is changed, you must also change {@link DimensionHelper}. */ public enum Dimension { - /** Value from ApplicationId::serializedForm of the form tenant:applicationName:instance. */ - APPLICATION_ID, - /** * Cloud from com.yahoo.config.provision.CloudName::value, e.g. yahoo, aws, gcp. * @@ -59,6 +56,9 @@ public class FetchVector { */ HOSTNAME, + /** Value from ApplicationId::serializedForm of the form tenant:applicationName:instance. */ + INSTANCE_ID, + /** Node type from com.yahoo.config.provision.NodeType::name, e.g. tenant, host, confighost, controller, etc. */ NODE_TYPE, diff --git a/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java b/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java index 1773a03feb1..451f45ec792 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java @@ -77,7 +77,7 @@ public class FlagDefinition { if (dimensions.contains(FetchVector.Dimension.CONSOLE_USER_EMAIL)) { Set<FetchVector.Dimension> disallowedCombinations = EnumSet.allOf(FetchVector.Dimension.class); disallowedCombinations.remove(FetchVector.Dimension.CONSOLE_USER_EMAIL); - disallowedCombinations.remove(FetchVector.Dimension.APPLICATION_ID); + disallowedCombinations.remove(FetchVector.Dimension.INSTANCE_ID); disallowedCombinations.remove(FetchVector.Dimension.TENANT_ID); disallowedCombinations.retainAll(dimensions); if (!disallowedCombinations.isEmpty()) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index de14d4e7b00..2e158f0f3ef 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -13,7 +13,7 @@ import java.util.Optional; import java.util.TreeMap; import java.util.function.Predicate; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLOUD_ACCOUNT; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_TYPE; @@ -35,7 +35,7 @@ import static com.yahoo.vespa.flags.FetchVector.Dimension.VESPA_VERSION; * an unbound flag to a flag source produces a (bound) flag, e.g. {@link BooleanFlag} and {@link StringFlag}.</li> * <li>If you would like your flag value to be dependent on e.g. the application ID, then 1. you should * declare this in the unbound flag definition in this file (referring to - * {@link FetchVector.Dimension#APPLICATION_ID}), and 2. specify the application ID when retrieving the value, e.g. + * {@link FetchVector.Dimension#INSTANCE_ID}), and 2. specify the application ID when retrieving the value, e.g. * {@link BooleanFlag#with(FetchVector.Dimension, String)}. See {@link FetchVector} for more info.</li> * </ol> * @@ -53,7 +53,7 @@ public class Flags { List.of("baldersheim"), "2020-12-02", "2023-12-31", "Default limit for when to apply termwise query evaluation", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag QUERY_DISPATCH_POLICY = defineStringFlag( "query-dispatch-policy", "adaptive", @@ -61,62 +61,62 @@ public class Flags { "Select query dispatch policy, valid values are adaptive, round-robin, best-of-random-2," + " latency-amortized-over-requests, latency-amortized-over-time", "Takes effect at redeployment (requires restart)", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag SUMMARY_DECODE_POLICY = defineStringFlag( "summary-decode-policy", "eager", List.of("baldersheim"), "2023-03-30", "2023-12-31", "Select summary decoding policy, valid values are eager and on-demand/ondemand.", "Takes effect at redeployment (requires restart)", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag FEED_SEQUENCER_TYPE = defineStringFlag( "feed-sequencer-type", "THROUGHPUT", List.of("baldersheim"), "2020-12-02", "2023-12-31", "Selects type of sequenced executor used for feeding in proton, valid values are LATENCY, ADAPTIVE, THROUGHPUT", "Takes effect at redeployment (requires restart)", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MAX_UNCOMMITTED_MEMORY = defineIntFlag( "max-uncommitted-memory", 130000, List.of("geirst, baldersheim"), "2021-10-21", "2023-12-31", "Max amount of memory holding updates to an attribute before we do a commit.", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag RESPONSE_SEQUENCER_TYPE = defineStringFlag( "response-sequencer-type", "ADAPTIVE", List.of("baldersheim"), "2020-12-02", "2023-12-31", "Selects type of sequenced executor used for mbus responses, valid values are LATENCY, ADAPTIVE, THROUGHPUT", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag RESPONSE_NUM_THREADS = defineIntFlag( "response-num-threads", 2, List.of("baldersheim"), "2020-12-02", "2023-12-31", "Number of threads used for mbus responses, default is 2, negative number = numcores/4", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE = defineFeatureFlag( "async-message-handling-on-schedule", false, List.of("baldersheim"), "2020-12-02", "2023-12-31", "Optionally deliver async messages in own thread", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag FEED_CONCURRENCY = defineDoubleFlag( "feed-concurrency", 0.5, List.of("baldersheim"), "2020-12-02", "2023-12-31", "How much concurrency should be allowed for feed", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag FEED_NICENESS = defineDoubleFlag( "feed-niceness", 0.0, List.of("baldersheim"), "2022-06-24", "2023-12-31", "How nice feeding shall be", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MBUS_JAVA_NUM_TARGETS = defineIntFlag( @@ -124,71 +124,71 @@ public class Flags { List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number of rpc targets per service", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MBUS_CPP_NUM_TARGETS = defineIntFlag( "mbus-cpp-num-targets", 2, List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number of rpc targets per service", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag RPC_NUM_TARGETS = defineIntFlag( "rpc-num-targets", 2, List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number of rpc targets per content node", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MBUS_JAVA_EVENTS_BEFORE_WAKEUP = defineIntFlag( "mbus-java-events-before-wakeup", 1, List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number write events before waking up transport thread", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MBUS_CPP_EVENTS_BEFORE_WAKEUP = defineIntFlag( "mbus-cpp-events-before-wakeup", 1, List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number write events before waking up transport thread", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag RPC_EVENTS_BEFORE_WAKEUP = defineIntFlag( "rpc-events-before-wakeup", 1, List.of("baldersheim"), "2022-07-05", "2023-12-31", "Number write events before waking up transport thread", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MBUS_NUM_NETWORK_THREADS = defineIntFlag( "mbus-num-network-threads", 1, List.of("baldersheim"), "2022-07-01", "2023-12-31", "Number of threads used for mbus network", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag SHARED_STRING_REPO_NO_RECLAIM = defineFeatureFlag( "shared-string-repo-no-reclaim", false, List.of("baldersheim"), "2022-06-14", "2023-12-31", "Controls whether we do track usage and reclaim unused enum values in shared string repo", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag CONTAINER_DUMP_HEAP_ON_SHUTDOWN_TIMEOUT = defineFeatureFlag( "container-dump-heap-on-shutdown-timeout", false, List.of("baldersheim"), "2021-09-25", "2023-12-31", "Will trigger a heap dump during if container shutdown times out", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag LOAD_CODE_AS_HUGEPAGES = defineFeatureFlag( "load-code-as-hugepages", false, List.of("baldersheim"), "2022-05-13", "2023-12-31", "Will try to map the code segment with huge (2M) pages", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag CONTAINER_SHUTDOWN_TIMEOUT = defineDoubleFlag( "container-shutdown-timeout", 50.0, List.of("baldersheim"), "2021-09-25", "2023-12-31", "Timeout for shutdown of a jdisc container", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); // TODO: Move to a permanent flag public static final UnboundListFlag<String> ALLOWED_ATHENZ_PROXY_IDENTITIES = defineListFlag( @@ -203,14 +203,14 @@ public class Flags { "Allows replicas in up to N content groups to not be activated " + "for query visibility if they are out of sync with a majority of other replicas", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag MIN_NODE_RATIO_PER_GROUP = defineDoubleFlag( "min-node-ratio-per-group", 0.0, List.of("geirst", "vekterli"), "2021-07-16", "2023-12-01", "Minimum ratio of nodes that have to be available (i.e. not Down) in any hierarchic content cluster group for the group to be Up", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag SYSTEM_MEMORY_HIGH = defineStringFlag( "system-memory-high", "", @@ -243,28 +243,28 @@ public class Flags { List.of("arnej"), "2021-11-15", "2023-12-31", "Use Vespa 8 types and formats for geographical positions", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MAX_COMPACT_BUFFERS = defineIntFlag( "max-compact-buffers", 1, List.of("baldersheim", "geirst", "toregge"), "2021-12-15", "2023-12-31", "Upper limit of buffers to compact in a data store at the same time for each reason (memory usage, address space usage)", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag ENABLE_PROXY_PROTOCOL_MIXED_MODE = defineFeatureFlag( "enable-proxy-protocol-mixed-mode", true, List.of("tokle"), "2022-05-09", "2023-10-01", "Enable or disable proxy protocol mixed mode", "Takes effect on redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag LOG_FILE_COMPRESSION_ALGORITHM = defineStringFlag( "log-file-compression-algorithm", "", List.of("arnej"), "2022-06-14", "2024-12-31", "Which algorithm to use for compressing log files. Valid values: empty string (default), gzip, zstd", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag SEPARATE_METRIC_CHECK_CONFIG = defineFeatureFlag( "separate-metric-check-config", false, @@ -278,7 +278,7 @@ public class Flags { List.of("bjorncs", "vekterli"), "2022-07-21", "2024-01-01", "Configure Vespa TLS capability enforcement mode", "Takes effect on restart of Docker container", - APPLICATION_ID,HOSTNAME,NODE_TYPE,TENANT_ID,VESPA_VERSION + INSTANCE_ID,HOSTNAME,NODE_TYPE,TENANT_ID,VESPA_VERSION ); public static final UnboundBooleanFlag ENABLE_OTELCOL = defineFeatureFlag( @@ -286,7 +286,7 @@ public class Flags { List.of("olaa"), "2022-09-23", "2023-12-01", "Whether an OpenTelemetry collector should be enabled", "Takes effect at next tick", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag CORE_ENCRYPTION_PUBLIC_KEY_ID = defineStringFlag( "core-encryption-public-key-id", "", @@ -300,7 +300,7 @@ public class Flags { List.of("arnej", "bjorncs"), "2023-02-28", "2024-01-10", "Enable global phase ranking", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag ENABLE_CROWDSTRIKE = defineFeatureFlag( "enable-crowdstrike", true, List.of("andreer"), "2023-04-13", "2023-10-14", @@ -311,7 +311,7 @@ public class Flags { "randomized-endpoint-names", false, List.of("andreer"), "2023-04-26", "2023-10-14", "Whether to use randomized endpoint names", "Takes effect on application deployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag ENABLE_THE_ONE_THAT_SHOULD_NOT_BE_NAMED = defineFeatureFlag( "enable-the-one-that-should-not-be-named", false, List.of("hmusum"), "2023-05-08", "2023-10-01", @@ -329,14 +329,14 @@ public class Flags { List.of("baldersheim"), "2023-06-29", "2023-12-31", "Should we enable proper nested multivalue grouping", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag USE_RECONFIGURABLE_DISPATCHER = defineFeatureFlag( "use-reconfigurable-dispatcher", false, List.of("jonmv"), "2023-07-14", "2023-10-01", "Whether to set up a ReconfigurableDispatcher with config self-sub for backend nodes", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag WRITE_CONFIG_SERVER_SESSION_DATA_AS_ONE_BLOB = defineFeatureFlag( "write-config-server-session-data-as-blob", false, @@ -382,21 +382,21 @@ public class Flags { List.of("freva"), "2023-09-08", "2023-11-01", "Minimum amount of advertised memory for exclusive nodes", "Takes effect immediately", - APPLICATION_ID, CLUSTER_ID, CLUSTER_TYPE); + INSTANCE_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundBooleanFlag ASSIGN_RANDOMIZED_ID = defineFeatureFlag( "assign-randomized-id", false, List.of("mortent"), "2023-08-31", "2024-02-01", "Whether to assign randomized id to the application", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag ASSIGNED_RANDOMIZED_ID_RATE = defineIntFlag( "assign-randomized-id-rate", 5, List.of("mortent"), "2023-09-11", "2024-02-01", "Rate for requesting assigned ids for existing certificates. Rate is per maintainer cycle.", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag CONTENT_LAYER_METADATA_FEATURE_LEVEL = defineIntFlag( "content-layer-metadata-feature-level", 0, @@ -404,7 +404,7 @@ public class Flags { "Value semantics: 0) legacy behavior, 1) operation cancellation, 2) operation " + "cancellation and ephemeral content node sequence numbers for bucket replicas", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners, diff --git a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java index f856ebeb456..629636afb68 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java @@ -13,7 +13,7 @@ import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_TYPE; import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL; @@ -43,19 +43,19 @@ public class PermanentFlags { "jvm-gc-options", "", "Sets default jvm gc options", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag HEAP_SIZE_PERCENTAGE = defineIntFlag( "heap-size-percentage", 70, "Sets default jvm heap size percentage", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag QUERY_DISPATCH_WARMUP = defineDoubleFlag( "query-dispatch-warmup", 5, "Warmup duration for query dispatcher", "Takes effect at redeployment (requires restart)", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag FLEET_CANARY = defineFeatureFlag( "fleet-canary", false, @@ -86,13 +86,13 @@ public class PermanentFlags { "host-flavor", "", "Specifies the Vespa flavor name that the hosts of the matching nodes should have.", "Takes effect on next deployment (including internal redeployment).", - APPLICATION_ID, CLUSTER_TYPE, CLUSTER_ID); + INSTANCE_ID, CLUSTER_TYPE, CLUSTER_ID); public static final UnboundBooleanFlag SKIP_MAINTENANCE_DEPLOYMENT = defineFeatureFlag( "node-repository-skip-maintenance-deployment", false, "Whether PeriodicApplicationMaintainer should skip deployment for an application", "Takes effect at next run of maintainer", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundListFlag<String> INACTIVE_MAINTENANCE_JOBS = defineListFlag( "inactive-maintenance-jobs", List.of(), String.class, @@ -120,19 +120,19 @@ public class PermanentFlags { "Hard limit on how many CPUs a container may use. This value is multiplied by CPU allocated to node, so " + "to cap CPU at 200%, set this to 2, etc. 0 disables the cap to allow unlimited CPU.", "Takes effect on next node agent tick. Change is orchestrated, but does NOT require container restart", - HOSTNAME, APPLICATION_ID, CLUSTER_ID, CLUSTER_TYPE); + HOSTNAME, INSTANCE_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundIntFlag MIN_DISK_THROUGHPUT_MB_S = defineIntFlag( "min-disk-throughput-mb-s", 0, "Minimum required disk throughput performance, 0 = default, Only when using remote disk", "Takes effect when node is provisioned", - APPLICATION_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); + INSTANCE_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundIntFlag MIN_DISK_IOPS_K = defineIntFlag( "min-disk-iops-k", 0, "Minimum required disk I/O operations per second, unit is kilo, 0 = default, Only when using remote disk", "Takes effect when node is provisioned", - APPLICATION_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); + INSTANCE_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag( "disabled-host-admin-tasks", List.of(), String.class, @@ -145,13 +145,13 @@ public class PermanentFlags { "docker-image-repo", "", "Override default docker image repo. Docker image version will be Vespa version.", "Takes effect on next deployment from controller", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag SEND_LIMITED_METRIC_SET = defineFeatureFlag( "send-limited-metric-set", true, "Whether a limited metric set should be fetched from metrics-proxy (CD systems only)", "Takes effect on next host admin tick", - APPLICATION_ID); + INSTANCE_ID); private static final String VERSION_QUALIFIER_REGEX = "[a-zA-Z0-9_-]+"; private static final Pattern QUALIFIER_PATTERN = Pattern.compile("^" + VERSION_QUALIFIER_REGEX + "$"); @@ -164,13 +164,13 @@ public class PermanentFlags { "Otherwise a '.' + the flag value will be appended.", "Takes effect on the next host admin tick. The upgrade to the new wanted docker image is orchestrated.", value -> value.isEmpty() || QUALIFIER_PATTERN.matcher(value).find() || VERSION_PATTERN.matcher(value).find(), - HOSTNAME, NODE_TYPE, TENANT_ID, APPLICATION_ID, CLUSTER_TYPE, CLUSTER_ID, VESPA_VERSION); + HOSTNAME, NODE_TYPE, TENANT_ID, INSTANCE_ID, CLUSTER_TYPE, CLUSTER_ID, VESPA_VERSION); public static final UnboundStringFlag ZOOKEEPER_SERVER_VERSION = defineStringFlag( "zookeeper-server-version", "3.8.0", "ZooKeeper server version, a jar file zookeeper-server-<ZOOKEEPER_SERVER_VERSION>-jar-with-dependencies.jar must exist", "Takes effect on restart of Docker container", - NODE_TYPE, APPLICATION_ID, HOSTNAME); + NODE_TYPE, INSTANCE_ID, HOSTNAME); public static final UnboundBooleanFlag ENABLE_PUBLIC_SIGNUP_FLOW = defineFeatureFlag( "enable-public-signup-flow", false, @@ -188,7 +188,7 @@ public class PermanentFlags { "jvm-omit-stack-trace-in-fast-throw", true, "Controls JVM option OmitStackTraceInFastThrow (default feature flag value is true, which is the default JVM option value as well)", "takes effect on JVM restart", - CLUSTER_TYPE, APPLICATION_ID); + CLUSTER_TYPE, INSTANCE_ID); public static final UnboundIntFlag MAX_TRIAL_TENANTS = defineIntFlag( "max-trial-tenants", -1, @@ -200,7 +200,7 @@ public class PermanentFlags { "allow-disable-mtls", true, "Allow application to disable client authentication", "Takes effect on redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MAX_OS_UPGRADES = defineIntFlag( "max-os-upgrades", 30, @@ -219,7 +219,7 @@ public class PermanentFlags { "tls-ciphers-override", List.of(), String.class, "Override TLS ciphers enabled for port 4443 on hosted application containers", "Takes effect on redeployment", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundStringFlag ENDPOINT_CERTIFICATE_ALGORITHM = defineStringFlag( @@ -227,20 +227,20 @@ public class PermanentFlags { // Acceptable values are: "rsa_4096", "ecdsa_p256" "Selects algorithm used for an applications endpoint certificate", "Takes effect when a new endpoint certificate is requested (on first deployment or deployment adding new endpoints)", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundDoubleFlag RESOURCE_LIMIT_DISK = defineDoubleFlag( "resource-limit-disk", 0.75, "Resource limit (between 0.0 and 1.0) for disk usage on content nodes, used by cluster controller for when to block feed", "Takes effect on next deployment", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundDoubleFlag RESOURCE_LIMIT_MEMORY = defineDoubleFlag( "resource-limit-memory", 0.8, "Resource limit (between 0.0 and 1.0) for memory usage on content nodes, used by cluster controller for when to block feed", "Takes effect on next deployment", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundListFlag<String> LOGCTL_OVERRIDE = defineListFlag( @@ -248,7 +248,7 @@ public class PermanentFlags { "A list of vespa-logctl statements that are run on container startup. " + "Each item should be on the form <service>:<component> <level>=on", "Takes effect on container restart", - APPLICATION_ID, HOSTNAME + INSTANCE_ID, HOSTNAME ); public static final UnboundListFlag<String> ENVIRONMENT_VARIABLES = defineListFlag( @@ -256,14 +256,14 @@ public class PermanentFlags { "A list of environment variables set for all services. " + "Each item should be on the form <ENV_VAR>=<VALUE>", "Takes effect on service restart", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundStringFlag CONFIG_PROXY_JVM_ARGS = defineStringFlag( "config-proxy-jvm-args", "", "Sets jvm args for config proxy (added at the end of startup command, will override existing ones)", "Takes effect on restart of Docker container", - APPLICATION_ID + INSTANCE_ID ); // This must be set in a feature flag to avoid flickering between the new and old value during config server upgrade @@ -277,20 +277,20 @@ public class PermanentFlags { "forward-issues-as-errors", true, "When the backend detects a problematic issue with a query, it will by default send it as an error message to the QRS, which adds it in an ErrorHit in the result. May be disabled using this flag.", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag DEACTIVATE_ROUTING = defineFeatureFlag( "deactivate-routing", false, "Deactivates routing for an application by removing all reals from its load balancers. Used in " + "cases where we immediately need to stop serving an application, i.e. in case of service violations", "Takes effect on next redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundListFlag<String> IGNORED_HTTP_USER_AGENTS = defineListFlag( "ignored-http-user-agents", List.of(), String.class, "List of user agents to ignore (crawlers etc)", "Takes effect immediately.", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundListFlag<String> INCOMPATIBLE_VERSIONS = defineListFlag( "incompatible-versions", List.of("8"), String.class, @@ -305,7 +305,7 @@ public class PermanentFlags { "The config server will refuse to serve config to nodes running a version which is incompatible with their " + "current wanted node version, i.e., nodes about to upgrade to a version which is incompatible with the current.", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundStringFlag ADMIN_CLUSTER_NODE_ARCHITECTURE = defineStringFlag( "admin-cluster-node-architecture", "x86_64", @@ -313,7 +313,7 @@ public class PermanentFlags { "(logserver and clustercontroller clusters).", "Takes effect on next redeployment", value -> Set.of("any", "arm64", "x86_64").contains(value), - APPLICATION_ID); + INSTANCE_ID); public static final UnboundListFlag<String> CLOUD_ACCOUNTS = defineListFlag( "cloud-accounts", List.of(), String.class, @@ -325,20 +325,20 @@ public class PermanentFlags { "fail-deployment-for-files-with-unknown-extension", "FAIL", "Whether to log or fail for deployments when app has a file with unknown extension (valid values: LOG, FAIL)", "Takes effect at redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundListFlag<String> DISABLED_DEPLOYMENT_ZONES = defineListFlag( "disabled-deployment-zones", List.of(), String.class, "The zones, e.g., prod.norway-71, where deployments jobs are currently disabled", "Takes effect immediately", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundBooleanFlag ALLOW_USER_FILTERS = defineFeatureFlag( "allow-user-filters", true, "Allow user filter (chains) in application", "Takes effect on next redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundLongFlag CONFIG_SERVER_SESSION_EXPIRY_TIME = defineLongFlag( "config-server-session-expiry-time", 3600, @@ -357,27 +357,27 @@ public class PermanentFlags { "keep-file-references-days", 30, "How many days to keep file references on tenant nodes (based on last modification time)", "Takes effect on restart of Docker container", - APPLICATION_ID + INSTANCE_ID ); public static final UnboundIntFlag KEEP_FILE_REFERENCES_COUNT = defineIntFlag( "keep-file-references-count", 20, "How many file references to keep on tenant nodes (no matter what last modification time is)", "Takes effect on restart of Docker container", - ZONE_ID, APPLICATION_ID + ZONE_ID, INSTANCE_ID ); public static final UnboundIntFlag ENDPOINT_CONNECTION_TTL = defineIntFlag( "endpoint-connection-ttl", 45, "Time to live for connections to endpoints in seconds", "Takes effect on next redeployment", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundBooleanFlag AUTOSCALING = defineFeatureFlag( "autoscaling", true, "Whether to enable autoscaling", "Takes effect immediately", - APPLICATION_ID); + INSTANCE_ID); public static final UnboundIntFlag MAX_HOSTS_PER_HOUR = defineIntFlag( "max-hosts-per-hour", 40, @@ -392,7 +392,7 @@ public class PermanentFlags { "Takes effect on next tick", // The application ID is the exclusive application ID associated with the host, // if any, or otherwise hosted-vespa:tenant-host:default. - APPLICATION_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); + INSTANCE_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundIntFlag DROP_DENTRIES = defineIntFlag( "drop-dentries", -1, @@ -401,7 +401,7 @@ public class PermanentFlags { "Takes effect on next tick", // The application ID is the exclusive application ID associated with the host, // if any, or otherwise hosted-vespa:tenant-host:default. - APPLICATION_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); + INSTANCE_ID, TENANT_ID, CLUSTER_ID, CLUSTER_TYPE); public static final UnboundIntFlag CERT_POOL_SIZE = defineIntFlag( "cert-pool-size", 0, diff --git a/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java b/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java index 2193d70ec47..8fb48c8a82f 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java @@ -4,30 +4,31 @@ package com.yahoo.vespa.flags.json; import com.yahoo.vespa.flags.FetchVector; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; -import java.util.stream.Collectors; /** * @author hakonhall */ public class DimensionHelper { - private static final Map<FetchVector.Dimension, String> serializedDimensions = new HashMap<>(); + private static final Map<FetchVector.Dimension, List<String>> serializedDimensions = new HashMap<>(); static { - serializedDimensions.put(FetchVector.Dimension.APPLICATION_ID, "application"); - serializedDimensions.put(FetchVector.Dimension.CLOUD, "cloud"); - serializedDimensions.put(FetchVector.Dimension.CLOUD_ACCOUNT, "cloud-account"); - serializedDimensions.put(FetchVector.Dimension.CLUSTER_ID, "cluster-id"); - serializedDimensions.put(FetchVector.Dimension.CLUSTER_TYPE, "cluster-type"); - serializedDimensions.put(FetchVector.Dimension.CONSOLE_USER_EMAIL, "console-user-email"); - serializedDimensions.put(FetchVector.Dimension.ENVIRONMENT, "environment"); - serializedDimensions.put(FetchVector.Dimension.HOSTNAME, "hostname"); - serializedDimensions.put(FetchVector.Dimension.NODE_TYPE, "node-type"); - serializedDimensions.put(FetchVector.Dimension.SYSTEM, "system"); - serializedDimensions.put(FetchVector.Dimension.TENANT_ID, "tenant"); - serializedDimensions.put(FetchVector.Dimension.VESPA_VERSION, "vespa-version"); - serializedDimensions.put(FetchVector.Dimension.ZONE_ID, "zone"); + serializedDimensions.put(FetchVector.Dimension.CLOUD, List.of("cloud")); + serializedDimensions.put(FetchVector.Dimension.CLOUD_ACCOUNT, List.of("cloud-account")); + serializedDimensions.put(FetchVector.Dimension.CLUSTER_ID, List.of("cluster-id")); + serializedDimensions.put(FetchVector.Dimension.CLUSTER_TYPE, List.of("cluster-type")); + serializedDimensions.put(FetchVector.Dimension.CONSOLE_USER_EMAIL, List.of("console-user-email")); + serializedDimensions.put(FetchVector.Dimension.ENVIRONMENT, List.of("environment")); + serializedDimensions.put(FetchVector.Dimension.HOSTNAME, List.of("hostname")); + serializedDimensions.put(FetchVector.Dimension.INSTANCE_ID, List.of("instance", "application")); + serializedDimensions.put(FetchVector.Dimension.NODE_TYPE, List.of("node-type")); + serializedDimensions.put(FetchVector.Dimension.SYSTEM, List.of("system")); + serializedDimensions.put(FetchVector.Dimension.TENANT_ID, List.of("tenant")); + serializedDimensions.put(FetchVector.Dimension.VESPA_VERSION, List.of("vespa-version")); + serializedDimensions.put(FetchVector.Dimension.ZONE_ID, List.of("zone")); if (serializedDimensions.size() != FetchVector.Dimension.values().length) { throw new IllegalStateException(FetchVectorHelper.class.getName() + " is not in sync with " + @@ -35,16 +36,27 @@ public class DimensionHelper { } } - private static final Map<String, FetchVector.Dimension> deserializedDimensions = serializedDimensions. - entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); + private static final Map<String, FetchVector.Dimension> deserializedDimensions = reverseMapping(serializedDimensions); + + private static Map<String, FetchVector.Dimension> reverseMapping(Map<FetchVector.Dimension, List<String>> mapping) { + Map<String, FetchVector.Dimension> reverseMapping = new LinkedHashMap<>(); + mapping.forEach((dimension, serializedDimensions) -> { + serializedDimensions.forEach(serializedDimension -> { + if (reverseMapping.put(serializedDimension, dimension) != null) { + throw new IllegalStateException("Duplicate serialized dimension: '" + serializedDimension + "'"); + } + }); + }); + return Map.copyOf(reverseMapping); + } public static String toWire(FetchVector.Dimension dimension) { - String serializedDimension = serializedDimensions.get(dimension); - if (serializedDimension == null) { + List<String> serializedDimension = serializedDimensions.get(dimension); + if (serializedDimension == null || serializedDimension.isEmpty()) { throw new IllegalArgumentException("Unsupported dimension (please add it): '" + dimension + "'"); } - return serializedDimension; + return serializedDimension.get(0); } public static FetchVector.Dimension fromWire(String serializedDimension) { diff --git a/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java b/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java index 3edde140de8..dd332be6627 100644 --- a/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java +++ b/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java @@ -50,7 +50,7 @@ public class FlagsTest { // zone is set because it was set on the unbound flag above assertThat(vector.getValue().getValue(FetchVector.Dimension.ZONE_ID), is(Optional.of("a-zone"))); // application and node type are not set - assertThat(vector.getValue().getValue(FetchVector.Dimension.APPLICATION_ID), is(Optional.empty())); + assertThat(vector.getValue().getValue(FetchVector.Dimension.INSTANCE_ID), is(Optional.empty())); assertThat(vector.getValue().getValue(FetchVector.Dimension.NODE_TYPE), is(Optional.empty())); RawFlag rawFlag = mock(RawFlag.class); @@ -58,11 +58,11 @@ public class FlagsTest { when(rawFlag.asJsonNode()).thenReturn(BooleanNode.getTrue()); // raw flag deserializes to true - assertThat(booleanFlag.with(FetchVector.Dimension.APPLICATION_ID, "an-app").value(), equalTo(true)); + assertThat(booleanFlag.with(FetchVector.Dimension.INSTANCE_ID, "an-app").value(), equalTo(true)); verify(source, times(2)).fetch(any(), vector.capture()); // application was set on the (bound) flag. - assertThat(vector.getValue().getValue(FetchVector.Dimension.APPLICATION_ID), is(Optional.of("an-app"))); + assertThat(vector.getValue().getValue(FetchVector.Dimension.INSTANCE_ID), is(Optional.of("an-app"))); } @Test diff --git a/flags/src/test/java/com/yahoo/vespa/flags/json/ConditionTest.java b/flags/src/test/java/com/yahoo/vespa/flags/json/ConditionTest.java index 4da66bd5cc1..084ad3b9395 100644 --- a/flags/src/test/java/com/yahoo/vespa/flags/json/ConditionTest.java +++ b/flags/src/test/java/com/yahoo/vespa/flags/json/ConditionTest.java @@ -18,7 +18,7 @@ public class ConditionTest { var params = new Condition.CreateParams(FetchVector.Dimension.HOSTNAME).withValues(hostname1); Condition condition = WhitelistCondition.create(params); assertFalse(condition.test(new FetchVector())); - assertFalse(condition.test(new FetchVector().with(FetchVector.Dimension.APPLICATION_ID, "foo"))); + assertFalse(condition.test(new FetchVector().with(FetchVector.Dimension.INSTANCE_ID, "foo"))); assertFalse(condition.test(new FetchVector().with(FetchVector.Dimension.HOSTNAME, "bar"))); assertTrue(condition.test(new FetchVector().with(FetchVector.Dimension.HOSTNAME, hostname1))); } @@ -29,7 +29,7 @@ public class ConditionTest { var params = new Condition.CreateParams(FetchVector.Dimension.HOSTNAME).withValues(hostname1); Condition condition = BlacklistCondition.create(params); assertTrue(condition.test(new FetchVector())); - assertTrue(condition.test(new FetchVector().with(FetchVector.Dimension.APPLICATION_ID, "foo"))); + assertTrue(condition.test(new FetchVector().with(FetchVector.Dimension.INSTANCE_ID, "foo"))); assertTrue(condition.test(new FetchVector().with(FetchVector.Dimension.HOSTNAME, "bar"))); assertFalse(condition.test(new FetchVector().with(FetchVector.Dimension.HOSTNAME, hostname1))); } diff --git a/flags/src/test/java/com/yahoo/vespa/flags/json/FlagDataTest.java b/flags/src/test/java/com/yahoo/vespa/flags/json/FlagDataTest.java index 3ca7f59c759..ed81afc8054 100644 --- a/flags/src/test/java/com/yahoo/vespa/flags/json/FlagDataTest.java +++ b/flags/src/test/java/com/yahoo/vespa/flags/json/FlagDataTest.java @@ -52,6 +52,8 @@ public class FlagDataTest { } }"""; + private final String json_with_instance = json.replace("application", "instance"); + private final FetchVector vector = new FetchVector(); @Test @@ -62,16 +64,16 @@ public class FlagDataTest { // First rule matches only if both conditions match verify(Optional.of("false"), vector .with(FetchVector.Dimension.HOSTNAME, "host1") - .with(FetchVector.Dimension.APPLICATION_ID, "app2")); + .with(FetchVector.Dimension.INSTANCE_ID, "app2")); verify(Optional.of("true"), vector .with(FetchVector.Dimension.HOSTNAME, "host1") - .with(FetchVector.Dimension.APPLICATION_ID, "app3")); + .with(FetchVector.Dimension.INSTANCE_ID, "app3")); // Verify unsetting a dimension with null works. verify(Optional.of("true"), vector .with(FetchVector.Dimension.HOSTNAME, "host1") - .with(FetchVector.Dimension.APPLICATION_ID, "app3") - .with(FetchVector.Dimension.APPLICATION_ID, null)); + .with(FetchVector.Dimension.INSTANCE_ID, "app3") + .with(FetchVector.Dimension.INSTANCE_ID, null)); // No rules apply if zone is overridden to an unknown zone verify(Optional.empty(), vector.with(FetchVector.Dimension.ZONE_ID, "unknown zone")); @@ -81,7 +83,7 @@ public class FlagDataTest { void testPartialResolve() { FlagData data = FlagData.deserialize(json); assertEquals(data.partialResolve(vector), data); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app1")), + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app1")), FlagData.deserialize(""" { "id": "id1", @@ -102,7 +104,7 @@ public class FlagDataTest { } }""")); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app1")), + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app1")), FlagData.deserialize(""" { "id": "id1", @@ -123,7 +125,7 @@ public class FlagDataTest { } }""")); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app3")), + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app3")), FlagData.deserialize(""" { "id": "id1", @@ -154,7 +156,7 @@ public class FlagDataTest { } }""")); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app3") + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app3") .with(FetchVector.Dimension.HOSTNAME, "host1")), FlagData.deserialize(""" { @@ -169,7 +171,7 @@ public class FlagDataTest { } }""")); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app3") + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app3") .with(FetchVector.Dimension.HOSTNAME, "host3")), FlagData.deserialize(""" { @@ -191,7 +193,7 @@ public class FlagDataTest { } }""")); - assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app3") + assertEquals(data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app3") .with(FetchVector.Dimension.HOSTNAME, "host3") .with(FetchVector.Dimension.ZONE_ID, "zone2")), FlagData.deserialize(""" @@ -204,7 +206,7 @@ public class FlagDataTest { ] }""")); - FlagData fullyResolved = data.partialResolve(vector.with(FetchVector.Dimension.APPLICATION_ID, "app3") + FlagData fullyResolved = data.partialResolve(vector.with(FetchVector.Dimension.INSTANCE_ID, "app3") .with(FetchVector.Dimension.HOSTNAME, "host3") .with(FetchVector.Dimension.ZONE_ID, "zone3")); assertEquals(fullyResolved, FlagData.deserialize(""" @@ -271,6 +273,11 @@ public class FlagDataTest { } private void verify(Optional<String> expectedValue, FetchVector vector) { + verify(json, expectedValue, vector); + verify(json_with_instance, expectedValue, vector); + } + + private void verify(String json, Optional<String> expectedValue, FetchVector vector) { FlagData data = FlagData.deserialize(json); assertEquals("id1", data.id().toString()); Optional<RawFlag> rawFlag = data.resolve(vector); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java index 466ee65fcc1..98252a696f2 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java @@ -40,7 +40,7 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_ID; import static com.yahoo.vespa.flags.FetchVector.Dimension.CLUSTER_TYPE; import static com.yahoo.vespa.flags.FetchVector.Dimension.HOSTNAME; @@ -416,7 +416,7 @@ public class NodeAgentImpl implements NodeAgent { private ContainerResources getContainerResources(NodeAgentContext context) { double cpuCap = context.vcpuOnThisHost() * containerCpuCap - .with(APPLICATION_ID, context.node().owner().map(ApplicationId::serializedForm)) + .with(INSTANCE_ID, context.node().owner().map(ApplicationId::serializedForm)) .with(CLUSTER_ID, context.node().membership().map(NodeMembership::clusterId)) .with(CLUSTER_TYPE, context.node().membership().map(membership -> membership.type().value())) .with(HOSTNAME, context.node().hostname()) 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 e228d31384c..f42d1ce9bd3 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 @@ -21,7 +21,8 @@ import java.util.Set; public class LoadBalancerInstance { private final Optional<DomainName> hostname; - private final Optional<String> ipAddress; + private final Optional<String> ip4Address; + private final Optional<String> ip6Address; private final Optional<DnsZone> dnsZone; private final Set<Integer> ports; private final Set<String> networks; @@ -30,11 +31,12 @@ public class LoadBalancerInstance { private final List<PrivateServiceId> serviceIds; private final CloudAccount cloudAccount; - public LoadBalancerInstance(Optional<DomainName> hostname, Optional<String> ipAddress, + public LoadBalancerInstance(Optional<DomainName> hostname, Optional<String> ip4Address, Optional<String> ip6Address, Optional<DnsZone> dnsZone, Set<Integer> ports, Set<String> networks, Set<Real> reals, ZoneEndpoint settings, List<PrivateServiceId> serviceIds, CloudAccount cloudAccount) { this.hostname = Objects.requireNonNull(hostname, "hostname must be non-null"); - this.ipAddress = Objects.requireNonNull(ipAddress, "ip must be non-null"); + this.ip4Address = Objects.requireNonNull(ip4Address, "ip4Address must be non-null"); + this.ip6Address = Objects.requireNonNull(ip6Address, "ip6Address must be non-null"); this.dnsZone = Objects.requireNonNull(dnsZone, "dnsZone must be non-null"); this.ports = ImmutableSortedSet.copyOf(requirePorts(ports)); this.networks = ImmutableSortedSet.copyOf(Objects.requireNonNull(networks, "networks must be non-null")); @@ -43,9 +45,9 @@ public class LoadBalancerInstance { this.serviceIds = List.copyOf(Objects.requireNonNull(serviceIds, "private service id must be non-null")); this.cloudAccount = Objects.requireNonNull(cloudAccount, "cloudAccount must be non-null"); - if (hostname.isEmpty() == ipAddress.isEmpty()) { - throw new IllegalArgumentException("Exactly 1 of hostname=%s and ipAddress=%s must be set".formatted( - hostname.map(DomainName::value).orElse("<empty>"), ipAddress.orElse("<empty>"))); + if (hostname.isEmpty() == ip4Address.isEmpty()) { + throw new IllegalArgumentException("Exactly 1 of hostname=%s and ip4Address=%s must be set".formatted( + hostname.map(DomainName::value).orElse("<empty>"), ip4Address.orElse("<empty>"))); } } @@ -54,9 +56,14 @@ public class LoadBalancerInstance { return hostname; } - /** IP address of this (public) load balancer */ - public Optional<String> ipAddress() { - return ipAddress; + /** IPv4 address of this (public) load balancer */ + public Optional<String> ip4Address() { + return ip4Address; + } + + /** IPv6 address of this (public) load balancer */ + public Optional<String> ip6Address() { + return ip6Address; } /** ID of the DNS zone associated with this */ @@ -114,7 +121,7 @@ public class LoadBalancerInstance { public LoadBalancerInstance with(Set<Real> reals, ZoneEndpoint settings, Optional<PrivateServiceId> serviceId) { List<PrivateServiceId> ids = new ArrayList<>(serviceIds); serviceId.filter(id -> ! ids.contains(id)).ifPresent(ids::add); - return new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, + return new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, ids, cloudAccount); } @@ -123,7 +130,7 @@ public class LoadBalancerInstance { public LoadBalancerInstance withServiceIds(List<PrivateServiceId> serviceIds) { List<PrivateServiceId> ids = new ArrayList<>(serviceIds); for (PrivateServiceId id : this.serviceIds) if ( ! ids.contains(id)) ids.add(id); - return new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, settings, ids, cloudAccount); + return new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, ids, cloudAccount); } } 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 a79766a577d..c79ccc2aece 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 @@ -57,6 +57,7 @@ public class LoadBalancerServiceMock implements LoadBalancerService { var instance = new LoadBalancerInstance( Optional.of(DomainName.of("lb-" + spec.application().toShortString() + "-" + spec.cluster().value())), Optional.empty(), + Optional.empty(), Optional.of(new DnsZone("zone-id-1")), Collections.singleton(4443), ImmutableSet.of("10.2.3.0/24", "10.4.5.0/24"), 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 e49d1b302cf..073662b39fe 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 @@ -45,6 +45,7 @@ public class SharedLoadBalancerService implements LoadBalancerService { return new LoadBalancerInstance(Optional.of(DomainName.of(vipHostname)), Optional.empty(), Optional.empty(), + Optional.empty(), Set.of(4443), Set.of(), spec.reals(), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java index 8638087c5cd..eb290d9ec2a 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java @@ -59,7 +59,7 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer { int failures = 0; outer: for (var applicationNodes : activeNodesByApplication().entrySet()) { - boolean enabled = enabledFlag.with(FetchVector.Dimension.APPLICATION_ID, + boolean enabled = enabledFlag.with(FetchVector.Dimension.INSTANCE_ID, applicationNodes.getKey().serializedForm()).value(); if (!enabled) continue; for (var clusterNodes : nodesByCluster(applicationNodes.getValue()).entrySet()) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java index 14693c75436..9cbf1778b3b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java @@ -58,7 +58,7 @@ public class PeriodicApplicationMaintainer extends ApplicationMaintainer { private boolean shouldMaintain(ApplicationId id) { BooleanFlag skipMaintenanceDeployment = PermanentFlags.SKIP_MAINTENANCE_DEPLOYMENT.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, id.serializedForm()); + .with(FetchVector.Dimension.INSTANCE_ID, id.serializedForm()); return ! skipMaintenanceDeployment.value(); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java index 3c3868bfeb8..8ad975f5334 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java @@ -47,6 +47,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; import static com.yahoo.stream.CustomCollectors.toLinkedMap; import static java.util.stream.Collectors.collectingAndThen; @@ -456,7 +457,12 @@ public class CuratorDb { transaction.onCommitted(() -> { for (var lb : loadBalancers) { if (lb.state() == fromState) continue; - Optional<String> target = lb.instance().flatMap(instance -> instance.hostname().map(DomainName::value).or(instance::ipAddress)); + Optional<String> target = lb.instance() + .flatMap(instance -> instance.hostname() + .map(DomainName::value) + .or(() -> Optional.of(Stream.concat(instance.ip4Address().stream(), + instance.ip6Address().stream()) + .collect(Collectors.joining(","))))); if (fromState == null) { log.log(Level.INFO, () -> "Creating " + lb.id() + target.map(t -> " (" + t + ")").orElse("") + " in " + lb.state()); 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 b85d96c6b54..d329676f842 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 @@ -45,6 +45,7 @@ public class LoadBalancerSerializer { private static final String idField = "id"; private static final String hostnameField = "hostname"; private static final String lbIpAddressField = "ipAddress"; + private static final String lbIp6AddressField = "ip6Address"; private static final String stateField = "state"; private static final String changedAtField = "changedAt"; private static final String dnsZoneField = "dnsZone"; @@ -69,7 +70,8 @@ public class LoadBalancerSerializer { root.setString(idField, loadBalancer.id().serializedForm()); loadBalancer.instance().flatMap(LoadBalancerInstance::hostname).ifPresent(hostname -> root.setString(hostnameField, hostname.value())); - loadBalancer.instance().flatMap(LoadBalancerInstance::ipAddress).ifPresent(ip -> root.setString(lbIpAddressField, ip)); + loadBalancer.instance().flatMap(LoadBalancerInstance::ip4Address).ifPresent(ip -> root.setString(lbIpAddressField, ip)); + loadBalancer.instance().flatMap(LoadBalancerInstance::ip6Address).ifPresent(ip -> root.setString(lbIp6AddressField, ip)); root.setString(stateField, asString(loadBalancer.state())); root.setLong(changedAtField, loadBalancer.changedAt().toEpochMilli()); loadBalancer.instance().flatMap(LoadBalancerInstance::dnsZone).ifPresent(dnsZone -> root.setString(dnsZoneField, dnsZone.id())); @@ -123,7 +125,8 @@ public class LoadBalancerSerializer { object.field(networksField).traverse((ArrayTraverser) (i, network) -> networks.add(network.asString())); 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<String> ip4Address = optionalString(object.field(lbIpAddressField), Function.identity()).filter(s -> !s.isEmpty()); + Optional<String> ip6Address = optionalString(object.field(lbIp6AddressField), Function.identity()).filter(s -> !s.isEmpty()); Optional<DnsZone> dnsZone = optionalString(object.field(dnsZoneField), DnsZone::new); ZoneEndpoint settings = zoneEndpoint(object.field(settingsField)); Optional<PrivateServiceId> serviceId = optionalString(object.field(serviceIdField), PrivateServiceId::of); @@ -131,9 +134,9 @@ public class LoadBalancerSerializer { object.field(serviceIdsField).traverse((ArrayTraverser) (__, serviceIdObject) -> serviceIds.add(PrivateServiceId.of(serviceIdObject.asString()))); if (serviceIds.isEmpty()) serviceId.ifPresent(serviceIds::add); // TODO: remove after winter vacation '23 CloudAccount cloudAccount = optionalString(object.field(cloudAccountField), CloudAccount::from).orElse(CloudAccount.empty); - Optional<LoadBalancerInstance> instance = hostname.isEmpty() && ipAddress.isEmpty() + Optional<LoadBalancerInstance> instance = hostname.isEmpty() && ip4Address.isEmpty() && ip6Address.isEmpty() ? Optional.empty() - : Optional.of(new LoadBalancerInstance(hostname, ipAddress, dnsZone, ports, networks, reals, settings, serviceIds, cloudAccount)); + : Optional.of(new LoadBalancerInstance(hostname, ip4Address, ip6Address, dnsZone, ports, networks, reals, settings, serviceIds, cloudAccount)); return new LoadBalancer(LoadBalancerId.fromSerializedForm(object.field(idField).asString()), instance, diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java index 4236f78336b..e5599ac3d18 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java @@ -18,7 +18,7 @@ import java.util.Map; import java.util.TreeMap; import static com.yahoo.config.provision.NodeResources.Architecture; -import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID; +import static com.yahoo.vespa.flags.FetchVector.Dimension.INSTANCE_ID; import static java.util.Objects.requireNonNull; /** @@ -146,7 +146,7 @@ public class CapacityPolicies { } private Architecture adminClusterArchitecture(ApplicationId instance) { - return Architecture.valueOf(adminClusterNodeArchitecture.with(APPLICATION_ID, instance.serializedForm()).value()); + return Architecture.valueOf(adminClusterNodeArchitecture.with(INSTANCE_ID, instance.serializedForm()).value()); } /** Returns the resources for the newest version not newer than that requested in the cluster spec. */ 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 c414c70f315..22909122079 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 @@ -273,7 +273,7 @@ public class LoadBalancerProvisioner { LoadBalancer currentLoadBalancer, ZoneEndpoint zoneEndpoint, CloudAccount cloudAccount) { - boolean shouldDeactivateRouting = deactivateRouting.with(FetchVector.Dimension.APPLICATION_ID, + boolean shouldDeactivateRouting = deactivateRouting.with(FetchVector.Dimension.INSTANCE_ID, id.application().serializedForm()) .value(); Set<Real> reals = shouldDeactivateRouting ? Set.of() : realsOf(nodes, cloudAccount); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java index b289a965567..ca170d2af6b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java @@ -94,7 +94,7 @@ class NodeAllocation { this.nextIndex = nextIndex; this.nodeRepository = nodeRepository; this.requiredHostFlavor = Optional.of(PermanentFlags.HOST_FLAVOR.bindTo(nodeRepository.flagSource()) - .with(FetchVector.Dimension.APPLICATION_ID, application.serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, application.serializedForm()) .with(FetchVector.Dimension.CLUSTER_TYPE, cluster.type().name()) .with(FetchVector.Dimension.CLUSTER_ID, cluster.id().value()) .value()) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java index 06ab9eb1a10..ab222c45252 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java @@ -88,7 +88,7 @@ public class NodeResourceLimits { if (cluster.type() == ClusterSpec.Type.admin) return 1; if (!exclusive) return 4; return minExclusiveAdvertisedMemoryGbFlag - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()) .with(FetchVector.Dimension.CLUSTER_ID, cluster.id().value()) .with(FetchVector.Dimension.CLUSTER_TYPE, cluster.type().name()) .value(); 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 09f947503f6..20aa7d8181e 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 @@ -57,7 +57,8 @@ public class LoadBalancersResponse extends SlimeJsonResponse { lbObject.setString("instance", lb.id().application().instance().value()); lbObject.setString("cluster", lb.id().cluster().value()); lb.instance().flatMap(LoadBalancerInstance::hostname).ifPresent(hostname -> lbObject.setString("hostname", hostname.value())); - lb.instance().flatMap(LoadBalancerInstance::ipAddress).ifPresent(ipAddress -> lbObject.setString("ipAddress", ipAddress)); + lb.instance().flatMap(LoadBalancerInstance::ip4Address).ifPresent(ip -> lbObject.setString("ipAddress", ip)); + lb.instance().flatMap(LoadBalancerInstance::ip6Address).ifPresent(ip -> lbObject.setString("ip6Address", ip)); lb.instance().flatMap(LoadBalancerInstance::dnsZone).ifPresent(dnsZone -> lbObject.setString("dnsZone", dnsZone.id())); Cursor networkArray = lbObject.setArray("networks"); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java index 2b908efde94..a8f526544d7 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java @@ -201,7 +201,7 @@ class NodesResponse extends SlimeJsonResponse { .with(FetchVector.Dimension.HOSTNAME, node.hostname()) .with(FetchVector.Dimension.NODE_TYPE, node.type().name()) .with(FetchVector.Dimension.TENANT_ID, allocation.owner().tenant().value()) - .with(FetchVector.Dimension.APPLICATION_ID, allocation.owner().serializedForm()) + .with(FetchVector.Dimension.INSTANCE_ID, allocation.owner().serializedForm()) .with(FetchVector.Dimension.CLUSTER_TYPE, allocation.membership().cluster().type().name()) .with(FetchVector.Dimension.CLUSTER_ID, allocation.membership().cluster().id().value()) .with(FetchVector.Dimension.VESPA_VERSION, allocation.membership().cluster().vespaVersion().toFullString()) 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 6dc681ae5c8..b5257e23d9e 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 @@ -40,6 +40,7 @@ public class LoadBalancerSerializerTest { Optional.of(new LoadBalancerInstance( Optional.of(DomainName.of("lb-host")), Optional.empty(), + Optional.empty(), Optional.of(new DnsZone("zone-id-1")), Set.of(4080, 4443), Set.of("10.2.3.4/24"), @@ -73,6 +74,7 @@ public class LoadBalancerSerializerTest { Optional.of(new LoadBalancerInstance( Optional.empty(), Optional.of("1.2.3.4"), + Optional.of("fd00::1"), Optional.of(new DnsZone("zone-id-1")), Set.of(4443), Set.of("10.2.3.4/24", "12.3.2.1/30"), @@ -86,6 +88,8 @@ public class LoadBalancerSerializerTest { var serialized = LoadBalancerSerializer.fromJson(LoadBalancerSerializer.toJson(loadBalancer)); assertEquals(loadBalancer.id(), serialized.id()); assertEquals(loadBalancer.instance().get().hostname(), serialized.instance().get().hostname()); + assertEquals(loadBalancer.instance().get().ip4Address(), serialized.instance().get().ip4Address()); + assertEquals(loadBalancer.instance().get().ip6Address(), serialized.instance().get().ip6Address()); assertEquals(loadBalancer.instance().get().dnsZone(), serialized.instance().get().dnsZone()); assertEquals(loadBalancer.instance().get().ports(), serialized.instance().get().ports()); assertEquals(loadBalancer.instance().get().networks(), serialized.instance().get().networks()); |