diff options
author | Martin Polden <mpolden@mpolden.no> | 2018-11-27 14:14:21 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2018-11-27 14:40:00 +0100 |
commit | b084bc71e5c921698a27157333cf9ac0c7aa09be (patch) | |
tree | 0e421e6a2b634737e32d2f3c15777897df14e3eb /node-repository/src/test | |
parent | e12e2d54042b2aeca632ee630f0d67695dfb2f1b (diff) |
Support feature flags in node repository
This implements feature flags for the node repository. A feature flag can be
toggled on/off for the following dimensions:
1) The node repository (entire zone)
2) A specific node
3) A specific application
Flags must be declared in the `FlagId` enum, this is typically done when
implementing the feature that should be guarded by a flag.
Flag status is stored in ZooKeeper. Inspecting and toggling flag status is done
through a REST API, see `RestApiTest#test_flags()`.
Diffstat (limited to 'node-repository/src/test')
5 files changed, 159 insertions, 0 deletions
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/flag/FlagsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/flag/FlagsTest.java new file mode 100644 index 00000000000..5018b18c491 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/flag/FlagsTest.java @@ -0,0 +1,64 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.flag; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.HostName; +import com.yahoo.vespa.curator.mock.MockCurator; +import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors; +import com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository; +import org.junit.Test; + +import java.util.function.Supplier; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author mpolden + */ +public class FlagsTest { + + @Test + public void test_flag_toggling() { + NodeRepository nodeRepository = new MockNodeRepository(new MockCurator(), new MockNodeFlavors()); + Flags flags = nodeRepository.flags(); + Supplier<Flag> flag = () -> flags.get(FlagId.exclusiveLoadBalancer); + + // Flag is disabled by default + assertFalse(flag.get().isEnabled()); + + // Toggle flag for a node + { + HostName node1 = HostName.from("host1"); + flags.setEnabled(FlagId.exclusiveLoadBalancer, node1, true); + assertTrue(flag.get().isEnabled(node1)); + assertFalse(flag.get().isEnabled()); + flags.setEnabled(FlagId.exclusiveLoadBalancer, node1, false); + assertFalse(flag.get().isEnabled(node1)); + } + + // Toggle flag for an application + { + ApplicationId app1 = ApplicationId.from("tenant1", "application1", "default"); + flags.setEnabled(FlagId.exclusiveLoadBalancer, app1, true); + assertTrue(flag.get().isEnabled(app1)); + assertFalse(flag.get().isEnabled()); + flags.setEnabled(FlagId.exclusiveLoadBalancer, app1, false); + assertFalse(flag.get().isEnabled(app1)); + } + + // Toggle flag globally + { + flags.setEnabled(FlagId.exclusiveLoadBalancer, true); + assertTrue(flag.get().isEnabled()); + // Flag is implicitly enabled for all dimensions + assertTrue(flag.get().isEnabled(HostName.from("host1"))); + assertTrue(flag.get().isEnabled(ApplicationId.from("tenant1", "application1", "default"))); + flags.setEnabled(FlagId.exclusiveLoadBalancer, false); + assertFalse(flag.get().isEnabled()); + } + } + + +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/FlagSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/FlagSerializerTest.java new file mode 100644 index 00000000000..15f2289d340 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/FlagSerializerTest.java @@ -0,0 +1,33 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.provision.persistence; + +import com.google.common.collect.ImmutableSet; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.vespa.hosted.provision.flag.Flag; +import com.yahoo.vespa.hosted.provision.flag.FlagId; +import org.junit.Test; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + +/** + * @author mpolden + */ +public class FlagSerializerTest { + + @Test + public void test_serialization() { + Flag flag = new Flag(FlagId.exclusiveLoadBalancer, true, + ImmutableSet.of("host1", "host2"), + Collections.singleton( + ApplicationId.from("tenant1", "application1", "default") + )); + Flag serialized = FlagSerializer.fromJson(FlagSerializer.toJson(flag)); + assertEquals(flag.id(), serialized.id()); + assertEquals(flag.isEnabled(), serialized.isEnabled()); + assertEquals(flag.hostnames(), serialized.hostnames()); + assertEquals(flag.applications(), serialized.applications()); + } + +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java index 2ff1e403e35..ae7f3f14975 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java @@ -659,6 +659,44 @@ public class RestApiTest { "]}"); } + @Test + public void test_flags() throws Exception { + assertFile(new Request("http://localhost:8080/nodes/v2/flags/"), "flags1.json"); + + // Enable flag for application + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer/application/foo:bar:default", + new byte[0], Request.Method.POST), + "{\"message\":\"Enabled feature exclusiveLoadBalancer for application 'foo:bar:default'\"}"); + + // Enable flag for node + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer/node/host1", + new byte[0], Request.Method.POST), + "{\"message\":\"Enabled feature exclusiveLoadBalancer for node 'host1'\"}"); + + assertFile(new Request("http://localhost:8080/nodes/v2/flags/"), "flags2.json"); + + // Enable flag for entire repository + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer", + new byte[0], Request.Method.POST), + "{\"message\":\"Enabled feature exclusiveLoadBalancer\"}"); + + // Disable flag for application + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer/application/foo:bar:default", + new byte[0], Request.Method.DELETE), + "{\"message\":\"Disabled feature exclusiveLoadBalancer for application 'foo:bar:default'\"}"); + + // Disable flag for node + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer/node/host1", + new byte[0], Request.Method.DELETE), + "{\"message\":\"Disabled feature exclusiveLoadBalancer for node 'host1'\"}"); + + // Disable flag for entire repository + assertResponse(new Request("http://localhost:8080/nodes/v2/flags/exclusive-load-balancer", + new byte[0], Request.Method.DELETE), + "{\"message\":\"Disabled feature exclusiveLoadBalancer\"}"); + + } + /** Tests the rendering of each node separately to make it easier to find errors */ @Test public void test_single_node_rendering() throws Exception { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json new file mode 100644 index 00000000000..8fd09b4a274 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json @@ -0,0 +1,10 @@ +{ + "flags": [ + { + "id": "exclusive-load-balancer", + "enabled": false, + "enabledHostnames": [], + "enabledApplications": [] + } + ] +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json new file mode 100644 index 00000000000..78de52e4e85 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json @@ -0,0 +1,14 @@ +{ + "flags": [ + { + "id": "exclusive-load-balancer", + "enabled": false, + "enabledHostnames": [ + "host1" + ], + "enabledApplications": [ + "foo:bar:default" + ] + } + ] +} |