@@ -30,6 +30,31 @@ class Utility
3030 */
3131 private static $ version ;
3232
33+ /**
34+ * @var bool
35+ */
36+ private static $ hasXPack = false ;
37+
38+ /**
39+ * @var bool
40+ */
41+ private static $ hasIlm = false ;
42+
43+ /**
44+ * @var bool
45+ */
46+ private static $ hasRollups = false ;
47+
48+ /**
49+ * @var bool
50+ */
51+ private static $ hasCcr = false ;
52+
53+ /**
54+ * @var bool
55+ */
56+ private static $ hasShutdown = false ;
57+
3358 /**
3459 * Get the host URL based on ENV variables
3560 */
@@ -87,7 +112,7 @@ public static function removeYamlXPackUsers(Client $client): void
87112 ]);
88113 }
89114
90- private static function getVersion (Client $ client ): string
115+ public static function getVersion (Client $ client ): string
91116 {
92117 if (!isset (self ::$ version )) {
93118 $ result = $ client ->info ();
@@ -96,64 +121,130 @@ private static function getVersion(Client $client): string
96121 return self ::$ version ;
97122 }
98123
124+ /**
125+ * Read the plugins installed in Elasticsearch using the
126+ * undocumented API GET /_nodes/plugins
127+ *
128+ * @see ESRestTestCase.java:initClient()
129+ */
130+ private static function readPlugins (Client $ client ): void
131+ {
132+ $ result = $ client ->transport ->performRequest ('GET ' , '/_nodes/plugins ' );
133+ foreach ($ result ['nodes ' ] as $ node ) {
134+ foreach ($ node ['modules ' ] as $ module ) {
135+ if (substr ($ module ['name ' ], 0 , 6 ) === 'x-pack ' ) {
136+ self ::$ hasXPack = true ;
137+ }
138+ if ($ module ['name ' ] === 'x-pack-ilm ' ) {
139+ self ::$ hasIlm = true ;
140+ }
141+ if ($ module ['name ' ] === 'x-pack-rollup ' ) {
142+ self ::$ hasRollups = true ;
143+ }
144+ if ($ module ['name ' ] === 'x-pack-ccr ' ) {
145+ self ::$ hasCcr = true ;
146+ }
147+ if ($ module ['name ' ] === 'x-pack-shutdown ' ) {
148+ self ::$ hasShutdown = true ;
149+ }
150+ }
151+ }
152+ }
153+
99154 /**
100155 * Clean up the cluster after a test
101156 *
102157 * @see ESRestTestCase.java:cleanUpCluster()
103158 */
104159 public static function cleanUpCluster (Client $ client ): void
105160 {
161+ self ::readPlugins ($ client );
162+
163+ self ::ensureNoInitializingShards ($ client );
106164 self ::wipeCluster ($ client );
107165 self ::waitForClusterStateUpdatesToFinish ($ client );
108166 }
109167
168+ /**
169+ * Waits until all shard initialization is completed.
170+ * This is a handy alternative to ensureGreen as it relates to all shards
171+ * in the cluster and doesn't require to know how many nodes/replica there are.
172+ *
173+ * @see ESRestTestCase.java:ensureNoInitializingShards()
174+ */
175+ private static function ensureNoInitializingShards (Client $ client ): void
176+ {
177+ $ client ->cluster ()->health ([
178+ 'wait_for_no_initializing_shards ' => true ,
179+ 'timeout ' => '70s ' ,
180+ 'level ' => 'shards '
181+ ]);
182+ }
183+
110184 /**
111185 * Delete the cluster
112186 *
113187 * @see ESRestTestCase.java:wipeCluster()
114188 */
115189 private static function wipeCluster (Client $ client ): void
116190 {
117- if (getenv ( ' TEST_SUITE ' ) === ' platinum ' ) {
191+ if (self :: $ hasRollups ) {
118192 self ::wipeRollupJobs ($ client );
119193 self ::waitForPendingRollupTasks ($ client );
120194 }
121- if (version_compare (self ::getVersion ($ client ), '7.3.99 ' ) > 0 ) {
122- self ::deleteAllSLMPolicies ($ client );
195+ self ::deleteAllSLMPolicies ($ client );
196+
197+ // Clean up searchable snapshots indices before deleting snapshots and repositories
198+ if (self ::$ hasXPack && version_compare (self ::getVersion ($ client ), '7.7.99 ' ) > 0 ) {
199+ self ::wipeSearchableSnapshotsIndices ($ client );
123200 }
124201
125202 self ::wipeSnapshots ($ client );
126203 self ::wipeDataStreams ($ client );
127204 self ::wipeAllIndices ($ client );
128205
129- if (getenv ( ' TEST_SUITE ' ) === ' platinum ' ) {
206+ if (self :: $ hasXPack ) {
130207 self ::wipeTemplateForXpack ($ client );
131208 } else {
132- // Delete templates
133- $ client ->indices ()->deleteTemplate ([
134- 'name ' => '* '
135- ]);
136- try {
137- // Delete index template
138- $ client ->indices ()->deleteIndexTemplate ([
139- 'name ' => '* '
140- ]);
141- // Delete component template
142- $ client ->cluster ()->deleteComponentTemplate ([
143- 'name ' => '* '
144- ]);
145- } catch (ElasticsearchException $ e ) {
146- // We hit a version of ES that doesn't support index templates v2 yet, so it's safe to ignore
147- }
209+ self ::wipeAllTemplates ($ client );
148210 }
149211
150212 self ::wipeClusterSettings ($ client );
151213
152- if (getenv ( ' TEST_SUITE ' ) === ' platinum ' ) {
214+ if (self :: $ hasIlm ) {
153215 self ::deleteAllILMPolicies ($ client );
216+ }
217+ if (self ::$ hasCcr ) {
154218 self ::deleteAllAutoFollowPatterns ($ client );
219+ }
220+ if (self ::$ hasXPack ) {
155221 self ::deleteAllTasks ($ client );
156222 }
223+
224+ self ::deleteAllNodeShutdownMetadata ($ client );
225+ }
226+
227+ /**
228+ * Remove all templates
229+ */
230+ private static function wipeAllTemplates (Client $ client ): void
231+ {
232+ // Delete templates
233+ $ client ->indices ()->deleteTemplate ([
234+ 'name ' => '* '
235+ ]);
236+ try {
237+ // Delete index template
238+ $ client ->indices ()->deleteIndexTemplate ([
239+ 'name ' => '* '
240+ ]);
241+ // Delete component template
242+ $ client ->cluster ()->deleteComponentTemplate ([
243+ 'name ' => '* '
244+ ]);
245+ } catch (ElasticsearchException $ e ) {
246+ // We hit a version of ES that doesn't support index templates v2 yet, so it's safe to ignore
247+ }
157248 }
158249
159250 /**
@@ -288,7 +379,7 @@ private static function deleteAllSLMPolicies(Client $client): void
288379 private static function wipeDataStreams (Client $ client ): void
289380 {
290381 try {
291- if (version_compare ( self ::getVersion ( $ client ), ' 7.8.99 ' ) > 0 ) {
382+ if (self ::$ hasXPack ) {
292383 $ client ->indices ()->deleteDataStream ([
293384 'name ' => '* ' ,
294385 'expand_wildcards ' => 'all '
@@ -297,12 +388,17 @@ private static function wipeDataStreams(Client $client): void
297388 } catch (ElasticsearchException $ e ) {
298389 // We hit a version of ES that doesn't understand expand_wildcards, try again without it
299390 try {
300- $ client ->indices ()->deleteDataStream ([
301- 'name ' => '* '
302- ]);
303- } catch (ElasticsearchException $ e ) {
391+ if (self ::$ hasXPack ) {
392+ $ client ->indices ()->deleteDataStream ([
393+ 'name ' => '* '
394+ ]);
395+ }
396+ } catch (Exception $ e ) {
304397 // We hit a version of ES that doesn't serialize DeleteDataStreamAction.Request#wildcardExpressionsOriginallySpecified
305398 // field or that doesn't support data streams so it's safe to ignore
399+ if ($ e ->getCode () !== '404 ' && $ e ->getCode () !== '405 ' ) {
400+ throw $ e ;
401+ }
306402 }
307403 }
308404 }
@@ -469,15 +565,15 @@ private static function isXPackTemplate(string $name): bool
469565 if (strpos ($ name , '.transform- ' ) !== false ) {
470566 return true ;
471567 }
568+ if (strpos ($ name , '.deprecation- ' ) !== false ) {
569+ return true ;
570+ }
472571 switch ($ name ) {
473572 case ".watches " :
474- case "logstash-index-template " :
475- case ".logstash-management " :
476573 case "security_audit_log " :
477574 case ".slm-history " :
478575 case ".async-search " :
479576 case "saml-service-provider " :
480- case "ilm-history " :
481577 case "logs " :
482578 case "logs-settings " :
483579 case "logs-mappings " :
@@ -488,12 +584,14 @@ private static function isXPackTemplate(string $name): bool
488584 case "synthetics-settings " :
489585 case "synthetics-mappings " :
490586 case ".snapshot-blob-cache " :
491- case ".deprecation-indexing-template " :
587+ case "ilm-history " :
492588 case "logstash-index-template " :
493589 case "security-index-template " :
590+ case "data-streams-mappings " :
494591 return true ;
592+ default :
593+ return false ;
495594 }
496- return false ;
497595 }
498596
499597 /**
@@ -562,6 +660,47 @@ private static function deleteAllTasks(Client $client): void
562660 }
563661 }
564662
663+ /**
664+ * If any nodes are registered for shutdown, removes their metadata
665+ *
666+ * @see https://github.com/elastic/elasticsearch/commit/cea054f7dae215475ea0499bc7060ca7ec05382f
667+ */
668+ private static function deleteAllNodeShutdownMetadata (Client $ client )
669+ {
670+ if (!self ::$ hasShutdown || version_compare (self ::getVersion ($ client ), '7.15.0 ' ) < 0 ) {
671+ // Node shutdown APIs are only present in xpack
672+ return ;
673+ }
674+ $ nodes = $ client ->shutdown ()->getNode ();
675+ foreach ($ nodes ['nodes ' ] as $ node ) {
676+ $ client ->shutdown ()->deleteNode ($ node ['node_id ' ]);
677+ }
678+ }
679+
680+ /**
681+ * Delete searchable snapshots index
682+ *
683+ * @see https://github.com/elastic/elasticsearch/commit/4927b6917deca6793776cf0c839eadf5ea512b4a
684+ */
685+ private static function wipeSearchableSnapshotsIndices (Client $ client )
686+ {
687+ $ indices = $ client ->cluster ()->state ([
688+ 'metric ' => 'metadata ' ,
689+ 'filter_path ' => 'metadata.indices.*.settings.index.store.snapshot '
690+ ]);
691+ if (!isset ($ indices ['metadata ' ]['indices ' ])) {
692+ return ;
693+ }
694+ foreach ($ indices ['metadata ' ]['indices ' ] as $ index => $ value ) {
695+ $ client ->indices ()->delete ([
696+ 'index ' => $ index ,
697+ 'client ' => [
698+ 'ignore ' => 404
699+ ]
700+ ]);
701+ }
702+ }
703+
565704 /**
566705 * Wait for Cluster state updates to finish
567706 *
0 commit comments