Skip to content

Commit ea31483

Browse files
author
Tianli Feng
authored
Add a new node role 'cluster_manager' as the alternative for 'master' role and deprecate 'master' role (#2424)
Add a new node role `cluster_manager`, as the replacement for `master` role, that used in setting `node.roles: [ master ]`. They have got the same functionality, but can NOT be assigned to `node.roles` together. * Add `CLUSTER_MANAGER_ROLE` in `DiscoveryNodeRole` class, and deprecate `MASTER_ROLE` * Remove `MASTER_ROLE` from the `DiscoveryNodeRole.BUILT_IN_ROLES`, and temporarily load the role by the existing method `DiscoveryNode.setAdditionalRoles` * Add a method `validateRole()` in `DiscoveryNodeRole` class, it's used to validate a specific role is compatible with the other roles to be assigned to a node together. * Add deprecation message when assigning `master` role in setting `node.roles` * Replace most `MASTER_ROLE` with `CLUSTER_MANAGER_ROLE` in current unit and integration tests * Add new unit and integration tests to validate `CLUSTER_MANAGER_ROLE` and `MASTER_ROLE` can be treated as the same. More explanation: * New node will have "cluster_manager", "data", and "ingest" roles by default. Which means the default value of setting "node.roles" will be `["cluster_manager","data","ingest"]`, instead of `["master","data","ingest"]` * "cluster_manager" role will be treated as "master" role in the OpenSearch node of previous versions. * "cluster_manager” role and "master" role have got the same abbreviation name: "m" Signed-off-by: Tianli Feng <ftianli@amazon.com>
1 parent 641350b commit ea31483

File tree

52 files changed

+356
-105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+356
-105
lines changed

benchmarks/src/main/java/org/opensearch/benchmark/routing/allocation/Allocators.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public static DiscoveryNode newNode(String nodeId, Map<String, String> attribute
111111
nodeId,
112112
new TransportAddress(TransportAddress.META_ADDRESS, portGenerator.incrementAndGet()),
113113
attributes,
114-
Sets.newHashSet(DiscoveryNodeRole.MASTER_ROLE, DiscoveryNodeRole.DATA_ROLE),
114+
Sets.newHashSet(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE, DiscoveryNodeRole.DATA_ROLE),
115115
Version.CURRENT
116116
);
117117
}

client/rest/src/main/java/org/opensearch/client/Node.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,21 @@ public Roles(final Set<String> roles) {
210210
}
211211

212212
/**
213-
* Teturns whether or not the node <strong>could</strong> be elected master.
213+
* Returns whether or not the node <strong>could</strong> be elected master.
214214
*/
215215
public boolean isMasterEligible() {
216-
return roles.contains("master");
216+
return roles.contains("master") || roles.contains("cluster_manager");
217217
}
218218

219219
/**
220-
* Teturns whether or not the node stores data.
220+
* Returns whether or not the node stores data.
221221
*/
222222
public boolean isData() {
223223
return roles.contains("data");
224224
}
225225

