Skip to content

Commit ed69b7b

Browse files
arteamjfreden
authored andcommitted
Revert "Don't return or accept node_version in the Desired Nodes API (elastic#114580)" (elastic#115829)
This reverts commit c64226c.
1 parent d0b1a4a commit ed69b7b

File tree

6 files changed

+191
-13
lines changed

6 files changed

+191
-13
lines changed

qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/DesiredNodesUpgradeIT.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.carrotsearch.randomizedtesting.annotations.Name;
1313

14+
import org.elasticsearch.Build;
1415
import org.elasticsearch.action.admin.cluster.desirednodes.UpdateDesiredNodesRequest;
1516
import org.elasticsearch.client.Request;
1617
import org.elasticsearch.client.ResponseException;
@@ -81,7 +82,8 @@ private void assertDesiredNodesUpdatedWithRoundedUpFloatsAreIdempotent() throws
8182
Settings.builder().put(NODE_NAME_SETTING.getKey(), nodeName).build(),
8283
1238.49922909,
8384
ByteSizeValue.ofGb(32),
84-
ByteSizeValue.ofGb(128)
85+
ByteSizeValue.ofGb(128),
86+
clusterHasFeature(DesiredNode.DESIRED_NODE_VERSION_DEPRECATED) ? null : Build.current().version()
8587
)
8688
)
8789
.toList();
@@ -151,7 +153,8 @@ private void addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges(int ve
151153
Settings.builder().put(NODE_NAME_SETTING.getKey(), nodeName).build(),
152154
processorsPrecision == ProcessorsPrecision.DOUBLE ? randomDoubleProcessorCount() : 0.5f,
153155
ByteSizeValue.ofGb(randomIntBetween(10, 24)),
154-
ByteSizeValue.ofGb(randomIntBetween(128, 256))
156+
ByteSizeValue.ofGb(randomIntBetween(128, 256)),
157+
clusterHasFeature(DesiredNode.DESIRED_NODE_VERSION_DEPRECATED) ? null : Build.current().version()
155158
)
156159
)
157160
.toList();
@@ -164,7 +167,8 @@ private void addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges(int ve
164167
Settings.builder().put(NODE_NAME_SETTING.getKey(), nodeName).build(),
165168
new DesiredNode.ProcessorsRange(minProcessors, minProcessors + randomIntBetween(10, 20)),
166169
ByteSizeValue.ofGb(randomIntBetween(10, 24)),
167-
ByteSizeValue.ofGb(randomIntBetween(128, 256))
170+
ByteSizeValue.ofGb(randomIntBetween(128, 256)),
171+
clusterHasFeature(DesiredNode.DESIRED_NODE_VERSION_DEPRECATED) ? null : Build.current().version()
168172
);
169173
}).toList();
170174
}
@@ -178,7 +182,8 @@ private void addClusterNodesToDesiredNodesWithIntegerProcessors(int version) thr
178182
Settings.builder().put(NODE_NAME_SETTING.getKey(), nodeName).build(),
179183
randomIntBetween(1, 24),
180184
ByteSizeValue.ofGb(randomIntBetween(10, 24)),
181-
ByteSizeValue.ofGb(randomIntBetween(128, 256))
185+
ByteSizeValue.ofGb(randomIntBetween(128, 256)),
186+
clusterHasFeature(DesiredNode.DESIRED_NODE_VERSION_DEPRECATED) ? null : Build.current().version()
182187
)
183188
)
184189
.toList();

