99
1010import org .elasticsearch .action .admin .cluster .state .ClusterStateRequest ;
1111import org .elasticsearch .cluster .ClusterState ;
12+ import org .elasticsearch .core .Tuple ;
1213import org .elasticsearch .reservedstate .service .FileSettingsService ;
1314import org .elasticsearch .test .ESIntegTestCase ;
1415import org .elasticsearch .test .SecurityIntegTestCase ;
3637@ ESIntegTestCase .ClusterScope (scope = ESIntegTestCase .Scope .TEST , numDataNodes = 0 , autoManageMasterNodes = false )
3738public class FileSettingsRoleMappingsRestartIT extends SecurityIntegTestCase {
3839
40+ private static final int MAX_WAIT_TIME_SECONDS = 20 ;
3941 private final AtomicLong versionCounter = new AtomicLong (1 );
4042
4143 @ Before
@@ -115,10 +117,9 @@ public void testReservedStatePersistsOnRestart() throws Exception {
115117 awaitFileSettingsWatcher ();
116118 logger .info ("--> write some role mappings, no other file settings" );
117119 writeJSONFile (masterNode , testJSONOnlyRoleMappings , logger , versionCounter );
118- boolean awaitSuccessful = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
119- assertTrue (awaitSuccessful );
120120
121- assertRoleMappingsInClusterState (
121+ assertRoleMappingsInClusterStateWithAwait (
122+ savedClusterState ,
122123 new ExpressionRoleMapping (
123124 "everyone_kibana_alone" ,
124125 new FieldExpression ("username" , List .of (new FieldExpression .FieldValue ("*" ))),
@@ -175,11 +176,8 @@ public void testReservedStatePersistsOnRestart() throws Exception {
175176 )
176177 );
177178
178- // now remove the role mappings via the same settings file
179- cleanupClusterState (masterNode );
180-
181- // no role mappings
182- assertRoleMappingsInClusterState ();
179+ // now remove the role mappings via an empty settings file
180+ cleanupClusterStateAndAssertNoMappings (masterNode );
183181
184182 // and restart the master to confirm the role mappings are all gone
185183 logger .info ("--> restart master again" );
@@ -195,14 +193,13 @@ public void testFileSettingsReprocessedOnRestartWithoutVersionChange() throws Ex
195193
196194 final String masterNode = internalCluster ().getMasterName ();
197195
198- var savedClusterState = setupClusterStateListener (masterNode , "everyone_kibana_alone" );
196+ Tuple < CountDownLatch , AtomicLong > savedClusterState = setupClusterStateListener (masterNode , "everyone_kibana_alone" );
199197 awaitFileSettingsWatcher ();
200198 logger .info ("--> write some role mappings, no other file settings" );
201199 writeJSONFile (masterNode , testJSONOnlyRoleMappings , logger , versionCounter );
202- boolean awaitSuccessful = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
203- assertTrue (awaitSuccessful );
204200
205- assertRoleMappingsInClusterState (
201+ assertRoleMappingsInClusterStateWithAwait (
202+ savedClusterState ,
206203 new ExpressionRoleMapping (
207204 "everyone_kibana_alone" ,
208205 new FieldExpression ("username" , List .of (new FieldExpression .FieldValue ("*" ))),
@@ -228,41 +225,8 @@ public void testFileSettingsReprocessedOnRestartWithoutVersionChange() throws Ex
228225 )
229226 );
230227
231- final CountDownLatch latch = new CountDownLatch (1 );
232- final FileSettingsService fileSettingsService = internalCluster ().getInstance (FileSettingsService .class , masterNode );
233- fileSettingsService .addFileChangedListener (latch ::countDown );
234- // Don't increment version but write new file contents to test re-processing on restart
228+ // write without version increment and assert that change gets applied on restart
235229 writeJSONFileWithoutVersionIncrement (masterNode , testJSONOnlyUpdatedRoleMappings , logger , versionCounter );
236- // Make sure we saw a file settings update so that we know it got processed, but it did not affect cluster state
237- assertTrue (latch .await (20 , TimeUnit .SECONDS ));
238-
239- // Nothing changed yet because version is the same and there was no restart
240- assertRoleMappingsInClusterState (
241- new ExpressionRoleMapping (
242- "everyone_kibana_alone" ,
243- new FieldExpression ("username" , List .of (new FieldExpression .FieldValue ("*" ))),
244- List .of ("kibana_user" ),
245- List .of (),
246- Map .of ("uuid" , "b9a59ba9-6b92-4be2-bb8d-02bb270cb3a7" , "_foo" , "something" , METADATA_NAME_FIELD , "everyone_kibana_alone" ),
247- true
248- ),
249- new ExpressionRoleMapping (
250- "everyone_fleet_alone" ,
251- new FieldExpression ("username" , List .of (new FieldExpression .FieldValue ("*" ))),
252- List .of ("fleet_user" ),
253- List .of (),
254- Map .of (
255- "uuid" ,
256- "b9a59ba9-6b92-4be3-bb8d-02bb270cb3a7" ,
257- "_foo" ,
258- "something_else" ,
259- METADATA_NAME_FIELD ,
260- "everyone_fleet_alone"
261- ),
262- false
263- )
264- );
265-
266230 logger .info ("--> restart master" );
267231 internalCluster ().restartNode (masterNode );
268232 ensureGreen ();
@@ -286,28 +250,52 @@ public void testFileSettingsReprocessedOnRestartWithoutVersionChange() throws Ex
286250 ),
287251 true
288252 )
289- )
253+ ),
254+ MAX_WAIT_TIME_SECONDS ,
255+ TimeUnit .SECONDS
290256 );
291257
292- cleanupClusterState (masterNode );
258+ cleanupClusterStateAndAssertNoMappings (masterNode );
293259 }
294260
295- private void assertRoleMappingsInClusterState (ExpressionRoleMapping ... expectedRoleMappings ) {
296- var clusterState = clusterAdmin ().state (new ClusterStateRequest (TEST_REQUEST_TIMEOUT )).actionGet ().getState ();
261+ private void assertRoleMappingsInClusterStateWithAwait (
262+ Tuple <CountDownLatch , AtomicLong > latchWithClusterStateVersion ,
263+ ExpressionRoleMapping ... expectedRoleMappings
264+ ) throws InterruptedException {
265+ boolean awaitSuccessful = latchWithClusterStateVersion .v1 ().await (MAX_WAIT_TIME_SECONDS , TimeUnit .SECONDS );
266+ assertTrue (awaitSuccessful );
267+ var clusterState = clusterAdmin ().state (
268+ new ClusterStateRequest (TEST_REQUEST_TIMEOUT ).waitForMetadataVersion (latchWithClusterStateVersion .v2 ().get ())
269+ ).actionGet ().getState ();
270+ assertRoleMappingsInClusterState (clusterState , expectedRoleMappings );
271+ }
272+
273+ private void assertRoleMappingsInClusterState (ClusterState clusterState , ExpressionRoleMapping ... expectedRoleMappings ) {
297274 String [] expectedRoleMappingNames = Arrays .stream (expectedRoleMappings ).map (ExpressionRoleMapping ::getName ).toArray (String []::new );
298275 assertRoleMappingReservedMetadata (clusterState , expectedRoleMappingNames );
299276 var actualRoleMappings = new ArrayList <>(RoleMappingMetadata .getFromClusterState (clusterState ).getRoleMappings ());
300277 assertThat (actualRoleMappings , containsInAnyOrder (expectedRoleMappings ));
301278 }
302279
303- private void cleanupClusterState (String masterNode ) throws Exception {
304- // now remove the role mappings via the same settings file
280+ private void assertRoleMappingsInClusterState (ExpressionRoleMapping ... expectedRoleMappings ) {
281+ assertRoleMappingsInClusterState (
282+ clusterAdmin ().state (new ClusterStateRequest (TEST_REQUEST_TIMEOUT )).actionGet ().getState (),
283+ expectedRoleMappings
284+ );
285+ }
286+
287+ private void cleanupClusterStateAndAssertNoMappings (String masterNode ) throws Exception {
305288 var savedClusterState = setupClusterStateListenerForCleanup (masterNode );
306289 awaitFileSettingsWatcher ();
307290 logger .info ("--> remove the role mappings with an empty settings file" );
308291 writeJSONFile (masterNode , emptyJSON , logger , versionCounter );
309- boolean awaitSuccessful = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
292+ boolean awaitSuccessful = savedClusterState .v1 ().await (MAX_WAIT_TIME_SECONDS , TimeUnit .SECONDS );
310293 assertTrue (awaitSuccessful );
294+ // ensure cluster-state update got propagated to expected version
295+ var clusterState = clusterAdmin ().state (
296+ new ClusterStateRequest (TEST_REQUEST_TIMEOUT ).waitForMetadataVersion (savedClusterState .v2 ().get ())
297+ ).actionGet ();
298+ assertRoleMappingsInClusterState (clusterState .getState ());
311299 }
312300
313301 private void assertRoleMappingReservedMetadata (ClusterState clusterState , String ... names ) {
0 commit comments