226226
/**
227-
* Teturns whether or not the node runs ingest pipelines.
227+
* Returns whether or not the node runs ingest pipelines.
228228
*/
229229
public boolean isIngest() {
230230
return roles.contains("ingest");

rest-api-spec/src/main/resources/rest-api-spec/test/cluster.stats/10_basic.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,22 @@
9191
cluster.stats: {}
9292

9393
- is_true: nodes.packaging_types
94+
95+
---
96+
"get cluster stats nodes count with both master and cluster_manager":
97+
- skip:
98+
version: " - 1.4.99"
99+
reason: "node role cluster_manager is added in 2.0.0"
100+
101+
- do:
102+
cluster.stats: {}
103+
104+
- set:
105+
nodes.count.cluster_manager: cluster_manager_count
106+
107+
- gte: { nodes.count.total: 1}
108+
- match: { nodes.count.cluster_manager: $cluster_manager_count }
109+
- match: { nodes.count.master: $cluster_manager_count }
110+
- gte: { nodes.count.data: 1}
111+
- gte: { nodes.count.ingest: 0}
112+
- gte: { nodes.count.coordinating_only: 0}

rest-api-spec/src/main/resources/rest-api-spec/test/nodes.info/10_basic.yml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,24 @@ setup:
1212
- is_true: cluster_name
1313

1414
---
15-
"node_info role test":
15+
"node_info role test - before 2.0.0":
1616
- skip:
17-
version: " - 7.7.99"
17+
version: " - 7.7.99 , 2.0.0 - "
1818
reason: "node roles were not sorted before 7.8.0"
19+
features: node_selector
1920

2021
- do:
2122
nodes.info: {}
23+
node_selector:
24+
# Only send request to nodes in <2.0 versions, especially during ':qa:mixed-cluster:v1.x.x#mixedClusterTest'.
25+
# Because YAML REST test takes the minimum OpenSearch version in the cluster to apply the filter in 'skip' section,
26+
# see OpenSearchClientYamlSuiteTestCase#initAndResetContext() for detail.
27+
# During 'mixedClusterTest', the cluster can be mixed with nodes in 1.x and 2.x versions,
28+
# so node_selector is required, and only filtering version in 'skip' is not enough.
29+
version: "1.0.0 - 1.4.99"
30+
2231
- set:
32+
# Note: It will only stash the first node_id in the api response.
2333
nodes._arbitrary_key_: node_id
2434

2535
- is_true: nodes.$node_id.roles
@@ -29,3 +39,21 @@ setup:
2939
- match: { nodes.$node_id.roles.2: "master" }
3040
- match: { nodes.$node_id.roles.3: "remote_cluster_client" }
3141

42+
---
43+
"node_info role test":
44+
- skip:
45+
version: " - 1.4.99"
46+
reason: "node role cluster_manager is added in 2.0.0"
47+
48+
- do:
49+
nodes.info: {}
50+
51+
- set:
52+
nodes._arbitrary_key_: node_id
53+
54+
- is_true: nodes.$node_id.roles
55+
# the roles output is sorted
56+
- match: { nodes.$node_id.roles.0: "cluster_manager" }
57+
- match: { nodes.$node_id.roles.1: "data" }
58+
- match: { nodes.$node_id.roles.2: "ingest" }
59+
- match: { nodes.$node_id.roles.3: "remote_cluster_client" }

server/src/internalClusterTest/java/org/opensearch/action/admin/cluster/stats/ClusterStatsIT.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public void testNodeCounts() {
8585
Map<String, Integer> expectedCounts = new HashMap<>();
8686
expectedCounts.put(DiscoveryNodeRole.DATA_ROLE.roleName(), 1);
8787
expectedCounts.put(DiscoveryNodeRole.MASTER_ROLE.roleName(), 1);
88+
expectedCounts.put(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName(), 1);
8889
expectedCounts.put(DiscoveryNodeRole.INGEST_ROLE.roleName(), 1);
8990
expectedCounts.put(DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE.roleName(), 1);
9091
expectedCounts.put(ClusterStatsNodes.Counts.COORDINATING_ONLY, 0);
@@ -106,7 +107,7 @@ public void testNodeCounts() {
106107
roles.add(DiscoveryNodeRole.INGEST_ROLE);
107108
}
108109
if (isMasterNode) {
109-
roles.add(DiscoveryNodeRole.MASTER_ROLE);
110+
roles.add(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE);
110111
}
111112
if (isRemoteClusterClientNode) {
112113
roles.add(DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE);
@@ -129,6 +130,7 @@ public void testNodeCounts() {
129130
}
130131
if (isMasterNode) {
131132
incrementCountForRole(DiscoveryNodeRole.MASTER_ROLE.roleName(), expectedCounts);
133+
incrementCountForRole(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName(), expectedCounts);
132134
}
133135
if (isRemoteClusterClientNode) {
134136
incrementCountForRole(DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE.roleName(), expectedCounts);

server/src/internalClusterTest/java/org/opensearch/env/NodeEnvironmentIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public Settings onNodeStopped(String nodeName) {
9595
})
9696
);
9797
if (writeDanglingIndices) {
98-
assertThat(ex.getMessage(), startsWith("node does not have the data and master roles but has index metadata"));
98+
assertThat(ex.getMessage(), startsWith("node does not have the data and cluster_manager roles but has index metadata"));
9999
} else {
100100
assertThat(ex.getMessage(), startsWith("node does not have the data role but has shard data"));
101101
}

server/src/main/java/org/opensearch/action/admin/cluster/stats/ClusterStatsNodes.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,14 @@ private Counts(final List<NodeInfo> nodeInfos) {
223223
roles.merge(COORDINATING_ONLY, 1, Integer::sum);
224224
} else {
225225
for (DiscoveryNodeRole role : nodeInfo.getNode().getRoles()) {
226-
roles.merge(role.roleName(), 1, Integer::sum);
226+
// TODO: Remove the 'if' condition and only keep the statement in 'else' after removing MASTER_ROLE.
227+
// As of 2.0, CLUSTER_MANAGER_ROLE is added, and it should be taken as MASTER_ROLE
228+
if (role.isClusterManager()) {
229+
roles.merge(DiscoveryNodeRole.MASTER_ROLE.roleName(), 1, Integer::sum);
230+
roles.merge(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName(), 1, Integer::sum);
231+
} else {
232+
roles.merge(role.roleName(), 1, Integer::sum);
233+
}
227234
}
228235
}
229236
}

server/src/main/java/org/opensearch/cluster/node/DiscoveryNode.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public static boolean hasRole(final Settings settings, final DiscoveryNodeRole r
9494
}
9595

9696
public static boolean isMasterNode(Settings settings) {
97-
return hasRole(settings, DiscoveryNodeRole.MASTER_ROLE);
97+
return hasRole(settings, DiscoveryNodeRole.MASTER_ROLE) || hasRole(settings, DiscoveryNodeRole.CLUSTER_MANAGER_ROLE);
9898
}
9999

100100
/**
@@ -343,7 +343,7 @@ public DiscoveryNode(StreamInput in) throws IOException {
343343
final LegacyRole legacyRole = in.readEnum(LegacyRole.class);
344344
switch (legacyRole) {
345345
case MASTER:
346-
roles.add(DiscoveryNodeRole.MASTER_ROLE);
346+
roles.add(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE);
347347
break;
348348
case DATA:
349349
roles.add(DiscoveryNodeRole.DATA_ROLE);
@@ -390,11 +390,11 @@ public void writeTo(StreamOutput out) throws IOException {
390390
.collect(Collectors.toList());
391391
out.writeVInt(rolesToWrite.size());
392392
for (final DiscoveryNodeRole role : rolesToWrite) {
393-
if (role == DiscoveryNodeRole.MASTER_ROLE) {
393+
if (role.isClusterManager()) {
394394
out.writeEnum(LegacyRole.MASTER);
395-
} else if (role == DiscoveryNodeRole.DATA_ROLE) {
395+
} else if (role.equals(DiscoveryNodeRole.DATA_ROLE)) {
396396
out.writeEnum(LegacyRole.DATA);
397-
} else if (role == DiscoveryNodeRole.INGEST_ROLE) {
397+
} else if (role.equals(DiscoveryNodeRole.INGEST_ROLE)) {
398398
out.writeEnum(LegacyRole.INGEST);
399399
}
400400
}
@@ -456,7 +456,7 @@ public boolean isDataNode() {
456456
* Can this node become master or not.
457457
*/
458458
public boolean isMasterNode() {
459-
return roles.contains(DiscoveryNodeRole.MASTER_ROLE);
459+
return roles.contains(DiscoveryNodeRole.MASTER_ROLE) || roles.contains(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE);
460460
}
461461

462462
/**
@@ -591,15 +591,19 @@ public static void setAdditionalRoles(final Set<DiscoveryNodeRole> additionalRol
591591
+ "], roles by name abbreviation ["
592592
+ roleNameAbbreviationToPossibleRoles
593593
+ "]";
594-
roleMap = roleNameToPossibleRoles;
594+
// TODO: Remove the Map 'roleNameToPossibleRolesWithMaster' and let 'roleMap = roleNameToPossibleRoles', after removing MASTER_ROLE.
595+
// It's used to allow CLUSTER_MANAGER_ROLE that introduced in 2.0, having the same abbreviation name with MASTER_ROLE.
596+
final Map<String, DiscoveryNodeRole> roleNameToPossibleRolesWithMaster = new HashMap<>(roleNameToPossibleRoles);
597+
roleNameToPossibleRolesWithMaster.put(DiscoveryNodeRole.MASTER_ROLE.roleName(), DiscoveryNodeRole.MASTER_ROLE);
598+
roleMap = Collections.unmodifiableMap(roleNameToPossibleRolesWithMaster);
595599
}
596600

597601
public static Set<String> getPossibleRoleNames() {
598602
return roleMap.keySet();
599603
}
600604

601605
/**
602-
* Enum that holds all the possible roles that that a node can fulfill in a cluster.
606+
* Enum that holds all the possible roles that a node can fulfill in a cluster.
603607
* Each role has its name and a corresponding abbreviation used by cat apis.
604608
*/
605609
private enum LegacyRole {

server/src/main/java/org/opensearch/cluster/node/DiscoveryNodeRole.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@
3434

3535
import org.opensearch.LegacyESVersion;
3636
import org.opensearch.Version;
37+
import org.opensearch.common.logging.DeprecationLogger;
3738
import org.opensearch.common.settings.Setting;
3839
import org.opensearch.common.settings.Setting.Property;
3940
import org.opensearch.common.settings.Settings;
4041
import org.opensearch.transport.RemoteClusterService;
4142

4243
import java.util.Arrays;
4344
import java.util.Collections;
45+
import java.util.List;
46+
import java.util.Locale;
4447
import java.util.Objects;
4548
import java.util.SortedSet;
4649
import java.util.TreeSet;
@@ -50,6 +53,10 @@
5053
*/
5154
public abstract class DiscoveryNodeRole implements Comparable<DiscoveryNodeRole> {
5255

56+
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(DiscoveryNodeRole.class);
57+
public static final String MASTER_ROLE_DEPRECATION_MESSAGE =
58+
"Assigning [master] role in setting [node.roles] is deprecated. To promote inclusive language, please use [cluster_manager] role instead.";
59+
5360
private final String roleName;
5461

5562
/**
@@ -129,6 +136,13 @@ public DiscoveryNodeRole getCompatibilityRole(Version nodeVersion) {
129136
return this;
130137
}
131138

139+
/**
140+
* Validate the role is compatible with the other roles in the list, when assigning the list of roles to a node.
141+
* An {@link IllegalArgumentException} is expected to be thrown, if the role can't coexist with the other roles.
142+
* @param roles a {@link List} of {@link DiscoveryNodeRole} that a node is going to have
143+
*/
144+
public void validateRole(List<DiscoveryNodeRole> roles) {};
145+
132146
@Override
133147
public final boolean equals(Object o) {
134148
if (this == o) return true;
@@ -193,15 +207,60 @@ public Setting<Boolean> legacySetting() {
193207

194208
/**
195209
* Represents the role for a master-eligible node.
210+
* @deprecated As of 2.0, because promoting inclusive language, replaced by {@link #CLUSTER_MANAGER_ROLE}
196211
*/
212+
@Deprecated
197213
public static final DiscoveryNodeRole MASTER_ROLE = new DiscoveryNodeRole("master", "m") {
198214

215+
@Override
216+
public Setting<Boolean> legacySetting() {
217+
// copy the setting here so we can mark it private in org.opensearch.node.Node
218+
// As of 2.0, set the default value to 'false', so that MASTER_ROLE isn't added as a default value of NODE_ROLES_SETTING
219+
return Setting.boolSetting("node.master", false, Property.Deprecated, Property.NodeScope);
220+
}
221+
222+
@Override
223+
public void validateRole(List<DiscoveryNodeRole> roles) {
224+
deprecationLogger.deprecate("node_role_master", MASTER_ROLE_DEPRECATION_MESSAGE);
225+
}
226+
227+
};
228+
229+
/**
230+
* Represents the role for a cluster-manager-eligible node.
231+
*/
232+
public static final DiscoveryNodeRole CLUSTER_MANAGER_ROLE = new DiscoveryNodeRole("cluster_manager", "m") {
233+
199234
@Override
200235
public Setting<Boolean> legacySetting() {
201236
// copy the setting here so we can mark it private in org.opensearch.node.Node
202237
return Setting.boolSetting("node.master", true, Property.Deprecated, Property.NodeScope);
203238
}
204239

240+
@Override
241+
public DiscoveryNodeRole getCompatibilityRole(Version nodeVersion) {
242+
if (nodeVersion.onOrAfter(Version.V_2_0_0)) {
243+
return this;
244+
} else {
245+
return DiscoveryNodeRole.MASTER_ROLE;
246+
}
247+
}
248+
249+
@Override
250+
public void validateRole(List<DiscoveryNodeRole> roles) {
251+
if (roles.contains(DiscoveryNodeRole.MASTER_ROLE)) {
252+
throw new IllegalArgumentException(
253+
String.format(
254+
Locale.ROOT,
255+
"The two roles [%s, %s] can not be assigned together to a node. %s",
256+
DiscoveryNodeRole.MASTER_ROLE.roleName(),
257+
DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName(),
258+
MASTER_ROLE_DEPRECATION_MESSAGE
259+
)
260+
);
261+
}
262+
}
263+
205264
};
206265

207266
public static final DiscoveryNodeRole REMOTE_CLUSTER_CLIENT_ROLE = new DiscoveryNodeRole("remote_cluster_client", "r") {
@@ -223,7 +282,7 @@ public Setting<Boolean> legacySetting() {
223282
* The built-in node roles.
224283
*/
225284
public static SortedSet<DiscoveryNodeRole> BUILT_IN_ROLES = Collections.unmodifiableSortedSet(
226-
new TreeSet<>(Arrays.asList(DATA_ROLE, INGEST_ROLE, MASTER_ROLE, REMOTE_CLUSTER_CLIENT_ROLE))
285+
new TreeSet<>(Arrays.asList(DATA_ROLE, INGEST_ROLE, CLUSTER_MANAGER_ROLE, REMOTE_CLUSTER_CLIENT_ROLE))
227286
);
228287

229288
/**
@@ -262,4 +321,13 @@ public Setting<Boolean> legacySetting() {
262321

263322
}
264323

324+
/**
325+
* Check if the role is {@link #CLUSTER_MANAGER_ROLE} or {@link #MASTER_ROLE}.
326+
* @deprecated As of 2.0, because promoting inclusive language. MASTER_ROLE is deprecated.
327+
* @return true if the node role is{@link #CLUSTER_MANAGER_ROLE} or {@link #MASTER_ROLE}
328+
*/
329+
@Deprecated
330+
public boolean isClusterManager() {
331+
return this.equals(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE) || this.equals(DiscoveryNodeRole.MASTER_ROLE);
332+
}
265333
}

server/src/main/java/org/opensearch/cluster/node/DiscoveryNodes.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ public DiscoveryNode resolveNode(String node) {
370370
* Works by tracking the current set of nodes and applying each node specification in sequence. The set starts out empty and each node
371371
* specification may either add or remove nodes. For instance:
372372
*
373-
* - _local, _master and _all respectively add to the subset the local node, the currently-elected master, and all the nodes
373+
* - _local, _cluster_manager (_master) and _all respectively add to the subset the local node, the currently-elected cluster_manager, and all the nodes
374374
* - node IDs, names, hostnames and IP addresses all add to the subset any nodes which match
375375
* - a wildcard-based pattern of the form "attr*:value*" adds to the subset all nodes with a matching attribute with a matching value
376376
* - role:true adds to the subset all nodes with a matching role
@@ -393,7 +393,7 @@ public String[] resolveNodes(String... nodes) {
393393
if (localNodeId != null) {
394394
resolvedNodesIds.add(localNodeId);
395395
}
396-
} else if (nodeId.equals("_master")) {
396+
} else if (nodeId.equals("_master") || nodeId.equals("_cluster_manager")) {
397397
String masterNodeId = getMasterNodeId();
398398
if (masterNodeId != null) {
399399
resolvedNodesIds.add(masterNodeId);
@@ -419,7 +419,7 @@ public String[] resolveNodes(String... nodes) {
419419
} else {
420420
resolvedNodesIds.removeAll(dataNodes.keys());
421421
}
422-
} else if (DiscoveryNodeRole.MASTER_ROLE.roleName().equals(matchAttrName)) {
422+
} else if (roleNameIsClusterManager(matchAttrName)) {
423423
if (Booleans.parseBoolean(matchAttrValue, true)) {
424424
resolvedNodesIds.addAll(masterNodes.keys());
425425
} else {
@@ -797,4 +797,17 @@ public boolean isLocalNodeElectedMaster() {
797797
return masterNodeId != null && masterNodeId.equals(localNodeId);
798798
}
799799
}
800+
801+
/**
802+
* Check if the given name of the node role is 'cluster_manger' or 'master'.
803+
* The method is added for {@link #resolveNodes} to keep the code clear, when support the both above roles.
804+
* @deprecated As of 2.0, because promoting inclusive language. MASTER_ROLE is deprecated.
805+
* @param matchAttrName a given String for a name of the node role.
806+
* @return true if the given roleName is 'cluster_manger' or 'master'
807+
*/
808+
@Deprecated
809+
private boolean roleNameIsClusterManager(String matchAttrName) {
810+
return DiscoveryNodeRole.MASTER_ROLE.roleName().equals(matchAttrName)
811+
|| DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName().equals(matchAttrName);
812+
}
800813
}

0 commit comments

Comments
 (0)