rest-api-spec/build.gradle

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,4 @@ tasks.named("yamlRestCompatTestTransform").configure ({ task ->
6161
task.skipTest("search/330_fetch_fields/Test search rewrite", "warning does not exist for compatibility")
6262
task.skipTest("indices.create/21_synthetic_source_stored/object param - nested object with stored array", "temporary until backported")
6363
task.skipTest("cat.aliases/10_basic/Deprecated local parameter", "CAT APIs not covered by compatibility policy")
64-
task.skipTest("cluster.desired_nodes/10_basic/Test delete desired nodes with node_version generates a warning", "node_version warning is removed in 9.0")
65-
task.skipTest("cluster.desired_nodes/10_basic/Test update desired nodes with node_version generates a warning", "node_version warning is removed in 9.0")
6664
})

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/cluster.desired_nodes/10_basic.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,61 @@ teardown:
5959
- contains: { nodes: { settings: { node: { name: "instance-000187" } }, processors: 8.5, memory: "64gb", storage: "128gb" } }
6060
- contains: { nodes: { settings: { node: { name: "instance-000188" } }, processors: 16.0, memory: "128gb", storage: "1tb" } }
6161
---
62+
"Test update desired nodes with node_version generates a warning":
63+
- skip:
64+
reason: "contains is a newly added assertion"
65+
features: ["contains", "allowed_warnings"]
66+
- do:
67+
cluster.state: {}
68+
69+
# Get master node id
70+
- set: { master_node: master }
71+
72+
- do:
73+
nodes.info: {}
74+
- set: { nodes.$master.version: es_version }
75+
76+
- do:
77+
_internal.update_desired_nodes:
78+
history_id: "test"
79+
version: 1
80+
body:
81+
nodes:
82+
- { settings: { "node.name": "instance-000187" }, processors: 8.5, memory: "64gb", storage: "128gb", node_version: $es_version }
83+
allowed_warnings:
84+
- "[version removal] Specifying node_version in desired nodes requests is deprecated."
85+
- match: { replaced_existing_history_id: false }
86+
87+
- do:
88+
_internal.get_desired_nodes: {}
89+
- match:
90+
$body:
91+
history_id: "test"
92+
version: 1
93+
nodes:
94+
- { settings: { node: { name: "instance-000187" } }, processors: 8.5, memory: "64gb", storage: "128gb", node_version: $es_version }
95+
96+
- do:
97+
_internal.update_desired_nodes:
98+
history_id: "test"
99+
version: 2
100+
body:
101+
nodes:
102+
- { settings: { "node.name": "instance-000187" }, processors: 8.5, memory: "64gb", storage: "128gb", node_version: $es_version }
103+
- { settings: { "node.name": "instance-000188" }, processors: 16.0, memory: "128gb", storage: "1tb", node_version: $es_version }
104+
allowed_warnings:
105+
- "[version removal] Specifying node_version in desired nodes requests is deprecated."
106+
- match: { replaced_existing_history_id: false }
107+
108+
- do:
109+
_internal.get_desired_nodes: {}
110+
111+
- match: { history_id: "test" }
112+
- match: { version: 2 }
113+
- length: { nodes: 2 }
114+
- contains: { nodes: { settings: { node: { name: "instance-000187" } }, processors: 8.5, memory: "64gb", storage: "128gb", node_version: $es_version } }
115+
- contains: { nodes: { settings: { node: { name: "instance-000188" } }, processors: 16.0, memory: "128gb", storage: "1tb", node_version: $es_version } }
116+
---
62117
"Test update move to a new history id":
63118
- skip:
64119
reason: "contains is a newly added assertion"
@@ -144,6 +199,46 @@ teardown:
144199
_internal.get_desired_nodes: {}
145200
- match: { status: 404 }
146201
---
202+
"Test delete desired nodes with node_version generates a warning":
203+
- skip:
204+
features: allowed_warnings
205+
- do:
206+
cluster.state: {}
207+
208+
- set: { master_node: master }
209+
210+
- do:
211+
nodes.info: {}
212+
- set: { nodes.$master.version: es_version }
213+
214+
- do:
215+
_internal.update_desired_nodes:
216+
history_id: "test"
217+
version: 1
218+
body:
219+
nodes:
220+
- { settings: { "node.external_id": "instance-000187" }, processors: 8.0, memory: "64gb", storage: "128gb", node_version: $es_version }
221+
allowed_warnings:
222+
- "[version removal] Specifying node_version in desired nodes requests is deprecated."
223+
- match: { replaced_existing_history_id: false }
224+
225+
- do:
226+
_internal.get_desired_nodes: {}
227+
- match:
228+
$body:
229+
history_id: "test"
230+
version: 1
231+
nodes:
232+
- { settings: { node: { external_id: "instance-000187" } }, processors: 8.0, memory: "64gb", storage: "128gb", node_version: $es_version }
233+
234+
- do:
235+
_internal.delete_desired_nodes: {}
236+
237+
- do:
238+
catch: missing
239+
_internal.get_desired_nodes: {}
240+
- match: { status: 404 }
241+
---
147242
"Test update desired nodes is idempotent":
148243
- skip:
149244
reason: "contains is a newly added assertion"

