diff options
Diffstat (limited to 'flags/src/main/java')
4 files changed, 115 insertions, 35 deletions
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flag.java b/flags/src/main/java/com/yahoo/vespa/flags/Flag.java index 7ca5066969f..4d49d52fa73 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flag.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flag.java @@ -1,6 +1,20 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.flags; +import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.CloudName; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.NodeResources.Architecture; +import com.yahoo.config.provision.NodeType; +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.Zone; +import com.yahoo.config.provision.zone.ZoneApi; +import com.yahoo.config.provision.zone.ZoneId; + import java.util.Optional; /** @@ -10,7 +24,7 @@ import java.util.Optional; * @param <F> The concrete subclass type of the flag * @author hakonhall */ -public interface Flag<T, F> { +public interface Flag<T, F extends Flag<T, F>> { /** The flag ID. */ FlagId id(); @@ -28,6 +42,54 @@ public interface Flag<T, F> { return dimensionValue.map(value -> with(dimension, value)).orElse(self()); } + /** Sets the tenant, application, and instance dimensions. */ + default F with(ApplicationId applicationId) { + return with(Dimension.TENANT_ID, applicationId.tenant().value()) + .with(Dimension.APPLICATION, applicationId.toSerializedFormWithoutInstance()) + .with(Dimension.INSTANCE_ID, applicationId.serializedForm()); + } + + /** architecture MUST NOT be 'any'. */ + default F with(Architecture architecture) { return with(Dimension.ARCHITECTURE, architecture.name()); } + /** + * Sets the cloud-account dimension ONLY IF it is an enclave account.<br/> + * Sets the clave dimension to "enclave" if it is an enclave account, otherwise "noclave". + */ + default F with(CloudAccount cloudAccount, Zone zone) { + return cloudAccount.isEnclave(zone) + ? with(Dimension.CLOUD_ACCOUNT, Optional.of(cloudAccount).map(CloudAccount::value)) + .with(Dimension.CLAVE, "enclave") + : with(Dimension.CLAVE, "noclave"); + } + default F with(CloudName cloud) { return with(Dimension.CLOUD, cloud.value()); } + default F with(ClusterSpec.Id clusterId) { return with(Dimension.CLUSTER_ID, clusterId.value()); } + default F with(ClusterSpec.Type clusterType) { return with(Dimension.CLUSTER_TYPE, clusterType.name()); } + default F with(Environment environment) { return with(Dimension.ENVIRONMENT, environment.value()); } + default F with(NodeType nodeType) { return with(Dimension.NODE_TYPE, nodeType.name()); } + default F with(SystemName systemName) { return with(Dimension.SYSTEM, systemName.value()); } + default F with(TenantName tenantName) { return with(Dimension.TENANT_ID, tenantName.value()); } + default F with(Version vespaVersion) { return with(Dimension.VESPA_VERSION, vespaVersion.toFullString()); } + default F with(ZoneId zoneId) { return with(Dimension.ZONE_ID, zoneId.value()); } + default F with(Zone zone) { return with(Dimension.ZONE_ID, zone.systemLocalValue()); } + default F with(ZoneApi zoneApi) { return with(zoneApi.getVirtualId()); } + + /** Sets the tenant, application, and instance dimensions. */ + default F withApplicationId(Optional<ApplicationId> applicationId) { return applicationId.map(this::with).orElse(self()); } + /** architecture MUST NOT be 'any'. */ + default F withArchitecture(Optional<Architecture> architecture) { return architecture.map(this::with).orElse(self()); } + default F withCloudAccount(Optional<CloudAccount> cloudAccount, Zone zone) { return cloudAccount.map(account -> with(account, zone)).orElse(self()); } + default F withCloudName(Optional<CloudName> cloud) { return cloud.map(this::with).orElse(self()); } + default F withClusterId(Optional<ClusterSpec.Id> clusterId) { return clusterId.map(this::with).orElse(self()); } + default F withClusterType(Optional<ClusterSpec.Type> clusterType) { return clusterType.map(this::with).orElse(self()); } + default F withEnvironment(Optional<Environment> environment) { return environment.map(this::with).orElse(self()); } + default F withNodeType(Optional<NodeType> nodeType) { return nodeType.map(this::with).orElse(self()); } + default F withSystemName(Optional<SystemName> systemName) { return systemName.map(this::with).orElse(self()); } + default F withTenantName(Optional<TenantName> tenantName) { return tenantName.map(this::with).orElse(self()); } + default F withVersion(Optional<Version> vespaVersion) { return vespaVersion.map(this::with).orElse(self()); } + default F withZoneId(Optional<ZoneId> zoneId) { return zoneId.map(this::with).orElse(self()); } + default F withZone(Optional<Zone> zone) { return zone.map(this::with).orElse(self()); } + default F withZoneApi(Optional<ZoneApi> zoneApi) { return zoneApi.map(this::with).orElse(self()); } + /** Returns the value, boxed if the flag wraps a primitive type. */ T boxedValue(); } 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 a3fe010c65b..abff6fcd4c6 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -84,18 +84,6 @@ public class Flags { "Takes effect at redeployment", INSTANCE_ID); - public static final UnboundBooleanFlag NEW_RESOURCES_FORMULA = defineFeatureFlag( - "new-resources-formula", true, - List.of("hakonhall"), "2024-04-25", "2024-05-25", - "Use an easier to understand formula for calculating the memory and disk resources", - "Takes effect on next deployment of an applications."); - - public static final UnboundBooleanFlag FIX_CONFIG_SERVER_HEAP = defineFeatureFlag( - "fix-config-server-heap", false, - List.of("hakonhall"), "2024-04-23", "2024-05-23", - "Base the calculation of the config server JVM heap size on the amount of memory available to the container.", - "Takes effect on start of config server Podman container"); - public static final UnboundStringFlag RESPONSE_SEQUENCER_TYPE = defineStringFlag( "response-sequencer-type", "ADAPTIVE", List.of("baldersheim"), "2020-12-02", "2024-12-31", @@ -243,13 +231,6 @@ public class Flags { "Takes effect on next tick.", NODE_TYPE); - public static final UnboundStringFlag DIST_HOST = defineStringFlag( - "dist-host", "", - List.of("freva"), "2024-04-15", "2024-05-31", - "Sets dist_host YUM variable, empty means old behavior. Only effective in Public.", - "Provisioning of instance or next host-admin tick", - HOSTNAME, NODE_TYPE, CLOUD_ACCOUNT); - public static final UnboundBooleanFlag ENABLED_HORIZON_DASHBOARD = defineFeatureFlag( "enabled-horizon-dashboard", false, List.of("olaa"), "2021-09-13", "2024-09-01", @@ -336,14 +317,14 @@ public class Flags { public static final UnboundBooleanFlag SORT_BLUEPRINTS_BY_COST = defineFeatureFlag( "sort-blueprints-by-cost", false, - List.of("baldersheim"), "2023-12-19", "2024-05-31", + List.of("baldersheim"), "2023-12-19", "2024-10-31", "If true blueprints are sorted based on cost estimate, rather that absolute estimated hits", "Takes effect at redeployment", INSTANCE_ID); public static final UnboundBooleanFlag ALWAYS_MARK_PHRASE_EXPENSIVE = defineFeatureFlag( "always-mark-phrase-expensive", false, - List.of("baldersheim"), "2023-11-20", "2024-05-31", + List.of("baldersheim"), "2023-11-20", "2024-10-31", "If true all phrases will be marked expensive, independent of parents", "Takes effect at redeployment", INSTANCE_ID); @@ -418,13 +399,13 @@ public class Flags { public static UnboundBooleanFlag CALYPSO_ENABLED = defineFeatureFlag( "calypso-enabled", true, - List.of("mortent"), "2024-02-19", "2024-05-01", + List.of("mortent"), "2024-02-19", "2024-08-01", "Whether to enable calypso for host", "Takes effect immediately", HOSTNAME); public static UnboundBooleanFlag ATHENZ_PROVIDER = defineFeatureFlag( "athenz-provider", false, - List.of("mortent"), "2024-02-19", "2024-05-01", + List.of("mortent"), "2024-02-19", "2024-08-01", "Whether to use athenz as node identity provider", "Takes effect on next identity refresh", HOSTNAME); @@ -435,7 +416,7 @@ public class Flags { "Takes effect immediately"); public static final UnboundIntFlag PERSISTENCE_THREAD_MAX_FEED_OP_BATCH_SIZE = defineIntFlag( - "persistence-thread-max-feed-op-batch-size", 1, + "persistence-thread-max-feed-op-batch-size", 64, List.of("vekterli"), "2024-04-12", "2025-01-01", "Maximum number of enqueued feed operations (put/update/remove) bound "+ "towards the same bucket that can be async dispatched as part of the " + @@ -449,6 +430,33 @@ public class Flags { "Whether logserver container should run otel agent", "Takes effect at redeployment", INSTANCE_ID); + public static UnboundBooleanFlag HUBSPOT_SYNC_TENANTS = defineFeatureFlag( + "hubspot-sync-tenants", false, + List.of("bjorncs"), "2024-05-07", "2025-01-01", + "Whether to sync tenants to HubSpot", + "Takes effect immediately"); + + public static final UnboundBooleanFlag REMOVE_ORPHANED_DNS_RECORDS = defineFeatureFlag( + "remove-orphaned-dns-records", false, + List.of("mpolden"), "2024-05-07", "2024-10-01", + "Whether EndpointDnsMaintainer should remove orphaned records instead of logging them", + "Takes effect on next maintenance run"); + + public static final UnboundBooleanFlag SYMMETRIC_PUT_AND_ACTIVATE_REPLICA_SELECTION = defineFeatureFlag( + "symmetric-put-and-activate-replica-selection", false, + List.of("vekterli"), "2024-05-23", "2024-08-01", + "Iff true there will be an 1-1 symmetry between the replicas chosen as feed targets " + + "for Put operations and the replica selection logic for bucket activation. If false, " + + "legacy feed behavior is used.", + "Takes effect immediately", + INSTANCE_ID); + + public static final UnboundBooleanFlag HUBSPOT_SYNC_CONTACTS = defineFeatureFlag( + "hubspot-sync-contacts", false, + List.of("bjorncs"), "2024-05-27", "2025-01-01", + "Whether to sync contacts to HubSpot", + "Takes effect immediately"); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners, String createdAt, String expiresAt, String description, 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 3b73d9d6013..1b1e74c0b1e 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java @@ -18,12 +18,12 @@ import static com.yahoo.vespa.flags.Dimension.ARCHITECTURE; import static com.yahoo.vespa.flags.Dimension.CERTIFICATE_PROVIDER; import static com.yahoo.vespa.flags.Dimension.CLAVE; import static com.yahoo.vespa.flags.Dimension.CLOUD_ACCOUNT; -import static com.yahoo.vespa.flags.Dimension.FLAVOR; -import static com.yahoo.vespa.flags.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.Dimension.CLUSTER_ID; import static com.yahoo.vespa.flags.Dimension.CLUSTER_TYPE; import static com.yahoo.vespa.flags.Dimension.CONSOLE_USER_EMAIL; +import static com.yahoo.vespa.flags.Dimension.FLAVOR; import static com.yahoo.vespa.flags.Dimension.HOSTNAME; +import static com.yahoo.vespa.flags.Dimension.INSTANCE_ID; import static com.yahoo.vespa.flags.Dimension.NODE_TYPE; import static com.yahoo.vespa.flags.Dimension.TENANT_ID; import static com.yahoo.vespa.flags.Dimension.VESPA_VERSION; @@ -178,7 +178,7 @@ public class PermanentFlags { 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.9.1", + "zookeeper-server-version", "3.9.2", "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, INSTANCE_ID, HOSTNAME); @@ -196,8 +196,8 @@ public class PermanentFlags { ); public static final UnboundBooleanFlag JVM_OMIT_STACK_TRACE_IN_FAST_THROW = defineFeatureFlag( - "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)", + "jvm-omit-stack-trace-in-fast-throw", false, + "Controls JVM option OmitStackTraceInFastThrow (the default JVM option corresponds to feature flag being false )", "takes effect on JVM restart", CLUSTER_TYPE, INSTANCE_ID); @@ -404,6 +404,12 @@ public class PermanentFlags { "Takes effect immediately", INSTANCE_ID); + public static final UnboundBooleanFlag AUTOSCALING_DETAILED_LOGGING = defineFeatureFlag( + "autoscaling-detailed-logging", false, + "Whether to log autoscaling decision data", + "Takes effect immediately", + INSTANCE_ID); + public static final UnboundIntFlag MAX_HOSTS_PER_HOUR = defineIntFlag( "max-hosts-per-hour", 40, "The number of hosts that can be provisioned per hour in a zone, before throttling is " + diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java index 66356d979a4..3f229862d7a 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java @@ -7,6 +7,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.SharedHosts; import com.yahoo.vespa.flags.PermanentFlags; import java.util.List; @@ -19,7 +21,7 @@ import java.util.Objects; */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(value = JsonInclude.Include.NON_NULL) -public class SharedHost { +public class SharedHost implements SharedHosts { private final List<HostResources> resources; @@ -43,14 +45,16 @@ public class SharedHost { /** Whether there are any shared hosts specifically for the given cluster type, or without a cluster type restriction. */ @JsonIgnore - public boolean supportsClusterType(String clusterType) { - return resources.stream().anyMatch(resource -> resource.clusterType().map(clusterType::equalsIgnoreCase).orElse(true)); + @Override + public boolean supportsClusterType(ClusterSpec.Type clusterType) { + return resources.stream().anyMatch(resource -> resource.clusterType().map(type -> clusterType.name().equalsIgnoreCase(type)).orElse(true)); } /** Whether there are any shared hosts specifically for the given cluster type. */ @JsonIgnore - public boolean hasClusterType(String clusterType) { - return resources.stream().anyMatch(resource -> resource.clusterType().map(clusterType::equalsIgnoreCase).orElse(false)); + @Override + public boolean hasClusterType(ClusterSpec.Type clusterType) { + return resources.stream().anyMatch(resource -> resource.clusterType().map(type -> clusterType.name().equalsIgnoreCase(type)).orElse(false)); } @JsonIgnore |