@@ -278,6 +278,33 @@ def _arguments_for_list_runs(parser):
278
278
parser .add_argument ("cluster" , nargs = '?' , default = None , help = "the cluster name" )
279
279
parser .add_argument ("keyspace" , nargs = '?' , default = None , help = "the keyspace name" )
280
280
281
+ def _arguments_for_list_snapshots (parser ):
282
+ """Arguments needed to list snapshots"""
283
+ parser .add_argument ("cluster" , nargs = '?' , default = None , help = "the cluster name" )
284
+ parser .add_argument ("--node" , default = None ,
285
+ help = ("A single node to get the snapshot list from" ))
286
+
287
+
288
+ def _arguments_for_create_snapshots (parser ):
289
+ """Arguments needed to create snapshots"""
290
+ parser .add_argument ("cluster_name" , nargs = '?' , default = None , help = "the cluster name" )
291
+ parser .add_argument ("--node" , default = None ,
292
+ help = ("A single node to get the snapshot list from" ))
293
+ parser .add_argument ("--keyspace" , default = None ,
294
+ help = ("A single keyspace to snapshot" ))
295
+ parser .add_argument ("--name" , default = "reaper" ,
296
+ help = ("Name that will prefix the snapshot" ))
297
+ _argument_owner (parser )
298
+ _argument_cause (parser )
299
+
300
+ def _arguments_for_delete_snapshots (parser ):
301
+ """Arguments needed to delete snapshots"""
302
+ parser .add_argument ("cluster_name" , nargs = '?' , default = None , help = "the cluster name" )
303
+ parser .add_argument ("snapshot_name" , nargs = '?' , default = None , help = "the snapshot name" )
304
+ parser .add_argument ("--node" , default = None ,
305
+ help = ("A single node to get the snapshot list from" ))
306
+
307
+
281
308
282
309
def _parse_arguments (command , description , usage = None , extra_arguments = None ):
283
310
"""Generic argument parsing done by every command"""
@@ -330,6 +357,9 @@ Usage: spreaper [<global_args>] <command> [<command_args>]
330
357
pause-schedule Pause a repair schedule.
331
358
delete-schedule Delete a repair schedule.
332
359
ping Test connectivity to the Reaper service.
360
+ list-snapshots List all snapshots for a given cluster or node.
361
+ take-snapshot Take a snapshot for a whole cluster or a specific node.
362
+ delete-snapshot Delete a named snapshot on a whole cluster or a specific node.
333
363
"""
334
364
335
365
@@ -428,6 +458,90 @@ class ReaperCLI(object):
428
458
printq ("# Found {0} schedules:" .format (len (data )))
429
459
print json .dumps (data , indent = 2 , sort_keys = True )
430
460
461
+ def list_snapshots (self ):
462
+ reaper , args = ReaperCLI .prepare_reaper (
463
+ "list-snapshots" ,
464
+ "List snapshots for a given cluster or node" ,
465
+ extra_arguments = _arguments_for_list_snapshots
466
+ )
467
+ if not args .node :
468
+ printq ("# Listing snapshots for cluster '{0}'" .format (args .cluster ))
469
+ snapshots = json .loads (reaper .get ("snapshot/cluster/{0}" .format (args .cluster )))
470
+ printq ("# Found {0} snapshots" .format (len (snapshots )))
471
+ print json .dumps (snapshots , indent = 2 , sort_keys = True )
472
+ else :
473
+ printq ("# Listing snapshots for cluster '{0}' and node '{1}'" .format (args .cluster , args .node ))
474
+ snapshots = json .loads (reaper .get ("snapshot/{0}/{1}" .format (args .cluster , args .node )))
475
+ printq ("# Found {0} snapshots" .format (len (snapshots )))
476
+ print json .dumps (snapshots , indent = 2 , sort_keys = True )
477
+
478
+ def take_snapshot (self ):
479
+ reaper , args = ReaperCLI .prepare_reaper (
480
+ "take-snapshot" ,
481
+ "Take a snapshot. You need to register a cluster "
482
+ "into Reaper (add-cluster) before calling this." ,
483
+ extra_arguments = _arguments_for_create_snapshots
484
+ )
485
+ if not args .cluster_name :
486
+ print ("# Please specify a cluster" )
487
+ exit (1 )
488
+ if args .keyspace :
489
+ if args .node :
490
+ print ("# Taking a snapshot on cluster '{0}', node '{1}' and keyspace '{2}', "
491
+ ).format (args .cluster_name , args .node , args .keyspace )
492
+ reply = reaper .post ("snapshot/{0}/{1}" .format (args .cluster_name , args .node ),
493
+ keyspace = args .keyspace ,
494
+ owner = args .owner , cause = args .cause ,
495
+ snapshot_name = args .name )
496
+ else :
497
+ print ("# Taking a snapshot on cluster '{0}' and keyspace '{1}', "
498
+ ).format (args .cluster_name , args .keyspace )
499
+ reply = reaper .post ("snapshot/cluster/{0}" .format (args .cluster_name ),
500
+ keyspace = args .keyspace ,
501
+ owner = args .owner , cause = args .cause ,
502
+ snapshot_name = args .name )
503
+ else :
504
+ if args .node :
505
+ print ("# Taking a snapshot on cluster '{0}' and node '{1}', "
506
+ ).format (args .cluster_name , args .node )
507
+ reply = reaper .post ("snapshot/{0}/{1}" .format (args .cluster_name , args .node ),
508
+ keyspace = args .keyspace ,
509
+ owner = args .owner , cause = args .cause ,
510
+ snapshot_name = args .name )
511
+ else :
512
+ print ("# Taking a snapshot on cluster '{0}', "
513
+ ).format (args .cluster_name )
514
+ reply = reaper .post ("snapshot/cluster/{0}" .format (args .cluster_name ),
515
+ keyspace = args .keyspace ,
516
+ owner = args .owner , cause = args .cause ,
517
+ snapshot_name = args .name )
518
+
519
+ snapshot = json .loads (reply )
520
+ printq ("# Snapshot taken" )
521
+ print json .dumps (snapshot , indent = 2 , sort_keys = True )
522
+
523
+ def delete_snapshot (self ):
524
+ reaper , args = ReaperCLI .prepare_reaper (
525
+ "delete-snapshot" ,
526
+ "Delete a snapshot." ,
527
+ extra_arguments = _arguments_for_delete_snapshots
528
+ )
529
+ if not args .cluster_name or not args .snapshot_name :
530
+ print ("# Please specify a cluster and a snapshot name" )
531
+ exit (1 )
532
+
533
+ if args .node :
534
+ print ("# Deleting snapshot '{1}' on cluster '{0}' and node '{2}'"
535
+ ).format (args .snapshot_name , args .cluster_name , args .node )
536
+ reply = reaper .delete ("snapshot/{0}/{1}/{2}" .format (args .cluster_name , args .node , args .snapshot_name ))
537
+ else :
538
+ print ("# Deleting snapshot '{1}' on cluster '{0}', "
539
+ ).format (args .cluster_name , args .snapshot_name )
540
+ reply = reaper .delete ("snapshot/cluster/{0}/{1}" .format (args .cluster_name , args .snapshot_name ))
541
+
542
+ printq ("# Snapshot deleted : {0}" .format (reply ))
543
+
544
+
431
545
def status_cluster (self ):
432
546
reaper , args = ReaperCLI .prepare_reaper (
433
547
"status-cluster" ,
0 commit comments