server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNode.java

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
import org.elasticsearch.Version;
1515
import org.elasticsearch.cluster.node.DiscoveryNode;
1616
import org.elasticsearch.cluster.node.DiscoveryNodeRole;
17+
import org.elasticsearch.common.Strings;
1718
import org.elasticsearch.common.io.stream.StreamInput;
1819
import org.elasticsearch.common.io.stream.StreamOutput;
1920
import org.elasticsearch.common.io.stream.Writeable;
2021
import org.elasticsearch.common.settings.Settings;
2122
import org.elasticsearch.common.unit.ByteSizeValue;
2223
import org.elasticsearch.common.unit.Processors;
2324
import org.elasticsearch.core.Nullable;
25+
import org.elasticsearch.core.UpdateForV9;
2426
import org.elasticsearch.features.NodeFeature;
2527
import org.elasticsearch.xcontent.ConstructingObjectParser;
2628
import org.elasticsearch.xcontent.ObjectParser;
@@ -36,6 +38,7 @@
3638
import java.util.Set;
3739
import java.util.TreeSet;
3840
import java.util.function.Predicate;
41+
import java.util.regex.Pattern;
3942

4043
import static java.lang.String.format;
4144
import static org.elasticsearch.node.Node.NODE_EXTERNAL_ID_SETTING;
@@ -55,6 +58,8 @@ public final class DesiredNode implements Writeable, ToXContentObject, Comparabl
5558
private static final ParseField PROCESSORS_RANGE_FIELD = new ParseField("processors_range");
5659
private static final ParseField MEMORY_FIELD = new ParseField("memory");
5760
private static final ParseField STORAGE_FIELD = new ParseField("storage");
61+
@UpdateForV9(owner = UpdateForV9.Owner.DISTRIBUTED_COORDINATION) // Remove deprecated field
62+
private static final ParseField VERSION_FIELD = new ParseField("node_version");
5863

5964
public static final ConstructingObjectParser<DesiredNode, Void> PARSER = new ConstructingObjectParser<>(
6065
"desired_node",
@@ -64,7 +69,8 @@ public final class DesiredNode implements Writeable, ToXContentObject, Comparabl
6469
(Processors) args[1],
6570
(ProcessorsRange) args[2],
6671
(ByteSizeValue) args[3],
67-
(ByteSizeValue) args[4]
72+
(ByteSizeValue) args[4],
73+
(String) args[5]
6874
)
6975
);
7076

@@ -98,6 +104,12 @@ static <T> void configureParser(ConstructingObjectParser<T, Void> parser) {
98104
STORAGE_FIELD,
99105
ObjectParser.ValueType.STRING
100106
);
107+
parser.declareField(
108+
ConstructingObjectParser.optionalConstructorArg(),
109+
(p, c) -> p.text(),
110+
VERSION_FIELD,
111+
ObjectParser.ValueType.STRING
112+
);
101113
}
102114

