@@ -208,38 +208,33 @@ public void testPolicyManualExecution() throws Exception {
208
208
assertThat (EntityUtils .toString (badResp .getResponse ().getEntity ()),
209
209
containsString ("no such snapshot lifecycle policy [" + policyName + "-bad]" ));
210
210
211
- Response goodResp = client (). performRequest ( new Request ( "PUT" , "/_slm/policy/" + policyName + "/_execute" ) );
211
+ final String snapshotName = executePolicy ( policyName );
212
212
213
- try (XContentParser parser = JsonXContent .jsonXContent .createParser (NamedXContentRegistry .EMPTY ,
214
- DeprecationHandler .THROW_UNSUPPORTED_OPERATION , EntityUtils .toByteArray (goodResp .getEntity ()))) {
215
- final String snapshotName = parser .mapStrings ().get ("snapshot_name" );
216
-
217
- // Check that the executed snapshot is created
218
- assertBusy (() -> {
219
- try {
220
- Response response = client ().performRequest (new Request ("GET" , "/_snapshot/" + repoId + "/" + snapshotName ));
221
- Map <String , Object > snapshotResponseMap ;
222
- try (InputStream is = response .getEntity ().getContent ()) {
223
- snapshotResponseMap = XContentHelper .convertToMap (XContentType .JSON .xContent (), is , true );
224
- }
225
- assertThat (snapshotResponseMap .size (), greaterThan (0 ));
226
- final Map <String , Object > metadata = extractMetadata (snapshotResponseMap , snapshotName );
227
- assertNotNull (metadata );
228
- assertThat (metadata .get ("policy" ), equalTo (policyName ));
229
- assertHistoryIsPresent (policyName , true , repoId , CREATE_OPERATION );
230
- } catch (ResponseException e ) {
231
- fail ("expected snapshot to exist but it does not: " + EntityUtils .toString (e .getResponse ().getEntity ()));
213
+ // Check that the executed snapshot is created
214
+ assertBusy (() -> {
215
+ try {
216
+ Response response = client ().performRequest (new Request ("GET" , "/_snapshot/" + repoId + "/" + snapshotName ));
217
+ Map <String , Object > snapshotResponseMap ;
218
+ try (InputStream is = response .getEntity ().getContent ()) {
219
+ snapshotResponseMap = XContentHelper .convertToMap (XContentType .JSON .xContent (), is , true );
232
220
}
221
+ assertThat (snapshotResponseMap .size (), greaterThan (0 ));
222
+ final Map <String , Object > metadata = extractMetadata (snapshotResponseMap , snapshotName );
223
+ assertNotNull (metadata );
224
+ assertThat (metadata .get ("policy" ), equalTo (policyName ));
225
+ assertHistoryIsPresent (policyName , true , repoId , CREATE_OPERATION );
226
+ } catch (ResponseException e ) {
227
+ fail ("expected snapshot to exist but it does not: " + EntityUtils .toString (e .getResponse ().getEntity ()));
228
+ }
233
229
234
- Map <String , Object > stats = getSLMStats ();
235
- Map <String , Object > policyStats = (Map <String , Object >) stats .get (SnapshotLifecycleStats .POLICY_STATS .getPreferredName ());
236
- Map <String , Object > policyIdStats = (Map <String , Object >) policyStats .get (policyName );
237
- int snapsTaken = (int ) policyIdStats .get (SnapshotLifecycleStats .SnapshotPolicyStats .SNAPSHOTS_TAKEN .getPreferredName ());
238
- int totalTaken = (int ) stats .get (SnapshotLifecycleStats .TOTAL_TAKEN .getPreferredName ());
239
- assertThat (snapsTaken , equalTo (1 ));
240
- assertThat (totalTaken , equalTo (1 ));
241
- });
242
- }
230
+ Map <String , Object > stats = getSLMStats ();
231
+ Map <String , Object > policyStats = (Map <String , Object >) stats .get (SnapshotLifecycleStats .POLICY_STATS .getPreferredName ());
232
+ Map <String , Object > policyIdStats = (Map <String , Object >) policyStats .get (policyName );
233
+ int snapsTaken = (int ) policyIdStats .get (SnapshotLifecycleStats .SnapshotPolicyStats .SNAPSHOTS_TAKEN .getPreferredName ());
234
+ int totalTaken = (int ) stats .get (SnapshotLifecycleStats .TOTAL_TAKEN .getPreferredName ());
235
+ assertThat (snapsTaken , equalTo (1 ));
236
+ assertThat (totalTaken , equalTo (1 ));
237
+ });
243
238
}
244
239
245
240
@ SuppressWarnings ("unchecked" )
@@ -261,31 +256,25 @@ public void testBasicTimeBasedRetenion() throws Exception {
261
256
new SnapshotRetentionConfiguration (TimeValue .timeValueMillis (1 ), null , null ));
262
257
263
258
// Manually create a snapshot
264
- Response executeResp = client (). performRequest ( new Request ( "PUT" , "/_slm/policy/" + policyName + "/_execute" ) );
259
+ final String snapshotName = executePolicy ( policyName );
265
260
266
- final String snapshotName ;
267
- try (XContentParser parser = JsonXContent .jsonXContent .createParser (NamedXContentRegistry .EMPTY ,
268
- DeprecationHandler .THROW_UNSUPPORTED_OPERATION , EntityUtils .toByteArray (executeResp .getEntity ()))) {
269
- snapshotName = parser .mapStrings ().get ("snapshot_name" );
270
-
271
- // Check that the executed snapshot is created
272
- assertBusy (() -> {
273
- try {
274
- Response response = client ().performRequest (new Request ("GET" , "/_snapshot/" + repoId + "/" + snapshotName ));
275
- Map <String , Object > snapshotResponseMap ;
276
- try (InputStream is = response .getEntity ().getContent ()) {
277
- snapshotResponseMap = XContentHelper .convertToMap (XContentType .JSON .xContent (), is , true );
278
- }
279
- assertThat (snapshotResponseMap .size (), greaterThan (0 ));
280
- final Map <String , Object > metadata = extractMetadata (snapshotResponseMap , snapshotName );
281
- assertNotNull (metadata );
282
- assertThat (metadata .get ("policy" ), equalTo (policyName ));
283
- assertHistoryIsPresent (policyName , true , repoId , CREATE_OPERATION );
284
- } catch (ResponseException e ) {
285
- fail ("expected snapshot to exist but it does not: " + EntityUtils .toString (e .getResponse ().getEntity ()));
261
+ // Check that the executed snapshot is created
262
+ assertBusy (() -> {
263
+ try {
264
+ Response response = client ().performRequest (new Request ("GET" , "/_snapshot/" + repoId + "/" + snapshotName ));
265
+ Map <String , Object > snapshotResponseMap ;
266
+ try (InputStream is = response .getEntity ().getContent ()) {
267
+ snapshotResponseMap = XContentHelper .convertToMap (XContentType .JSON .xContent (), is , true );
286
268
}
287
- });
288
- }
269
+ assertThat (snapshotResponseMap .size (), greaterThan (0 ));
270
+ final Map <String , Object > metadata = extractMetadata (snapshotResponseMap , snapshotName );
271
+ assertNotNull (metadata );
272
+ assertThat (metadata .get ("policy" ), equalTo (policyName ));
273
+ assertHistoryIsPresent (policyName , true , repoId , CREATE_OPERATION );
274
+ } catch (ResponseException e ) {
275
+ fail ("expected snapshot to exist but it does not: " + EntityUtils .toString (e .getResponse ().getEntity ()));
276
+ }
277
+ });
289
278
290
279
// Run retention every second
291
280
ClusterUpdateSettingsRequest req = new ClusterUpdateSettingsRequest ();
@@ -391,6 +380,127 @@ public void testSnapshotInProgress() throws Exception {
391
380
}
392
381
}
393
382
383
+ @ SuppressWarnings ("unchecked" )
384
+ public void testRetentionWhileSnapshotInProgress () throws Exception {
385
+ final String indexName = "test" ;
386
+ final String slowPolicy = "slow" ;
387
+ final String fastPolicy = "fast" ;
388
+ final String slowRepo = "slow-repo" ;
389
+ final String fastRepo = "fast-repo" ;
390
+ int docCount = 20 ;
391
+ for (int i = 0 ; i < docCount ; i ++) {
392
+ index (client (), indexName , "" + i , "foo" , "bar" );
393
+ }
394
+
395
+ // Create snapshot repos, one fast and one slow
396
+ initializeRepo (slowRepo , "1b" );
397
+ initializeRepo (fastRepo , "10mb" );
398
+
399
+ createSnapshotPolicy (slowPolicy , "snap" , "1 2 3 4 5 ?" , slowRepo , indexName , true ,
400
+ new SnapshotRetentionConfiguration (TimeValue .timeValueSeconds (0 ), null , null ));
401
+ createSnapshotPolicy (fastPolicy , "snap" , "1 2 3 4 5 ?" , fastRepo , indexName , true ,
402
+ new SnapshotRetentionConfiguration (TimeValue .timeValueSeconds (0 ), null , null ));
403
+
404
+ // Create a snapshot and wait for it to be complete (need something that can be deleted)
405
+ final String completedSnapshotName = executePolicy (fastPolicy );
406
+ assertBusy (() -> {
407
+ try {
408
+ Response getResp = client ().performRequest (new Request ("GET" ,
409
+ "/_snapshot/" + fastRepo + "/" + completedSnapshotName + "/_status" ));
410
+ try (InputStream content = getResp .getEntity ().getContent ()) {
411
+ Map <String , Object > snaps = XContentHelper .convertToMap (XContentType .JSON .xContent (), content , true );
412
+ logger .info ("--> waiting for snapshot {} to be successful, got: {}" , completedSnapshotName , snaps );
413
+ List <Map <String , Object >> snaps2 = (List <Map <String , Object >>) snaps .get ("snapshots" );
414
+ assertThat (snaps2 .get (0 ).get ("state" ), equalTo ("SUCCESS" ));
415
+ }
416
+ } catch (NullPointerException | ResponseException e ) {
417
+ fail ("unable to retrieve completed snapshot: " + e );
418
+ }
419
+ }, 60 , TimeUnit .SECONDS );
420
+
421
+ // Take another snapshot
422
+ final String slowSnapshotName = executePolicy (slowPolicy );
423
+
424
+ // Check that the executed snapshot shows up in the SLM output as in_progress
425
+ assertBusy (() -> {
426
+ try {
427
+ Response response = client ().performRequest (new Request ("GET" , "/_slm/policy" + (randomBoolean () ? "" : "?human" )));
428
+ Map <String , Object > policyResponseMap ;
429
+ try (InputStream content = response .getEntity ().getContent ()) {
430
+ policyResponseMap = XContentHelper .convertToMap (XContentType .JSON .xContent (), content , true );
431
+ }
432
+ assertThat (policyResponseMap .size (), greaterThan (0 ));
433
+ Optional <Map <String , Object >> inProgress = Optional .ofNullable ((Map <String , Object >) policyResponseMap .get (slowPolicy ))
434
+ .map (policy -> (Map <String , Object >) policy .get ("in_progress" ));
435
+
436
+ if (inProgress .isPresent ()) {
437
+ Map <String , Object > inProgressMap = inProgress .get ();
438
+ assertThat (inProgressMap .get ("name" ), equalTo (slowSnapshotName ));
439
+ assertNotNull (inProgressMap .get ("uuid" ));
440
+ assertThat (inProgressMap .get ("state" ), equalTo ("STARTED" ));
441
+ assertThat ((long ) inProgressMap .get ("start_time_millis" ), greaterThan (0L ));
442
+ assertNull (inProgressMap .get ("failure" ));
443
+ } else {
444
+ fail ("expected in_progress to contain a running snapshot, but the response was " + policyResponseMap );
445
+ }
446
+ } catch (ResponseException e ) {
447
+ fail ("expected policy to exist but it does not: " + EntityUtils .toString (e .getResponse ().getEntity ()));
448
+ }
449
+ });
450
+
451
+ // Run retention every second
452
+ ClusterUpdateSettingsRequest req = new ClusterUpdateSettingsRequest ();
453
+ req .transientSettings (Settings .builder ().put (LifecycleSettings .SLM_RETENTION_SCHEDULE , "*/1 * * * * ?" ));
454
+ try (XContentBuilder builder = jsonBuilder ()) {
455
+ req .toXContent (builder , ToXContent .EMPTY_PARAMS );
456
+ Request r = new Request ("PUT" , "/_cluster/settings" );
457
+ r .setJsonEntity (Strings .toString (builder ));
458
+ client ().performRequest (r );
459
+ }
460
+
461
+ // Cancel the snapshot since it is not going to complete quickly, do it in a thread because
462
+ // cancelling the snapshot can take a long time and we might as well check retention while
463
+ // its deleting
464
+ Thread t = new Thread (() -> {
465
+ try {
466
+ assertOK (client ().performRequest (new Request ("DELETE" , "/_snapshot/" + slowRepo + "/" + slowSnapshotName )));
467
+ } catch (IOException e ) {
468
+ fail ("should not have thrown " + e );
469
+ }
470
+ });
471
+ t .start ();
472
+
473
+ // Check that the snapshot created by the policy has been removed by retention
474
+ assertBusy (() -> {
475
+ // We expect a failed response because the snapshot should not exist
476
+ try {
477
+ logger .info ("--> checking to see if snapshot has been deleted..." );
478
+ Response response = client ().performRequest (new Request ("GET" , "/_snapshot/" + slowRepo + "/" + completedSnapshotName ));
479
+ assertThat (EntityUtils .toString (response .getEntity ()), containsString ("snapshot_missing_exception" ));
480
+ } catch (ResponseException e ) {
481
+ assertThat (EntityUtils .toString (e .getResponse ().getEntity ()), containsString ("snapshot_missing_exception" ));
482
+ }
483
+ }, 60 , TimeUnit .SECONDS );
484
+
485
+ t .join (5000 );
486
+ }
487
+
488
+ /**
489
+ * Execute the given policy and return the generated snapshot name
490
+ */
491
+ private String executePolicy (String policyId ) {
492
+ try {
493
+ Response executeRepsonse = client ().performRequest (new Request ("PUT" , "/_slm/policy/" + policyId + "/_execute" ));
494
+ try (XContentParser parser = JsonXContent .jsonXContent .createParser (NamedXContentRegistry .EMPTY ,
495
+ DeprecationHandler .THROW_UNSUPPORTED_OPERATION , EntityUtils .toByteArray (executeRepsonse .getEntity ()))) {
496
+ return parser .mapStrings ().get ("snapshot_name" );
497
+ }
498
+ } catch (Exception e ) {
499
+ fail ("failed to execute policy " + policyId + " - got: " + e );
500
+ throw new RuntimeException (e );
501
+ }
502
+ }
503
+
394
504
@ SuppressWarnings ("unchecked" )
395
505
private static Map <String , Object > extractMetadata (Map <String , Object > snapshotResponseMap , String snapshotPrefix ) {
396
506
List <Map <String , Object >> snapResponse = ((List <Map <String , Object >>) snapshotResponseMap .get ("responses" )).stream ()
0 commit comments