summaryrefslogtreecommitdiffstats
path: root/flags
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2020-12-03 19:33:21 +0100
committerØyvind Grønnesby <oyving@verizonmedia.com>2020-12-03 19:33:21 +0100
commit2b01b49d4f9fa0338c00a113daf7e61e10041646 (patch)
tree2c970f2cae118746977147fbaca49e5f0c02c09a /flags
parentf0771b2201f06684f66c7261c528167adb8f4c7b (diff)
parent5ad34990803dc859ee107ba46b3e60ef877898ca (diff)
Merge remote-tracking branch 'origin/master' into ogronnesby/trial-tenant-limit
Conflicts: controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java flags/src/main/java/com/yahoo/vespa/flags/Flags.java
Diffstat (limited to 'flags')
-rw-r--r--flags/pom.xml5
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java40
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java221
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java172
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java3
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java50
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java29
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java25
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java25
9 files changed, 400 insertions, 170 deletions
diff --git a/flags/pom.xml b/flags/pom.xml
index ba0e4a94692..4f1bdcb61e3 100644
--- a/flags/pom.xml
+++ b/flags/pom.xml
@@ -88,6 +88,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
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 0dce61cf0bb..d01ca64cb9f 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.flags;
import javax.annotation.concurrent.Immutable;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -12,13 +13,26 @@ import java.util.List;
@Immutable
public class FlagDefinition {
private final UnboundFlag<?, ?, ?> unboundFlag;
+ private final List<String> owners;
+ private final Instant createdAt;
+ private final Instant expiresAt;
private final String description;
private final String modificationEffect;
private final List<FetchVector.Dimension> dimensions;
- public FlagDefinition(UnboundFlag<?, ?, ?> unboundFlag, String description, String modificationEffect,
- FetchVector.Dimension... dimensions) {
+ public FlagDefinition(
+ UnboundFlag<?, ?, ?> unboundFlag,
+ List<String> owners,
+ Instant createdAt,
+ Instant expiresAt,
+ String description,
+ String modificationEffect,
+ FetchVector.Dimension... dimensions) {
+ validate(owners, createdAt, expiresAt);
this.unboundFlag = unboundFlag;
+ this.owners = owners;
+ this.createdAt = createdAt;
+ this.expiresAt = expiresAt;
this.description = description;
this.modificationEffect = modificationEffect;
this.dimensions = Collections.unmodifiableList(Arrays.asList(dimensions));
@@ -39,4 +53,26 @@ public class FlagDefinition {
public String getModificationEffect() {
return modificationEffect;
}
+
+ public List<String> getOwners() { return owners; }
+
+ public Instant getCreatedAt() { return createdAt; }
+
+ public Instant getExpiresAt() { return expiresAt; }
+
+ private static void validate(List<String> owners, Instant createdAt, Instant expiresAt) {
+ if (expiresAt.isBefore(createdAt)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Flag cannot expire before its creation date (createdAt='%s', expiresAt='%s')",
+ createdAt, expiresAt));
+ }
+ if (owners == PermanentFlags.OWNERS) {
+ if (!createdAt.equals(PermanentFlags.CREATED_AT) || !expiresAt.equals(PermanentFlags.EXPIRES_AT)) {
+ throw new IllegalArgumentException("Invalid creation or expiration date for permanent flag");
+ }
+ } else if (owners.isEmpty()) {
+ throw new IllegalArgumentException("Owner(s) must be specified");
+ }
+ }
}
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 ab9dcd6415d..1279e11393d 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -3,18 +3,18 @@ package com.yahoo.vespa.flags;
import com.yahoo.component.Vtag;
import com.yahoo.vespa.defaults.Defaults;
-import com.yahoo.vespa.flags.custom.ClusterCapacity;
-import com.yahoo.vespa.flags.custom.SharedHost;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.TreeMap;
import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID;
-import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL;
import static com.yahoo.vespa.flags.FetchVector.Dimension.HOSTNAME;
import static com.yahoo.vespa.flags.FetchVector.Dimension.NODE_TYPE;
-import static com.yahoo.vespa.flags.FetchVector.Dimension.TENANT_ID;
import static com.yahoo.vespa.flags.FetchVector.Dimension.VESPA_VERSION;
import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
@@ -42,226 +42,173 @@ import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
public class Flags {
private static volatile TreeMap<FlagId, FlagDefinition> flags = new TreeMap<>();
- public static final UnboundBooleanFlag FLEET_CANARY = defineFeatureFlag(
- "fleet-canary", false,
- "Whether the host is a fleet canary.",
- "Takes effect on next host admin tick.",
- HOSTNAME);
-
- public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag(
- "disabled-host-admin-tasks", List.of(), String.class,
- "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask), or some node-agent " +
- "functionality (see NodeAgentTask), that should be skipped",
- "Takes effect on next host admin tick",
- HOSTNAME, NODE_TYPE);
-
- public static final UnboundStringFlag DOCKER_VERSION = defineStringFlag(
- "docker-version", "1.13.1-102.git7f2769b",
- "The version of the docker to use of the format VERSION-REL: The YUM package to be installed will be " +
- "2:docker-VERSION-REL.el7.centos.x86_64 in AWS (and without '.centos' otherwise). " +
- "If docker-version is not of this format, it must be parseable by YumPackageName::fromString.",
- "Takes effect on next tick.",
- HOSTNAME);
-
- public static final UnboundDoubleFlag CONTAINER_CPU_CAP = defineDoubleFlag(
- "container-cpu-cap", 0,
- "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.",
- "Takes effect on next node agent tick. Change is orchestrated, but does NOT require container restart",
- HOSTNAME, APPLICATION_ID);
-
- public static final UnboundIntFlag REBOOT_INTERVAL_IN_DAYS = defineIntFlag(
- "reboot-interval-in-days", 30,
- "No reboots are scheduled 0x-1x reboot intervals after the previous reboot, while reboot is " +
- "scheduled evenly distributed in the 1x-2x range (and naturally guaranteed at the 2x boundary).",
- "Takes effect on next run of NodeRebooter");
-
public static final UnboundBooleanFlag RETIRE_WITH_PERMANENTLY_DOWN = defineFeatureFlag(
"retire-with-permanently-down", false,
+ List.of("hakonhall"), "2020-12-02", "2021-02-01",
"If enabled, retirement will end with setting the host status to PERMANENTLY_DOWN, " +
"instead of ALLOWED_TO_BE_DOWN (old behavior).",
"Takes effect on the next run of RetiredExpirer.",
HOSTNAME);
- public static final UnboundListFlag<ClusterCapacity> PREPROVISION_CAPACITY = defineListFlag(
- "preprovision-capacity", List.of(), ClusterCapacity.class,
- "Specifies the resources that ought to be immediately available for additional cluster " +
- "allocations. If the resources are not available, additional hosts will be provisioned. " +
- "Only applies to dynamically provisioned zones.",
- "Takes effect on next iteration of DynamicProvisioningMaintainer.");
-
- public static final UnboundBooleanFlag COMPACT_PREPROVISION_CAPACITY = defineFeatureFlag(
- "compact-preprovision-capacity", true,
- "Whether preprovision capacity can be satisfied with available capacity on hosts with " +
- "existing allocations. Historically preprovision-capacity referred to empty hosts.",
- "Takes effect on next iteration of DynamicProvisioningMaintainer.");
-
- public static final UnboundJacksonFlag<SharedHost> SHARED_HOST = defineJacksonFlag(
- "shared-host", SharedHost.createDisabled(), SharedHost.class,
- "Specifies whether shared hosts can be provisioned, and if so, the advertised " +
- "node resources of the host, the maximum number of containers, etc.",
- "Takes effect on next iteration of DynamicProvisioningMaintainer.");
-
- public static final UnboundListFlag<String> INACTIVE_MAINTENANCE_JOBS = defineListFlag(
- "inactive-maintenance-jobs", List.of(), String.class,
- "The list of maintenance jobs that are inactive.",
- "Takes effect immediately, but any currently running jobs will run until completion.");
-
public static final UnboundDoubleFlag DEFAULT_TERM_WISE_LIMIT = defineDoubleFlag(
"default-term-wise-limit", 1.0,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Default limit for when to apply termwise query evaluation",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
- public static final UnboundStringFlag JVM_GC_OPTIONS = defineStringFlag(
- "jvm-gc-options", "",
- "Sets deafult jvm gc options",
- "Takes effect at redeployment",
- ZONE_ID, APPLICATION_ID);
-
public static final UnboundStringFlag FEED_SEQUENCER_TYPE = defineStringFlag(
"feed-sequencer-type", "LATENCY",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Selects type of sequenced executor used for feeding, valid values are LATENCY, ADAPTIVE, THROUGHPUT",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundStringFlag RESPONSE_SEQUENCER_TYPE = defineStringFlag(
"response-sequencer-type", "ADAPTIVE",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Selects type of sequenced executor used for mbus responses, valid values are LATENCY, ADAPTIVE, THROUGHPUT",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundIntFlag RESPONSE_NUM_THREADS = defineIntFlag(
"response-num-threads", 2,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Number of threads used for mbus responses, default is 2, negative number = numcores/4",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_COMMUNICATIONMANAGER_THREAD = defineFeatureFlag(
"skip-communicatiomanager-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the communicationmanager thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_MBUS_REQUEST_THREAD = defineFeatureFlag(
"skip-mbus-request-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the mbus request thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_MBUS_REPLY_THREAD = defineFeatureFlag(
"skip-mbus-reply-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the mbus reply thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_THREE_PHASE_UPDATES = defineFeatureFlag(
"use-three-phase-updates", false,
+ List.of("vekterli"), "2020-12-02", "2021-02-01",
"Whether to enable the use of three-phase updates when bucket replicas are out of sync.",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_DIRECT_STORAGE_API_RPC = defineFeatureFlag(
"use-direct-storage-api-rpc", false,
+ List.of("geirst"), "2020-12-02", "2021-02-01",
"Whether to use direct RPC for Storage API communication between content cluster nodes.",
"Takes effect at restart of distributor and content node process",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_FAST_VALUE_TENSOR_IMPLEMENTATION = defineFeatureFlag(
"use-fast-value-tensor-implementation", false,
+ List.of("geirst"), "2020-12-02", "2021-02-01",
"Whether to use FastValueBuilderFactory as the tensor implementation on all content nodes.",
"Takes effect at restart of content node process",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag HOST_HARDENING = defineFeatureFlag(
"host-hardening", false,
+ List.of("hakonhall"), "2020-12-02", "2021-02-01",
"Whether to enable host hardening Linux baseline.",
"Takes effect on next tick or on host-admin restart (may vary where used).",
HOSTNAME);
public static final UnboundBooleanFlag TCP_ABORT_ON_OVERFLOW = defineFeatureFlag(
"tcp-abort-on-overflow", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to set /proc/sys/net/ipv4/tcp_abort_on_overflow to 0 (false) or 1 (true)",
"Takes effect on next host-admin tick.",
HOSTNAME);
- public static final UnboundStringFlag ZOOKEEPER_SERVER_VERSION = defineStringFlag(
- "zookeeper-server-version", "3.5.6",
- "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);
-
public static final UnboundStringFlag TLS_FOR_ZOOKEEPER_CLIENT_SERVER_COMMUNICATION = defineStringFlag(
"tls-for-zookeeper-client-server-communication", "OFF",
+ List.of("hmusum"), "2020-12-02", "2021-02-01",
"How to setup TLS for ZooKeeper client/server communication. Valid values are OFF, PORT_UNIFICATION, TLS_WITH_PORT_UNIFICATION, TLS_ONLY",
"Takes effect on restart of config server",
NODE_TYPE, HOSTNAME);
public static final UnboundBooleanFlag USE_TLS_FOR_ZOOKEEPER_CLIENT = defineFeatureFlag(
"use-tls-for-zookeeper-client", false,
+ List.of("hmusum"), "2020-12-02", "2021-02-01",
"Whether to use TLS for ZooKeeper clients",
"Takes effect on restart of process",
NODE_TYPE, HOSTNAME);
public static final UnboundBooleanFlag VALIDATE_ENDPOINT_CERTIFICATES = defineFeatureFlag(
"validate-endpoint-certificates", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether endpoint certificates should be validated before use",
"Takes effect on the next deployment of the application");
public static final UnboundStringFlag DELETE_UNUSED_ENDPOINT_CERTIFICATES = defineStringFlag(
"delete-unused-endpoint-certificates", "disable",
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether the endpoint certificate maintainer should delete unused certificates in cameo/zk",
"Takes effect on next scheduled run of maintainer - set to \"disable\", \"dryrun\" or \"enable\"");
public static final UnboundBooleanFlag USE_ALTERNATIVE_ENDPOINT_CERTIFICATE_PROVIDER = defineFeatureFlag(
"use-alternative-endpoint-certificate-provider", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to use an alternative CA when provisioning new certificates",
"Takes effect only on initial application deployment - not on later certificate refreshes!");
public static final UnboundStringFlag DOCKER_IMAGE_REPO = defineStringFlag(
"docker-image-repo", "",
+ List.of("valerijf"), "2020-12-02", "2021-02-01",
"Override default docker image repo. Docker image version will be Vespa version.",
"Takes effect on next deployment from controller",
ZONE_ID, APPLICATION_ID);
+ public static final UnboundStringFlag YUM_DIST_HOST = defineStringFlag(
+ "yum-dist-host", "",
+ List.of("aressem"), "2020-12-02", "2021-02-01",
+ "Override the default dist host for yum.",
+ "Takes effect on next tick or on host-admin restart (may vary where used).");
+
public static final UnboundBooleanFlag ENDPOINT_CERT_IN_SHARED_ROUTING = defineFeatureFlag(
"endpoint-cert-in-shared-routing", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to provision and use endpoint certs for apps in shared routing zones",
"Takes effect on next deployment of the application", APPLICATION_ID);
- public static final UnboundBooleanFlag USE_CLOUD_INIT_FORMAT = defineFeatureFlag(
- "use-cloud-init", false,
- "Use the cloud-init format when provisioning hosts",
- "Takes effect immediately",
- ZONE_ID);
-
public static final UnboundBooleanFlag PROVISION_APPLICATION_ROLES = defineFeatureFlag(
"provision-application-roles", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether application roles should be provisioned",
"Takes effect on next deployment (controller)",
ZONE_ID);
public static final UnboundBooleanFlag APPLICATION_IAM_ROLE = defineFeatureFlag(
"application-iam-roles", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Allow separate iam roles when provisioning/assigning hosts",
"Takes effect immediately on new hosts, on next redeploy for applications",
APPLICATION_ID);
- public static final UnboundBooleanFlag ENABLE_PUBLIC_SIGNUP_FLOW = defineFeatureFlag(
- "enable-public-signup-flow", false,
- "Show the public signup flow for a user in the console",
- "takes effect on browser reload of api/user/v1/user",
- CONSOLE_USER_EMAIL
- );
-
public static final UnboundIntFlag MAX_TRIAL_TENANTS = defineIntFlag(
"max-trial-tenants", -1,
+ List.of("ogronnesby"), "2020-12-03", "2021-04-01",
"The maximum nr. of tenants with trial plan, -1 is unlimited",
"Takes effect immediately"
);
public static final UnboundBooleanFlag CONTROLLER_PROVISION_LB = defineFeatureFlag(
"controller-provision-lb", false,
+ List.of("mpolden"), "2020-12-02", "2021-02-01",
"Provision load balancer for controller cluster",
"Takes effect when controller application is redeployed",
ZONE_ID
@@ -269,142 +216,132 @@ public class Flags {
public static final UnboundIntFlag TENANT_NODE_QUOTA = defineIntFlag(
"tenant-node-quota", 5,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"The number of nodes a tenant is allowed to request per cluster",
"Only takes effect on next deployment, if set to a value other than the default for flag!",
APPLICATION_ID
);
- public static final UnboundIntFlag TENANT_BUDGET_QUOTA = defineIntFlag(
- "tenant-budget-quota", -1,
- "The budget in cents/hr a tenant is allowed spend per instance, as calculated by NodeResources",
- "Only takes effect on next deployment, if set to a value other than the default for flag!",
- TENANT_ID
- );
-
public static final UnboundBooleanFlag ONLY_PUBLIC_ACCESS = defineFeatureFlag(
"enable-public-only", false,
+ List.of("ogronnesby"), "2020-12-02", "2021-02-01",
"Only access public hosts from container",
"Takes effect on next tick"
);
- public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV4 = defineListFlag(
- "container-outbound-blocked-ipv4", List.of(), String.class,
- "List of IPs or CIDRs that are blocked for outbound connections",
- "Takes effect on next tick"
- );
-
- public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV6 = defineListFlag(
- "container-outbound-blocked-ipv6", List.of(), String.class,
- "List of IPs or CIDRs that are blocked for outbound connections",
- "Takes effect on next tick"
- );
-
public static final UnboundBooleanFlag HIDE_SHARED_ROUTING_ENDPOINT = defineFeatureFlag(
- "hide-shared-routing-endpoint",
- false,
+ "hide-shared-routing-endpoint", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether the controller should hide shared routing layer endpoint",
"Takes effect immediately",
APPLICATION_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);
-
public static final UnboundBooleanFlag USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION = defineFeatureFlag(
- "use-access-control-client-authentication",
- false,
+ "use-access-control-client-authentication", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether application container should set up client authentication on default port based on access control element",
"Takes effect on next internal redeployment",
APPLICATION_ID);
public static final UnboundBooleanFlag USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE = defineFeatureFlag(
"async-message-handling-on-schedule", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Optionally deliver async messages in own thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundIntFlag CONTENT_NODE_BUCKET_DB_STRIPE_BITS = defineIntFlag(
"content-node-bucket-db-stripe-bits", 0,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Number of bits used for striping the bucket DB in service layer",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundIntFlag MERGE_CHUNK_SIZE = defineIntFlag(
"merge-chunk-size", 0x400000,
- "Size of merge buffer in service layer",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
+ "Size of baldersheim buffer in service layer",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundDoubleFlag FEED_CONCURRENCY = defineDoubleFlag(
"feed-concurrency", 0.5,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"How much concurrency should be allowed for feed",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag ENABLE_AUTOMATIC_REINDEXING = defineFeatureFlag(
- "enable-automatic-reindexing",
- false,
+ "enable-automatic-reindexing", false,
+ List.of("bjorncs", "jonmv"), "2020-12-02", "2021-02-01",
"Whether to automatically trigger reindexing from config change",
"Takes effect on next internal redeployment",
APPLICATION_ID);
public static final UnboundBooleanFlag USE_POWER_OF_TWO_CHOICES_LOAD_BALANCING = defineFeatureFlag(
- "use-power-of-two-choices-load-balancing",
- false,
+ "use-power-of-two-choices-load-balancing", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether to use Power of two load balancing algorithm for application",
"Takes effect on next internal redeployment",
APPLICATION_ID);
public static final UnboundBooleanFlag DYNAMIC_RECONFIGURATION_OF_ZOOKEEPER_CLUSTER = defineFeatureFlag(
- "dynamic-reconfiguration-of-zookeeper-cluster",
- false,
+ "dynamic-reconfiguration-of-zookeeper-cluster", false,
+ List.of("hmusum"), "2020-12-02", "2021-02-01",
"Whether to allow dynamic reconfiguration of zookeeper cluster",
"Takes effect on next deployment",
APPLICATION_ID);
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, String description,
+ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundBooleanFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundBooleanFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundStringFlag defineStringFlag(String flagId, String defaultValue, String description,
+ public static UnboundStringFlag defineStringFlag(String flagId, String defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundStringFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundStringFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundIntFlag defineIntFlag(String flagId, int defaultValue, String description,
+ public static UnboundIntFlag defineIntFlag(String flagId, int defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundIntFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundIntFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundLongFlag defineLongFlag(String flagId, long defaultValue, String description,
+ public static UnboundLongFlag defineLongFlag(String flagId, long defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundLongFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundLongFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundDoubleFlag defineDoubleFlag(String flagId, double defaultValue, String description,
+ public static UnboundDoubleFlag defineDoubleFlag(String flagId, double defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundDoubleFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundDoubleFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static <T> UnboundJacksonFlag<T> defineJacksonFlag(String flagId, T defaultValue, Class<T> jacksonClass, String description,
+ public static <T> UnboundJacksonFlag<T> defineJacksonFlag(String flagId, T defaultValue, Class<T> jacksonClass, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
return define((id2, defaultValue2, vector2) -> new UnboundJacksonFlag<>(id2, defaultValue2, vector2, jacksonClass),
- flagId, defaultValue, description, modificationEffect, dimensions);
+ flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
public static <T> UnboundListFlag<T> defineListFlag(String flagId, List<T> defaultValue, Class<T> elementClass,
+ List<String> owners, String createdAt, String expiresAt,
String description, String modificationEffect, FetchVector.Dimension... dimensions) {
return define((fid, dval, fvec) -> new UnboundListFlag<>(fid, dval, elementClass, fvec),
- flagId, defaultValue, description, modificationEffect, dimensions);
+ flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
@FunctionalInterface
@@ -435,6 +372,9 @@ public class Flags {
private static <T, U extends UnboundFlag<?, ?, ?>> U define(TypedUnboundFlagFactory<T, U> factory,
String flagId,
T defaultValue,
+ List<String> owners,
+ String createdAt,
+ String expiresAt,
String description,
String modificationEffect,
FetchVector.Dimension[] dimensions) {
@@ -445,11 +385,16 @@ public class Flags {
// (determined by the current major version). Consider not setting VESPA_VERSION if minor = micro = 0.
.with(VESPA_VERSION, Vtag.currentVersion.toFullString());
U unboundFlag = factory.create(id, defaultValue, vector);
- FlagDefinition definition = new FlagDefinition(unboundFlag, description, modificationEffect, dimensions);
+ FlagDefinition definition = new FlagDefinition(
+ unboundFlag, owners, parseDate(createdAt), parseDate(expiresAt), description, modificationEffect, dimensions);
flags.put(id, definition);
return unboundFlag;
}
+ private static Instant parseDate(String rawDate) {
+ return DateTimeFormatter.ISO_DATE.parse(rawDate, LocalDate::from).atStartOfDay().toInstant(ZoneOffset.UTC);
+ }
+
public static List<FlagDefinition> getAllFlags() {
return List.copyOf(flags.values());
}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
new file mode 100644
index 00000000000..a3e2a11a79c
--- /dev/null
+++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
@@ -0,0 +1,172 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags;
+
+import com.yahoo.vespa.flags.custom.ClusterCapacity;
+import com.yahoo.vespa.flags.custom.SharedHost;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.HOSTNAME;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.NODE_TYPE;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.TENANT_ID;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
+
+/**
+ * Definition for permanent feature flags
+ *
+ * @author bjorncs
+ */
+public class PermanentFlags {
+
+ static final List<String> OWNERS = List.of();
+ static final Instant CREATED_AT = Instant.EPOCH;
+ static final Instant EXPIRES_AT = ZonedDateTime.of(2100, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant();
+
+ public static final UnboundBooleanFlag USE_ALTERNATIVE_ENDPOINT_CERTIFICATE_PROVIDER = defineFeatureFlag(
+ "use-alternative-endpoint-certificate-provider", false,
+ "Whether to use an alternative CA when provisioning new certificates",
+ "Takes effect only on initial application deployment - not on later certificate refreshes!");
+
+ public static final UnboundStringFlag JVM_GC_OPTIONS = defineStringFlag(
+ "jvm-gc-options", "",
+ "Sets deafult jvm gc options",
+ "Takes effect at redeployment",
+ ZONE_ID, APPLICATION_ID);
+
+ public static final UnboundStringFlag DOCKER_VERSION = defineStringFlag(
+ "docker-version", "1.13.1-102.git7f2769b",
+ "The version of the docker to use of the format VERSION-REL: The YUM package to be installed will be " +
+ "2:docker-VERSION-REL.el7.centos.x86_64 in AWS (and without '.centos' otherwise). " +
+ "If docker-version is not of this format, it must be parseable by YumPackageName::fromString.",
+ "Takes effect on next tick.",
+ HOSTNAME);
+
+ public static final UnboundBooleanFlag FLEET_CANARY = defineFeatureFlag(
+ "fleet-canary", false,
+ "Whether the host is a fleet canary.",
+ "Takes effect on next host admin tick.",
+ HOSTNAME);
+
+ public static final UnboundListFlag<ClusterCapacity> PREPROVISION_CAPACITY = defineListFlag(
+ "preprovision-capacity", List.of(), ClusterCapacity.class,
+ "Specifies the resources that ought to be immediately available for additional cluster " +
+ "allocations. If the resources are not available, additional hosts will be provisioned. " +
+ "Only applies to dynamically provisioned zones.",
+ "Takes effect on next iteration of DynamicProvisioningMaintainer.");
+
+ public static final UnboundIntFlag REBOOT_INTERVAL_IN_DAYS = defineIntFlag(
+ "reboot-interval-in-days", 30,
+ "No reboots are scheduled 0x-1x reboot intervals after the previous reboot, while reboot is " +
+ "scheduled evenly distributed in the 1x-2x range (and naturally guaranteed at the 2x boundary).",
+ "Takes effect on next run of NodeRebooter");
+
+ public static final UnboundJacksonFlag<SharedHost> SHARED_HOST = defineJacksonFlag(
+ "shared-host", SharedHost.createDisabled(), SharedHost.class,
+ "Specifies whether shared hosts can be provisioned, and if so, the advertised " +
+ "node resources of the host, the maximum number of containers, etc.",
+ "Takes effect on next iteration of DynamicProvisioningMaintainer.");
+
+ 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);
+
+ public static final UnboundListFlag<String> INACTIVE_MAINTENANCE_JOBS = defineListFlag(
+ "inactive-maintenance-jobs", List.of(), String.class,
+ "The list of maintenance jobs that are inactive.",
+ "Takes effect immediately, but any currently running jobs will run until completion.");
+
+ public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV4 = defineListFlag(
+ "container-outbound-blocked-ipv4", List.of(), String.class,
+ "List of IPs or CIDRs that are blocked for outbound connections",
+ "Takes effect on next tick");
+
+ public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV6 = defineListFlag(
+ "container-outbound-blocked-ipv6", List.of(), String.class,
+ "List of IPs or CIDRs that are blocked for outbound connections",
+ "Takes effect on next tick");
+
+ public static final UnboundIntFlag TENANT_BUDGET_QUOTA = defineIntFlag(
+ "tenant-budget-quota", -1,
+ "The budget in cents/hr a tenant is allowed spend per instance, as calculated by NodeResources",
+ "Only takes effect on next deployment, if set to a value other than the default for flag!",
+ TENANT_ID);
+
+ public static final UnboundDoubleFlag CONTAINER_CPU_CAP = defineDoubleFlag(
+ "container-cpu-cap", 0,
+ "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.",
+ "Takes effect on next node agent tick. Change is orchestrated, but does NOT require container restart",
+ HOSTNAME, APPLICATION_ID);
+
+ public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag(
+ "disabled-host-admin-tasks", List.of(), String.class,
+ "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask), or some node-agent " +
+ "functionality (see NodeAgentTask), that should be skipped",
+ "Takes effect on next host admin tick",
+ HOSTNAME, NODE_TYPE);
+
+ public static final UnboundStringFlag DOCKER_IMAGE_REPO = defineStringFlag(
+ "docker-image-repo", "",
+ "Override default docker image repo. Docker image version will be Vespa version.",
+ "Takes effect on next deployment from controller",
+ ZONE_ID, APPLICATION_ID);
+
+ public static final UnboundStringFlag ZOOKEEPER_SERVER_VERSION = defineStringFlag(
+ "zookeeper-server-version", "3.5.6",
+ "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);
+
+ public static final UnboundBooleanFlag ENABLE_PUBLIC_SIGNUP_FLOW = defineFeatureFlag(
+ "enable-public-signup-flow", false,
+ "Show the public signup flow for a user in the console",
+ "takes effect on browser reload of api/user/v1/user",
+ CONSOLE_USER_EMAIL);
+
+ private PermanentFlags() {}
+
+ private static UnboundBooleanFlag defineFeatureFlag(
+ String flagId, boolean defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineFeatureFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundStringFlag defineStringFlag(
+ String flagId, String defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineStringFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundIntFlag defineIntFlag(
+ String flagId, int defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineIntFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundLongFlag defineLongFlag(
+ String flagId, long defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineLongFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundDoubleFlag defineDoubleFlag(
+ String flagId, double defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineDoubleFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static <T> UnboundJacksonFlag<T> defineJacksonFlag(
+ String flagId, T defaultValue, Class<T> jacksonClass, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineJacksonFlag(flagId, defaultValue, jacksonClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static <T> UnboundListFlag<T> defineListFlag(
+ String flagId, List<T> defaultValue, Class<T> elementClass, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineListFlag(flagId, defaultValue, elementClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static String toString(Instant instant) { return DateTimeFormatter.ISO_DATE.withZone(ZoneOffset.UTC).format(instant); }
+}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
index c0b5d7a523c..129e1020b04 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
@@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
/**
@@ -45,7 +44,7 @@ public class HostResources {
this.vcpu = requirePositive("vcpu", vcpu);
this.memoryGb = requirePositive("memoryGb", memoryGb);
this.diskGb = requirePositive("diskGb", diskGb);
- this.bandwidthGbps = requirePositive("bandwidthGbps", Optional.ofNullable(bandwidthGbps).orElse(0.3));
+ this.bandwidthGbps = requirePositive("bandwidthGbps", bandwidthGbps);
this.diskSpeed = validateEnum("diskSpeed", validDiskSpeeds, diskSpeed);
this.storageType = validateEnum("storageType", validStorageTypes, storageType);
this.containers = requirePositive("containers", containers);
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 e463159eb8f..c952161cf72 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
@@ -2,46 +2,68 @@
package com.yahoo.vespa.flags.custom;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
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.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import java.util.List;
import java.util.Objects;
/**
- * Defines properties related to shared hosts, see {@link Flags#SHARED_HOST}.
+ * Defines properties related to shared hosts, see {@link PermanentFlags#SHARED_HOST}.
*
* @author hakon
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class SharedHost {
+ private final int DEFAULT_MIN_COUNT = 0;
+
private final List<HostResources> resources;
+ private final int minCount;
public static SharedHost createDisabled() {
- return new SharedHost(null);
+ return new SharedHost(null, null);
}
+ /**
+ * @param resourcesOrNull the resources of the shared host (or several to support e.g. tiers or
+ * fast/slow disks separately)
+ * @param minCountOrNull the minimum number of shared hosts
+ */
@JsonCreator
- public SharedHost(@JsonProperty("resources") List<HostResources> resources) {
- this.resources = resources == null ? List.of() : List.copyOf(resources);
+ public SharedHost(@JsonProperty("resources") List<HostResources> resourcesOrNull,
+ @JsonProperty("min-count") Integer minCountOrNull) {
+ this.resources = resourcesOrNull == null ? List.of() : List.copyOf(resourcesOrNull);
+ this.minCount = requireNonNegative(minCountOrNull, DEFAULT_MIN_COUNT, "min-count");
}
- @JsonProperty("resources")
+ @JsonGetter("resources")
public List<HostResources> getResourcesOrNull() {
return resources.isEmpty() ? null : resources;
}
+ @JsonGetter("min-count")
+ public Integer getMinCountOrNull() {
+ return minCount == DEFAULT_MIN_COUNT ? null : minCount;
+ }
+
+ @JsonIgnore
+ public boolean isEnabled() {
+ return resources.size() > 0;
+ }
+
@JsonIgnore
public List<HostResources> getHostResources() {
return resources;
}
- public boolean isEnabled() {
- return resources.size() > 0;
+ @JsonIgnore
+ public int getMinCount() {
+ return minCount;
}
@Override
@@ -61,4 +83,16 @@ public class SharedHost {
public int hashCode() {
return Objects.hash(resources);
}
+
+ private int requireNonNegative(Integer integerOrNull, int defaultValue, String fieldName) {
+ if (integerOrNull == null) {
+ return defaultValue;
+ }
+
+ if (integerOrNull < 0) {
+ throw new IllegalArgumentException(fieldName + " cannot be negative");
+ }
+
+ return integerOrNull;
+ }
}
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 28e84bcf3e5..48ed318af41 100644
--- a/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java
+++ b/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java
@@ -4,8 +4,6 @@ package com.yahoo.vespa.flags;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.node.BooleanNode;
-import com.yahoo.vespa.flags.custom.HostResources;
-import com.yahoo.vespa.flags.custom.SharedHost;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -34,7 +32,7 @@ public class FlagsTest {
public void testBoolean() {
final boolean defaultValue = false;
FlagSource source = mock(FlagSource.class);
- BooleanFlag booleanFlag = Flags.defineFeatureFlag("id", defaultValue, "description",
+ BooleanFlag booleanFlag = Flags.defineFeatureFlag("id", defaultValue, List.of("owner"), "1970-01-01", "2100-01-01", "description",
"modification effect", FetchVector.Dimension.ZONE_ID, FetchVector.Dimension.HOSTNAME)
.with(FetchVector.Dimension.ZONE_ID, "a-zone")
.bindTo(source);
@@ -69,29 +67,29 @@ public class FlagsTest {
@Test
public void testString() {
- testGeneric(Flags.defineStringFlag("string-id", "default value", "description",
+ testGeneric(Flags.defineStringFlag("string-id", "default value", List.of("owner"), "1970-01-01", "2100-01-01", "description",
"modification effect", FetchVector.Dimension.ZONE_ID, FetchVector.Dimension.HOSTNAME),
"other value");
}
@Test
public void testInt() {
- testGeneric(Flags.defineIntFlag("int-id", 2, "desc", "mod"), 3);
+ testGeneric(Flags.defineIntFlag("int-id", 2, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 3);
}
@Test
public void testLong() {
- testGeneric(Flags.defineLongFlag("long-id", 1L, "desc", "mod"), 2L);
+ testGeneric(Flags.defineLongFlag("long-id", 1L, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 2L);
}
@Test
public void testDouble() {
- testGeneric(Flags.defineDoubleFlag("double-id", 3.142, "desc", "mod"), 2.718);
+ testGeneric(Flags.defineDoubleFlag("double-id", 3.142, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 2.718);
}
@Test
public void testList() {
- testGeneric(Flags.defineListFlag("list-id", List.of("a"), String.class, "desc", "mod"), List.of("a", "b", "c"));
+ testGeneric(Flags.defineListFlag("list-id", List.of("a"), String.class, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), List.of("a", "b", "c"));
}
@Test
@@ -102,23 +100,14 @@ public class FlagsTest {
instance.string = "foo";
testGeneric(Flags.defineJacksonFlag("jackson-id", defaultInstance, ExampleJacksonClass.class,
- "description", "modification effect", FetchVector.Dimension.HOSTNAME),
+ List.of("owner"), "1970-01-01", "2100-01-01", "description", "modification effect", FetchVector.Dimension.HOSTNAME),
instance);
- testGeneric(Flags.defineListFlag("jackson-list-id", List.of(defaultInstance), ExampleJacksonClass.class, "desc", "mod"),
+ testGeneric(Flags.defineListFlag("jackson-list-id", List.of(defaultInstance), ExampleJacksonClass.class, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"),
List.of(instance));
}
- @Test
- public void testSharedHostFlag() {
- SharedHost sharedHost = new SharedHost(List.of(new HostResources(
- 4.0, 16.0, 50.0, null,
- "fast", "local",
- 10)));
- testGeneric(Flags.SHARED_HOST, sharedHost);
- }
-
- private <T> void testGeneric(UnboundFlag<T, ?, ?> unboundFlag, T value) {
+ static <T> void testGeneric(UnboundFlag<T, ?, ?> unboundFlag, T value) {
FlagSource source = mock(FlagSource.class);
Flag<T, ?> flag = unboundFlag.bindTo(source);
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java b/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java
new file mode 100644
index 00000000000..3f43682cfb9
--- /dev/null
+++ b/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java
@@ -0,0 +1,25 @@
+package com.yahoo.vespa.flags;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.yahoo.vespa.flags.custom.HostResources;
+import com.yahoo.vespa.flags.custom.SharedHost;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static com.yahoo.vespa.flags.FlagsTest.testGeneric;
+
+/**
+ * @author bjorncs
+ */
+class PermanentFlagsTest {
+ @Test
+ public void testSharedHostFlag() {
+ SharedHost sharedHost = new SharedHost(List.of(new HostResources(
+ 4.0, 16.0, 50.0, 0.3,
+ "fast", "local",
+ 10)),
+ null);
+ testGeneric(PermanentFlags.SHARED_HOST, sharedHost);
+ }
+
+} \ No newline at end of file
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java b/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java
new file mode 100644
index 00000000000..f0a11f244a4
--- /dev/null
+++ b/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags.custom;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class SharedHostTest {
+ @Test
+ public void serialization() throws IOException {
+ verifySerialization(new SharedHost(List.of(new HostResources(1.0, 2.0, 3.0, 4.0, "fast", "remote", 5)), 6));
+ verifySerialization(new SharedHost(List.of(new HostResources(1.0, 2.0, 3.0, 4.0, "fast", "remote", 5)), null));
+ }
+
+ private void verifySerialization(SharedHost sharedHost) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(sharedHost);
+ SharedHost deserialized = mapper.readValue(json, SharedHost.class);
+ assertEquals(sharedHost, deserialized);
+ }
+} \ No newline at end of file