103115
private final Settings settings;
@@ -106,9 +118,21 @@ static <T> void configureParser(ConstructingObjectParser<T, Void> parser) {
106118
private final ByteSizeValue memory;
107119
private final ByteSizeValue storage;
108120

121+
@UpdateForV9(owner = UpdateForV9.Owner.DISTRIBUTED_COORDINATION) // Remove deprecated version field
122+
private final String version;
109123
private final String externalId;
110124
private final Set<DiscoveryNodeRole> roles;
111125

126+
@Deprecated
127+
public DesiredNode(Settings settings, ProcessorsRange processorsRange, ByteSizeValue memory, ByteSizeValue storage, String version) {
128+
this(settings, null, processorsRange, memory, storage, version);
129+
}
130+
131+
@Deprecated
132+
public DesiredNode(Settings settings, double processors, ByteSizeValue memory, ByteSizeValue storage, String version) {
133+
this(settings, Processors.of(processors), null, memory, storage, version);
134+
}
135+
112136
public DesiredNode(Settings settings, ProcessorsRange processorsRange, ByteSizeValue memory, ByteSizeValue storage) {
113137
this(settings, null, processorsRange, memory, storage);
114138
}
@@ -118,6 +142,17 @@ public DesiredNode(Settings settings, double processors, ByteSizeValue memory, B
118142
}
119143

120144
DesiredNode(Settings settings, Processors processors, ProcessorsRange processorsRange, ByteSizeValue memory, ByteSizeValue storage) {
145+
this(settings, processors, processorsRange, memory, storage, null);
146+
}
147+
148+
DesiredNode(
149+
Settings settings,
150+
Processors processors,
151+
ProcessorsRange processorsRange,
152+
ByteSizeValue memory,
153+
ByteSizeValue storage,
154+
@Deprecated String version
155+
) {
121156
assert settings != null;
122157
assert memory != null;
123158
assert storage != null;
@@ -151,6 +186,7 @@ public DesiredNode(Settings settings, double processors, ByteSizeValue memory, B
151186
this.processorsRange = processorsRange;
152187
this.memory = memory;
153188
this.storage = storage;
189+
this.version = version;
154190
this.externalId = NODE_EXTERNAL_ID_SETTING.get(settings);
155191
this.roles = Collections.unmodifiableSortedSet(new TreeSet<>(DiscoveryNode.getRolesFromSettings(settings)));
156192
}
@@ -174,7 +210,19 @@ public static DesiredNode readFrom(StreamInput in) throws IOException {
174210
} else {
175211
version = Version.readVersion(in).toString();
176212
}
177-
return new DesiredNode(settings, processors, processorsRange, memory, storage);
213+
return new DesiredNode(settings, processors, processorsRange, memory, storage, version);
214+
}
215+
216+
private static final Pattern SEMANTIC_VERSION_PATTERN = Pattern.compile("^(\\d+\\.\\d+\\.\\d+)\\D?.*");
217+
218+
private static Version parseLegacyVersion(String version) {
219+
if (version != null) {
220+
var semanticVersionMatcher = SEMANTIC_VERSION_PATTERN.matcher(version);
221+
if (semanticVersionMatcher.matches()) {
222+
return Version.fromString(semanticVersionMatcher.group(1));
223+
}
224+
}
225+
return null;
178226
}
179227

180228
@Override
@@ -191,9 +239,15 @@ public void writeTo(StreamOutput out) throws IOException {
191239
memory.writeTo(out);
192240
storage.writeTo(out);
193241
if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_13_0)) {
194-
out.writeOptionalString(null);
242+
out.writeOptionalString(version);
195243
} else {
196-
Version.writeVersion(Version.CURRENT, out);
244+
Version parsedVersion = parseLegacyVersion(version);
245+
if (version == null) {
246+
// Some node is from before we made the version field not required. If so, fill in with the current node version.
247+
Version.writeVersion(Version.CURRENT, out);
248+
} else {
249+
Version.writeVersion(parsedVersion, out);
250+
}
197251
}
198252
}
199253

@@ -221,6 +275,14 @@ public void toInnerXContent(XContentBuilder builder, Params params) throws IOExc
221275
}
222276
builder.field(MEMORY_FIELD.getPreferredName(), memory);
223277
builder.field(STORAGE_FIELD.getPreferredName(), storage);
278+
addDeprecatedVersionField(builder);
279+
}
280+
281+
@UpdateForV9(owner = UpdateForV9.Owner.DISTRIBUTED_COORDINATION) // Remove deprecated field from response
282+
private void addDeprecatedVersionField(XContentBuilder builder) throws IOException {
283+
if (version != null) {
284+
builder.field(VERSION_FIELD.getPreferredName(), version);
285+
}
224286
}
225287

