summaryrefslogtreecommitdiffstats
path: root/config-provisioning/src
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-02-04 09:31:18 +0100
committerMartin Polden <mpolden@mpolden.no>2019-02-04 09:33:19 +0100
commit4cabf81b4078dc5974d37270f1170a92e5ed37b8 (patch)
treeaacb1e26fa47c3b9d64daa3535d2e194fbbe5214 /config-provisioning/src
parent143348b1f6fe210ec8a3a0d22eb07cac56a07825 (diff)
Add rotations to cluster spec
Diffstat (limited to 'config-provisioning/src')
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java36
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java36
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java56
3 files changed, 107 insertions, 21 deletions
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
index 1253496cdd2..c0099878b45 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
@@ -3,9 +3,14 @@ package com.yahoo.config.provision;
import com.yahoo.component.Version;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
/**
* A node's membership in a cluster. This is a value object.
- * The format is "clusterType/clusterId/groupId/index[/exclusive][/retired]
+ * The format is "clusterType/clusterId/groupId/index[/exclusive][/retired][/rotationId,...]"
*
* @author bratseth
*/
@@ -20,18 +25,26 @@ public class ClusterMembership {
private ClusterMembership(String stringValue, Version vespaVersion) {
String[] components = stringValue.split("/");
- if (components.length < 4 || components.length > 6)
+ if (components.length < 4 || components.length > 7)
throw new RuntimeException("Could not parse '" + stringValue + "' to a cluster membership. " +
- "Expected 'clusterType/clusterId/groupId/index[/retired][/exclusive]'");
+ "Expected 'clusterType/clusterId/groupId/index[/retired][/exclusive][/rotationId,...]'");
boolean exclusive = false;
+ Set<RotationName> rotations = Collections.emptySet();
if (components.length > 4) {
- exclusive = components[4].equals("exclusive");
- retired = components[components.length-1].equals("retired");
+ for (int i = 4; i < components.length; i++) {
+ String component = components[i];
+ switch (component) {
+ case "exclusive": exclusive = true; break;
+ case "retired": retired = true; break;
+ default: rotations = rotationsFrom(component); break;
+ }
+ }
}
this.cluster = ClusterSpec.from(ClusterSpec.Type.valueOf(components[0]), ClusterSpec.Id.from(components[1]),
- ClusterSpec.Group.from(Integer.valueOf(components[2])), vespaVersion, exclusive);
+ ClusterSpec.Group.from(Integer.valueOf(components[2])), vespaVersion, exclusive,
+ rotations);
this.index = Integer.parseInt(components[3]);
this.stringValue = toStringValue();
}
@@ -49,7 +62,8 @@ public class ClusterMembership {
(cluster.group().isPresent() ? "/" + cluster.group().get().index() : "") +
"/" + index +
( cluster.isExclusive() ? "/exclusive" : "") +
- ( retired ? "/retired" : "");
+ ( retired ? "/retired" : "") +
+ ( !cluster.rotations().isEmpty() ? "/" + rotationsAsString(cluster.rotations()) : "");
}
@@ -107,4 +121,12 @@ public class ClusterMembership {
return new ClusterMembership(cluster, index, true);
}
+ private static Set<RotationName> rotationsFrom(String s) {
+ return Arrays.stream(s.split(",")).map(RotationName::from).collect(Collectors.toUnmodifiableSet());
+ }
+
+ private static String rotationsAsString(Set<RotationName> rotations) {
+ return rotations.stream().map(RotationName::value).collect(Collectors.joining(","));
+ }
+
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 5c2d41f11be..bd03949191e 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -1,10 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
+import com.google.common.collect.ImmutableSortedSet;
import com.yahoo.component.Version;
+import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
/**
* A specification of a cluster - or group in a grouped cluster - to be run on a set of hosts.
@@ -19,17 +22,21 @@ public final class ClusterSpec {
/** The group id of these hosts, or empty if this is represents a request for hosts */
private final Optional<Group> groupId;
-
private final Version vespaVersion;
-
private boolean exclusive;
+ private final Set<RotationName> rotations;
- private ClusterSpec(Type type, Id id, Optional<Group> groupId, Version vespaVersion, boolean exclusive) {
+ private ClusterSpec(Type type, Id id, Optional<Group> groupId, Version vespaVersion, boolean exclusive,
+ Set<RotationName> rotations) {
+ if (type != Type.container && !rotations.isEmpty()) {
+ throw new IllegalArgumentException("Rotations can only be declared for clusters of type " + Type.container);
+ }
this.type = type;
this.id = id;
this.groupId = groupId;
this.vespaVersion = vespaVersion;
this.exclusive = exclusive;
+ this.rotations = ImmutableSortedSet.copyOf(rotations);
}
/** Returns the cluster type */
@@ -51,20 +58,35 @@ public final class ClusterSpec {
*/
public boolean isExclusive() { return exclusive; }
+ /** Returns the rotations of which this cluster should be a member */
+ public Set<RotationName> rotations() {
+ return rotations;
+ }
+
public ClusterSpec with(Optional<Group> newGroup) {
- return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive);
+ return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, rotations);
}
public ClusterSpec exclusive(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, rotations);
}
+ // TODO: Remove when versions <= 7.6 are gone
public static ClusterSpec request(Type type, Id id, Version vespaVersion, boolean exclusive) {
- return new ClusterSpec(type, id, Optional.empty(), vespaVersion, exclusive);
+ return new ClusterSpec(type, id, Optional.empty(), vespaVersion, exclusive, Collections.emptySet());
}
+ public static ClusterSpec request(Type type, Id id, Version vespaVersion, boolean exclusive, Set<RotationName> rotations) {
+ return new ClusterSpec(type, id, Optional.empty(), vespaVersion, exclusive, rotations);
+ }
+
+ // TODO: Remove when versions <= 7.6 are gone
public static ClusterSpec from(Type type, Id id, Group groupId, Version vespaVersion, boolean exclusive) {
- return new ClusterSpec(type, id, Optional.of(groupId), vespaVersion, exclusive);
+ return from(type, id, groupId, vespaVersion, exclusive, Collections.emptySet());
+ }
+
+ public static ClusterSpec from(Type type, Id id, Group groupId, Version vespaVersion, boolean exclusive, Set<RotationName> rotations) {
+ return new ClusterSpec(type, id, Optional.of(groupId), vespaVersion, exclusive, rotations);
}
@Override
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
index f1970326137..9bd0680b691 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
@@ -1,11 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
-import com.yahoo.component.*;
import com.yahoo.component.Version;
+import com.yahoo.component.Vtag;
import org.junit.Test;
-import java.util.Optional;
+import java.util.Collections;
+import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -18,20 +19,56 @@ public class ClusterMembershipTest {
@Test
public void testContainerServiceInstance() {
- ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false);
+ ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false, Collections.emptySet());
assertContainerService(ClusterMembership.from(cluster, 3));
}
@Test
+ public void testContainerInstanceWithOptionalParts() {
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive/retired", Vtag.currentVersion);
+ assertTrue(instance.retired());
+ assertTrue(instance.cluster().isExclusive());
+ }
+
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive", Vtag.currentVersion);
+ assertFalse(instance.retired());
+ assertTrue(instance.cluster().isExclusive());
+ }
+
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/rotation1,rotation2", Vtag.currentVersion);
+ assertFalse(instance.retired());
+ assertFalse(instance.cluster().isExclusive());
+ assertEquals(Set.of(RotationName.from("rotation1"), RotationName.from("rotation2")), instance.cluster().rotations());
+ }
+
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive/rotation1,rotation2", Vtag.currentVersion);
+ assertFalse(instance.retired());
+ assertTrue(instance.cluster().isExclusive());
+ assertEquals(Set.of(RotationName.from("rotation1"), RotationName.from("rotation2")), instance.cluster().rotations());
+ }
+
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive/retired/rotation1,rotation2", Vtag.currentVersion);
+ assertTrue(instance.retired());
+ assertTrue(instance.cluster().isExclusive());
+ assertEquals(Set.of(RotationName.from("rotation1"), RotationName.from("rotation2")), instance.cluster().rotations());
+ }
+ }
+
+ @Test
public void testServiceInstance() {
- ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false);
+ ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false, Collections.emptySet());
assertContentService(ClusterMembership.from(cluster, 37));
}
@Test
public void testServiceInstanceWithGroup() {
ClusterSpec cluster = ClusterSpec.from(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"),
- ClusterSpec.Group.from(4), Version.fromString("6.42"), false);
+ ClusterSpec.Group.from(4), Version.fromString("6.42"), false, Collections.emptySet());
assertContentServiceWithGroup(ClusterMembership.from(cluster, 37));
}
@@ -42,14 +79,14 @@ public class ClusterMembershipTest {
@Test
public void testServiceInstanceWithRetire() {
- ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false);
+ ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"), Version.fromString("6.42"), false, Collections.emptySet());
assertContentServiceWithRetire(ClusterMembership.retiredFrom(cluster, 37));
}
@Test
public void testServiceInstanceWithGroupAndRetire() {
ClusterSpec cluster = ClusterSpec.from(ClusterSpec.Type.content, ClusterSpec.Id.from("id1"),
- ClusterSpec.Group.from(4), Version.fromString("6.42"), false);
+ ClusterSpec.Group.from(4), Version.fromString("6.42"), false, Collections.emptySet());
assertContentServiceWithGroupAndRetire(ClusterMembership.retiredFrom(cluster, 37));
}
@@ -64,6 +101,7 @@ public class ClusterMembershipTest {
assertFalse(instance.cluster().group().isPresent());
assertEquals(3, instance.index());
assertEquals("container/id1/3", instance.stringValue());
+ assertTrue(instance.cluster().rotations().isEmpty());
}
private void assertContentService(ClusterMembership instance) {
@@ -73,6 +111,7 @@ public class ClusterMembershipTest {
assertEquals(37, instance.index());
assertFalse(instance.retired());
assertEquals("content/id1/37", instance.stringValue());
+ assertTrue(instance.cluster().rotations().isEmpty());
}
private void assertContentServiceWithGroup(ClusterMembership instance) {
@@ -82,6 +121,7 @@ public class ClusterMembershipTest {
assertEquals(37, instance.index());
assertFalse(instance.retired());
assertEquals("content/id1/4/37", instance.stringValue());
+ assertTrue(instance.cluster().rotations().isEmpty());
}
/** Serializing a spec without a group assigned works, but not deserialization */
@@ -91,6 +131,7 @@ public class ClusterMembershipTest {
assertEquals(37, instance.index());
assertTrue(instance.retired());
assertEquals("content/id1/37/retired", instance.stringValue());
+ assertTrue(instance.cluster().rotations().isEmpty());
}
private void assertContentServiceWithGroupAndRetire(ClusterMembership instance) {
@@ -100,6 +141,7 @@ public class ClusterMembershipTest {
assertEquals(37, instance.index());
assertTrue(instance.retired());
assertEquals("content/id1/4/37/retired", instance.stringValue());
+ assertTrue(instance.cluster().rotations().isEmpty());
}
}