1717import org .elasticsearch .common .Strings ;
1818import org .elasticsearch .common .settings .Settings ;
1919import org .elasticsearch .common .unit .ByteSizeValue ;
20+ import org .elasticsearch .common .unit .Processors ;
2021import org .elasticsearch .common .xcontent .support .XContentMapValues ;
2122import org .elasticsearch .xcontent .json .JsonXContent ;
2223
3132import static org .hamcrest .Matchers .is ;
3233
3334public class DesiredNodesUpgradeIT extends AbstractRollingTestCase {
35+ private enum ProcessorsPrecision {
36+ DOUBLE ,
37+ FLOAT
38+ }
39+
3440 public void testUpgradeDesiredNodes () throws Exception {
3541 // Desired nodes was introduced in 8.1
3642 if (UPGRADE_FROM_VERSION .before (Version .V_8_1_0 )) {
3743 return ;
3844 }
3945
46+ if (UPGRADE_FROM_VERSION .onOrAfter (Processors .DOUBLE_PROCESSORS_SUPPORT_VERSION )) {
47+ assertUpgradedNodesCanReadDesiredNodes ();
48+ } else if (UPGRADE_FROM_VERSION .onOrAfter (DesiredNode .RANGE_FLOAT_PROCESSORS_SUPPORT_VERSION )) {
49+ assertDesiredNodesUpdatedWithRoundedUpFloatsAreIdempotent ();
50+ } else {
51+ assertDesiredNodesWithFloatProcessorsAreRejectedInOlderVersions ();
52+ }
53+ }
54+
55+ private void assertUpgradedNodesCanReadDesiredNodes () throws Exception {
56+ final int desiredNodesVersion = switch (CLUSTER_TYPE ) {
57+ case OLD -> 1 ;
58+ case MIXED -> FIRST_MIXED_ROUND ? 2 : 3 ;
59+ case UPGRADED -> 4 ;
60+ };
61+
62+ if (CLUSTER_TYPE != ClusterType .OLD ) {
63+ final Map <String , Object > desiredNodes = getLatestDesiredNodes ();
64+ final String historyId = extractValue (desiredNodes , "history_id" );
65+ final int version = extractValue (desiredNodes , "version" );
66+ assertThat (historyId , is (equalTo ("upgrade_test" )));
67+ assertThat (version , is (equalTo (desiredNodesVersion - 1 )));
68+ }
69+
70+ addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges (desiredNodesVersion , ProcessorsPrecision .DOUBLE );
71+ assertAllDesiredNodesAreActualized ();
72+ }
73+
74+ private void assertDesiredNodesUpdatedWithRoundedUpFloatsAreIdempotent () throws Exception {
75+ // We define the same set of desired nodes to ensure that they are equal across all
76+ // the test runs, otherwise we cannot guarantee an idempotent update in this test
77+ final var desiredNodes = getNodeNames ().stream ()
78+ .map (
79+ nodeName -> new DesiredNode (
80+ Settings .builder ().put (NODE_NAME_SETTING .getKey (), nodeName ).build (),
81+ 1238.49922909 ,
82+ ByteSizeValue .ofGb (32 ),
83+ ByteSizeValue .ofGb (128 ),
84+ Version .CURRENT
85+ )
86+ )
87+ .toList ();
88+
89+ final int desiredNodesVersion = switch (CLUSTER_TYPE ) {
90+ case OLD -> 1 ;
91+ case MIXED -> FIRST_MIXED_ROUND ? 2 : 3 ;
92+ case UPGRADED -> 4 ;
93+ };
94+
95+ if (CLUSTER_TYPE != ClusterType .OLD ) {
96+ updateDesiredNodes (desiredNodes , desiredNodesVersion - 1 );
97+ }
98+ for (int i = 0 ; i < 2 ; i ++) {
99+ updateDesiredNodes (desiredNodes , desiredNodesVersion );
100+ }
101+
102+ final Map <String , Object > latestDesiredNodes = getLatestDesiredNodes ();
103+ final int latestDesiredNodesVersion = extractValue (latestDesiredNodes , "version" );
104+ assertThat (latestDesiredNodesVersion , is (equalTo (desiredNodesVersion )));
105+
106+ if (CLUSTER_TYPE == ClusterType .UPGRADED ) {
107+ assertAllDesiredNodesAreActualized ();
108+ }
109+ }
110+
111+ private void assertDesiredNodesWithFloatProcessorsAreRejectedInOlderVersions () throws Exception {
40112 switch (CLUSTER_TYPE ) {
41113 case OLD -> addClusterNodesToDesiredNodesWithIntegerProcessors (1 );
42114 case MIXED -> {
43115 int version = FIRST_MIXED_ROUND ? 2 : 3 ;
44- if (UPGRADE_FROM_VERSION .onOrAfter (DesiredNode .RANGE_FLOAT_PROCESSORS_SUPPORT_VERSION )) {
45- addClusterNodesToDesiredNodesWithFloatProcessorsOrProcessorRanges (version );
46- } else {
47- // Processor ranges or float processors are forbidden during upgrades: 8.2 -> 8.3 clusters
48- final var responseException = expectThrows (
49- ResponseException .class ,
50- () -> addClusterNodesToDesiredNodesWithFloatProcessorsOrProcessorRanges (version )
51- );
52- final var statusCode = responseException .getResponse ().getStatusLine ().getStatusCode ();
53- assertThat (statusCode , is (equalTo (400 )));
54- }
116+ // Processor ranges or float processors are forbidden during upgrades: 8.2 -> 8.3 clusters
117+ final var responseException = expectThrows (
118+ ResponseException .class ,
119+ () -> addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges (version , ProcessorsPrecision .FLOAT )
120+ );
121+ final var statusCode = responseException .getResponse ().getStatusLine ().getStatusCode ();
122+ assertThat (statusCode , is (equalTo (400 )));
55123 }
56124 case UPGRADED -> {
57125 assertAllDesiredNodesAreActualized ();
58- addClusterNodesToDesiredNodesWithFloatProcessorsOrProcessorRanges ( 4 );
126+ addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges ( 4 , ProcessorsPrecision . FLOAT );
59127 }
60128 }
61129
130+ getLatestDesiredNodes ();
131+ }
132+
133+ private Map <String , Object > getLatestDesiredNodes () throws IOException {
62134 final var getDesiredNodesRequest = new Request ("GET" , "/_internal/desired_nodes/_latest" );
63135 final var response = client ().performRequest (getDesiredNodesRequest );
64136 assertThat (response .getStatusLine ().getStatusCode (), is (equalTo (200 )));
137+ return responseAsMap (response );
65138 }
66139
67140 private void assertAllDesiredNodesAreActualized () throws Exception {
@@ -77,32 +150,34 @@ private void assertAllDesiredNodesAreActualized() throws Exception {
77150 }
78151 }
79152
80- private void addClusterNodesToDesiredNodesWithFloatProcessorsOrProcessorRanges (int version ) throws Exception {
153+ private void addClusterNodesToDesiredNodesWithProcessorsOrProcessorRanges (int version , ProcessorsPrecision processorsPrecision )
154+ throws Exception {
81155 final List <DesiredNode > nodes ;
82156 if (randomBoolean ()) {
83157 nodes = getNodeNames ().stream ()
84158 .map (
85159 nodeName -> new DesiredNode (
86160 Settings .builder ().put (NODE_NAME_SETTING .getKey (), nodeName ).build (),
87- 0.5f ,
161+ processorsPrecision == ProcessorsPrecision . DOUBLE ? randomDoubleProcessorCount () : randomFloatProcessorCount () ,
88162 ByteSizeValue .ofGb (randomIntBetween (10 , 24 )),
89163 ByteSizeValue .ofGb (randomIntBetween (128 , 256 )),
90164 Version .CURRENT
91165 )
92166 )
93167 .toList ();
94168 } else {
95- nodes = getNodeNames ().stream ()
96- .map (
97- nodeName -> new DesiredNode (
98- Settings .builder ().put (NODE_NAME_SETTING .getKey (), nodeName ).build (),
99- new DesiredNode .ProcessorsRange (randomIntBetween (1 , 10 ), (float ) randomIntBetween (20 , 30 )),
100- ByteSizeValue .ofGb (randomIntBetween (10 , 24 )),
101- ByteSizeValue .ofGb (randomIntBetween (128 , 256 )),
102- Version .CURRENT
103- )
104- )
105- .toList ();
169+ nodes = getNodeNames ().stream ().map (nodeName -> {
170+ double minProcessors = processorsPrecision == ProcessorsPrecision .DOUBLE
171+ ? randomDoubleProcessorCount ()
172+ : randomFloatProcessorCount ();
173+ return new DesiredNode (
174+ Settings .builder ().put (NODE_NAME_SETTING .getKey (), nodeName ).build (),
175+ new DesiredNode .ProcessorsRange (minProcessors , minProcessors + randomIntBetween (10 , 20 )),
176+ ByteSizeValue .ofGb (randomIntBetween (10 , 24 )),
177+ ByteSizeValue .ofGb (randomIntBetween (128 , 256 )),
178+ Version .CURRENT
179+ );
180+ }).toList ();
106181 }
107182 updateDesiredNodes (nodes , version );
108183 }
@@ -123,7 +198,7 @@ private void addClusterNodesToDesiredNodesWithIntegerProcessors(int version) thr
123198 }
124199
125200 private void updateDesiredNodes (List <DesiredNode > nodes , int version ) throws IOException {
126- final var request = new Request ("PUT" , "/_internal/desired_nodes/history /" + version );
201+ final var request = new Request ("PUT" , "/_internal/desired_nodes/upgrade_test /" + version );
127202 try (var builder = JsonXContent .contentBuilder ()) {
128203 builder .startObject ();
129204 builder .xContentList (UpdateDesiredNodesRequest .NODES_FIELD .getPreferredName (), nodes );
@@ -149,6 +224,14 @@ private List<String> getNodeNames() throws Exception {
149224 return nodeNames ;
150225 }
151226
227+ private double randomDoubleProcessorCount () {
228+ return randomDoubleBetween (0.5 , 512.1234 , true );
229+ }
230+
231+ private float randomFloatProcessorCount () {
232+ return randomIntBetween (1 , 512 ) + randomFloat ();
233+ }
234+
152235 @ SuppressWarnings ("unchecked" )
153236 private static <T > T extractValue (Map <String , Object > map , String path ) {
154237 return (T ) XContentMapValues .extractValue (path , map );
0 commit comments