226288
public boolean hasMasterRole() {
@@ -304,6 +366,7 @@ private boolean equalsWithoutProcessorsSpecification(DesiredNode that) {
304366
return Objects.equals(settings, that.settings)
305367
&& Objects.equals(memory, that.memory)
306368
&& Objects.equals(storage, that.storage)
369+
&& Objects.equals(version, that.version)
307370
&& Objects.equals(externalId, that.externalId)
308371
&& Objects.equals(roles, that.roles);
309372
}
@@ -316,7 +379,7 @@ public boolean equalsWithProcessorsCloseTo(DesiredNode that) {
316379

317380
@Override
318381
public int hashCode() {
319-
return Objects.hash(settings, processors, processorsRange, memory, storage, externalId, roles);
382+
return Objects.hash(settings, processors, processorsRange, memory, storage, version, externalId, roles);
320383
}
321384

322385
@Override
@@ -345,6 +408,10 @@ public String toString() {
345408
+ '}';
346409
}
347410

411+
public boolean hasVersion() {
412+
return Strings.isNullOrBlank(version) == false;
413+
}
414+
348415
public record ProcessorsRange(Processors min, @Nullable Processors max) implements Writeable, ToXContentObject {
349416

350417
private static final ParseField MIN_FIELD = new ParseField("min");

server/src/main/java/org/elasticsearch/cluster/metadata/DesiredNodeWithStatus.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ public record DesiredNodeWithStatus(DesiredNode desiredNode, Status status)
4444
(Processors) args[1],
4545
(DesiredNode.ProcessorsRange) args[2],
4646
(ByteSizeValue) args[3],
47-
(ByteSizeValue) args[4]
47+
(ByteSizeValue) args[4],
48+
(String) args[5]
4849
),
4950
// An unknown status is expected during upgrades to versions >= STATUS_TRACKING_SUPPORT_VERSION
5051
// the desired node status would be populated when a node in the newer version is elected as
5152
// master, the desired nodes status update happens in NodeJoinExecutor.
52-
args[5] == null ? Status.PENDING : (Status) args[5]
53+
args[6] == null ? Status.PENDING : (Status) args[6]
5354
)
5455
);
5556

server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestUpdateDesiredNodesAction.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
import org.elasticsearch.action.admin.cluster.desirednodes.UpdateDesiredNodesAction;
1313
import org.elasticsearch.action.admin.cluster.desirednodes.UpdateDesiredNodesRequest;
1414
import org.elasticsearch.client.internal.node.NodeClient;
15+
import org.elasticsearch.cluster.metadata.DesiredNode;
1516
import org.elasticsearch.common.logging.DeprecationLogger;
1617
import org.elasticsearch.features.NodeFeature;
1718
import org.elasticsearch.rest.BaseRestHandler;
1819
import org.elasticsearch.rest.RestRequest;
1920
import org.elasticsearch.rest.action.RestToXContentListener;
21+
import org.elasticsearch.xcontent.XContentParseException;
2022
import org.elasticsearch.xcontent.XContentParser;
2123

2224
import java.io.IOException;
@@ -65,6 +67,16 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
6567
);
6668
}
6769

70+
if (clusterSupportsFeature.test(DesiredNode.DESIRED_NODE_VERSION_DEPRECATED)) {
71+
if (updateDesiredNodesRequest.getNodes().stream().anyMatch(DesiredNode::hasVersion)) {
72+
deprecationLogger.compatibleCritical("desired_nodes_version", VERSION_DEPRECATION_MESSAGE);
73+
}
74+
} else {
75+
if (updateDesiredNodesRequest.getNodes().stream().anyMatch(n -> n.hasVersion() == false)) {
76+
throw new XContentParseException("[node_version] field is required and must have a valid value");
77+
}
78+
}
79+
6880
return restChannel -> client.execute(
6981
UpdateDesiredNodesAction.INSTANCE,
7082
updateDesiredNodesRequest,

0 commit comments

Comments
 (0)