You are on page 1of 14

#!

/usr/bin/python
#
# Copyright (c) 2017 Nutanix Inc. All rights reserved.
#
# Disclaimer:
# Usage of this tool must be under guidance of Nutanix Support or an
# authorised partner.
# Summary:
# This script provides utility methods for dealing with snapshots
# created by any backup software. This tool is meant to be used to clean up
# such snapshots that have been left behind, for whatever reason.
# Version of the script: Version 2
# Compatible software version(s): AOS 5.1.1.1 and above with AHV hypervisors.
# Brief syntax usage:
# Example: 'backup_snapshots --list_for_vm <VM UUID> <user_name>';
# Please run 'backup_snapshots -h' for usage details.
# Caveats:
# Command line options for volume group snapshots such as '--list_for_vg',
# '--delete_vg_snapshot', and '--delete_for_vg' do not work in software
# versions prior to AOS 5.6.2, because volume_group_snapshots APIs are first
# introduced in 5.6.2.
#
# Change log
# ----------------------------------------------------------------------------
# Date Ticket Addressed
# ============================================================================
# 2019/11/01 bug fixed for delete snapshots.
# 2020/03/31 VG snapshot support, minor bug fixes.
# ----------------------------------------------------------------------------
#

import env

import argparse
import datetime
import getpass
import json
import operator
import requests
import time

from collections import namedtuple

import aplos.interfaces as interfaces


from aplos.intentengine.lib.intent_spec_wal import AplosIntentSpecWal
from cerebro.client.cerebro_interface_client import \
CerebroInterfaceTool, CerebroInterfaceError
from cerebro.interface.cerebro_interface_pb2 import \
ListProtectionDomainsArg, QueryProtectionDomainArg, ModifySnapshotArg
from util.base.types import NutanixUuid
import util.infrastructure.version as version_utils

cluster_version = version_utils.get_cluster_version(numeric=True)
if (version_utils.compare_versions(cluster_version, "5.11") >= 0):
from insights_interface.cpdb_interface.cpdb_query import (ALL, EQ, COL, STR)
else:
from util.db.cpdb_query import (ALL, EQ, COL, STR)

class Password(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
if values is None:
values = getpass.getpass()
setattr(namespace, self.dest, values)

PD = namedtuple("PD", "name system")

class Snapshot(object):
"""
The class represents a snapshot and its state. The snapshot could be
a proper VM / VG snapshot, a VM / VG snapshot missing cerebro backend
snapshot or a stale snapshot with only backend cerebro snapshot.
"""
def __init__(self, pd_name, cerebro_snap_uuid, ctime):
self._pd_name = pd_name
self._cerebro_snap_uuid = cerebro_snap_uuid
self._ctime = ctime
self._vm_uuid = None
self._vg_uuid = None
self._snap_uuid = None

def __lt__(self, other):


return self._ctime < other._ctime

@property
def pd_name(self):
return self._pd_name

@property
def cerebro_snap_uuid(self):
return self._cerebro_snap_uuid

@property
def ctime(self):
return self._ctime

@property
def vm_uuid(self):
return self._vm_uuid

@vm_uuid.setter
def vm_uuid(self, value):
self._vm_uuid = value

@property
def vg_uuid(self):
return self._vg_uuid

@vg_uuid.setter
def vg_uuid(self, value):
self._vg_uuid = value

@property
def snap_uuid(self):
return self._snap_uuid

@snap_uuid.setter
def snap_uuid(self, value):
self._snap_uuid = value
@property
def complete(self):
return self.snap_uuid and self.ctime and self.pd_name

namedtuple("Snapshot",
"pd_name cerebro_snap_uuid ctime vm_uuid snap_uuid")

def print_table_of_snapshots(snapshots):
"""
The function prints a well-fromated table for snapshots.
Args:
snapshots(Iterable list of objects with type 'Snapshot'):
list of snapshots to print.
"""
# Sort the snapshots.
snapshots = sorted(snapshots, key=operator.attrgetter('ctime'),
reverse=True)
snapshots = sorted(snapshots, key=operator.attrgetter('vg_uuid'))
snapshots = sorted(snapshots, key=operator.attrgetter('pd_name'),
reverse=True)
snapshots = sorted(snapshots, key=operator.attrgetter('complete'),
reverse=True)

# Length of the UUID hex string.


UUID_HEX_LENGTH=36
# Length of datetime string in format "%Y-%m-%d %H:%M"
TIME_STR_LENGTH=16
# Length of column of entity type.
ENTITY_TYPE_LENGTH=11
# Each column's header and width.
header = ["Snap UUID", "Entity Type", "Entity UUID", "Creation Time",
"Cerebro Snap UUID", "PD Name"]
col_widths = [UUID_HEX_LENGTH, ENTITY_TYPE_LENGTH, UUID_HEX_LENGTH,
TIME_STR_LENGTH, UUID_HEX_LENGTH, UUID_HEX_LENGTH]
def print_row(row):
"""
Helper function to print a row as formatted.
"""
print("".join(str(value).ljust(col_widths[idx]+2) for idx, value in
enumerate(row)))

print_row(header)
for ss in snapshots:
ctime = datetime.datetime.fromtimestamp(
ss.ctime / (1000 * 1000)).strftime(
'%Y-%m-%d %H:%M') if ss.ctime else None
entity_type = None
entity_uuid = None
if ss.vm_uuid:
entity_type = "VM"
entity_uuid = ss.vm_uuid
elif ss.vg_uuid:
entity_type="VG"
entity_uuid=ss.vg_uuid
print_row([ss.snap_uuid, entity_type, entity_uuid, ctime,
ss.cerebro_snap_uuid, ss.pd_name])

class BackupSnapshotClient(object):
"""
A simple python client to manage the snapshots created by backup software.
"""

def __init__(self, username, password):


self.cluster_url = "https://127.0.0.1:9440/api/nutanix/v3"
self.session = requests.Session()
self.user = username
self.password = password
self.session.auth = (self.user, self.password)

def __query_all_pd_names(self):
"""
Returns a set of all async PDs in the cluster including the name/UUID
of the system protection domain.
"""
cerebro_client = CerebroInterfaceTool()
pd_names = set()
arg = ListProtectionDomainsArg()
ret = cerebro_client.list_protection_domains(arg)
for pd_name in ret.protection_domain_name:
pd_names.add(PD(pd_name, False))

# Get the name of the System PD


system_pd_arg = ListProtectionDomainsArg()
system_pd_arg.list_system_pd = True
ret = cerebro_client.list_protection_domains(system_pd_arg)
for pd_name in ret.protection_domain_name:
pd_names.add(PD(pd_name, True))

return pd_names

def __query_pd_scoped_snapshots(self, pd_name):


"""
Query all the scoped/backup snapshots in the protection domain
specified by pd_name.

This function returns a set of Cerebro snapshot instances


representing the backup snapshots in the protection domain.
"""
cerebro_client = CerebroInterfaceTool()
pd_snaps = set()
arg = QueryProtectionDomainArg()
arg.protection_domain_name = pd_name
arg.list_snapshot_handles.list_scoped_snapshots = True
while True:
try:
ret = cerebro_client.query_protection_domain(arg)
if len(ret.snapshot_handle_vec) == 0:
break
for snapshot in ret.snapshot_control_block_vec:
pd_snaps.add(Snapshot(pd_name, snapshot.snapshot_uuid,
snapshot.finish_time_usecs))
# Continue listing remaining snapshots in the pd.
arg.ClearField("list_snapshot_handles")
arg.list_snapshot_handles.list_scoped_snapshots = True
arg.list_snapshot_handles.last_snapshot_handle.cluster_id = (
ret.snapshot_handle_vec[-1].cluster_id)
arg.list_snapshot_handles.last_snapshot_handle.cluster_incarnation_id = (
ret.snapshot_handle_vec[-1].cluster_incarnation_id)
arg.list_snapshot_handles.last_snapshot_handle.entity_id = (
ret.snapshot_handle_vec[-1].entity_id)
except CerebroInterfaceError as cie:
print ("Query protection domain returned error '%s'" % str(cie))
raise cie
return pd_snaps

def __get_vm_snapshots_from_intent_db(self):
"""
Queries the Aplos Intent Engine database for all the scoped snapshots whose
intent is in the database. This is done to get the snapshot ID seen by the
outside world. Returns a map of the form:
<key=Cerebro snapshot UUID, Value=tuple(VM UUID, external snapshot UUID)>.

Includes only scoped snapshots in kComplete state.


"""
def get_entity_uuid_from_spec(spec_json):
"""
Fetch the VM UUID from VM snapshot intent spec in Aplos.
"""
return spec_json["resources"]["entity_uuid"]

return self.__get_snapshots_from_intent_db(
snapshot_kind_name="vm_snapshot",
get_entity_uuid_from_spec=get_entity_uuid_from_spec)

def __get_vg_snapshots_from_intent_db(self):
"""
Queries the Aplos IntentEngine database for all the VG snapshots whose
intent is in the database.
The function returns a map of the form:
<key=Cerebro snapshot UUID, Value=tuple(VG UUID, external snapshot UUID)>.
The map includes only the snapshot in kComplete state.
"""
def get_entity_uuid_from_spec(spec_json):
"""
Fetch the VG UUID from VG snapshot intent spec in Aplos.
"""
return spec_json["resources"]["volume_group_reference"]["uuid"]

return self.__get_snapshots_from_intent_db(
snapshot_kind_name="volume_group_snapshot",
get_entity_uuid_from_spec=get_entity_uuid_from_spec)

def __get_snapshots_from_intent_db(self, snapshot_kind_name,


get_entity_uuid_from_spec):
"""
Queries the Aplos IntentEngine database for all the VM or VG snapshots
whose intent is in the database.
Args:
kind_name(string): Kind name of the snapshots of interest. It is
expected to be either 'vm_snapshot' or
'volume_group_snapshot'.
get_entity_uuid_from_spec(callable): The callable should take Aplos
intent spec in json and returns uuid of the snapshotted entity (VM or
VG).
Returns:
A map of the form:
<key=Cerebro snapshot UUID, Value=tuple(VG UUID, external snapshot UUID)>.
The map includes only the snapshot in kComplete state.
"""
snapshots = {}
predicates = []
predicates.append(EQ(COL("kind"), STR(snapshot_kind_name)))
predicates.append(EQ(COL("state"), STR("kComplete")))
requested_attribute_list = ['uuid', 'spec_json']
# The return value from intentgw_db is a list of tuples in the following
# format (intent_spec_uuid, (kind_uuid, spec_json)).
completed_scoped_snapshots = \
interfaces.intentgw_db.lookup_by_attribute_values(
kind_str="intent_spec",
requested_attributes=requested_attribute_list,
sort_order="ASCENDING",
sort_column="uuid",
where_clause=ALL(*predicates))
for snap in completed_scoped_snapshots:
intent_spec_uuid = snap[0]
external_snap_uuid = snap[1][0]
wal = AplosIntentSpecWal(intent_spec_uuid)
if wal.wal_proto.entity_snapshot_kind_wal.HasField(
"cerebro_snapshot_uuid"):
cerebro_snap_uuid = \
wal.wal_proto.entity_snapshot_kind_wal.cerebro_snapshot_uuid
spec_json = json.loads(snap[1][1]) if snap[1][1] else {}
if not spec_json:
# The corresponding intent_spec does not have spec_json. We need to
# remove the corresponding intent_specs as well during garbage
# collection. Hence, we record kind uuid here but leave
# vm_uuid blank.
snapshots[cerebro_snap_uuid] = ("NONE", external_snap_uuid)
continue
entity_uuid = get_entity_uuid_from_spec(spec_json)
snapshots[cerebro_snap_uuid] = (entity_uuid, external_snap_uuid)

return snapshots

def __list_backup_snapshots(self, pd_name=None):


"""
This function lists all VM / VG snapshots for backup which includes:
1.A complete snapshot (one has both aplos entity and cerebro backend
snapshot);
2.A lingering backend snapshot (a stale snapshot missing aplos entity);
3.A stale snapshot missing cerebro backend snapshot.

The function returns the above set by joining set of the backend snapshot
and set of entries from Aplos Intent Engine database using
cerebro backend snapshot UUID.

Returns:
Set of objects with type 'Snapshot'.
"""
scoped_snaps_from_cerebro = set()
if pd_name:
scoped_snaps_from_cerebro.update(
self.__query_pd_scoped_snapshots(pd_name))
else:
pds = self.__query_all_pd_names()
for pd in pds:
scoped_snaps_from_cerebro.update(
self.__query_pd_scoped_snapshots(pd.name))

vm_snaps_from_aplos = self.__get_vm_snapshots_from_intent_db()
vg_snaps_from_aplos = self.__get_vg_snapshots_from_intent_db()
cerebro_snapshot_uuids = set()
for snap in scoped_snaps_from_cerebro:
cerebro_snap_uuid = snap.cerebro_snap_uuid
cerebro_snapshot_uuids.add(cerebro_snap_uuid)
# Populate information for complete VM snapshots.
if cerebro_snap_uuid in vm_snaps_from_aplos:
snap.vm_uuid = vm_snaps_from_aplos[cerebro_snap_uuid][0]
snap.snap_uuid = vm_snaps_from_aplos[cerebro_snap_uuid][1]

# Populate information for complete VG snapshots.


if cerebro_snap_uuid in vg_snaps_from_aplos:
snap.vg_uuid = vg_snaps_from_aplos[cerebro_snap_uuid][0]
snap.snap_uuid = vg_snaps_from_aplos[cerebro_snap_uuid][1]

# In case when there are dangling intent specs in Aplos (possible because
# cerebro snapshots can be manually deleted by mistake), we also
# need to list them and indicate that the intent specs are left behind.
# We should only do this when we are trying to list all scoped snapshots
# in the system. Otherwise, we don't have enough information to determine
# which cerebro snapshots are lacking intent specs in Aplos.
if not pd_name:

def add_stale_snapshots(snaps_from_aplos, is_vm):


"""
Helper method to find snapshot with dangling intent specs in Aplos and
add those stale snapshots to result list.
Args:
snaps_from_aplos(dict): Map from cerebro snapshot uuid to tuple of
(entity uuid, external snapshot uuid)
is_vm(bool): True if the entity type is a VM. Otherwise, it is a VG.
"""
for cerebro_snap_uuid in snaps_from_aplos:
if cerebro_snap_uuid not in cerebro_snapshot_uuids:
snap = Snapshot(None, cerebro_snap_uuid, None)
entity_uuid = snaps_from_aplos[cerebro_snap_uuid][0]
if is_vm:
snap.vm_uuid = entity_uuid
else:
snap.vg_uuid = entity_uuid
snap.snap_uuid = snaps_from_aplos[cerebro_snap_uuid][1]
scoped_snaps_from_cerebro.add(snap)

# Find stale VM snapshots missing cerebro backend snapshot.


add_stale_snapshots(vm_snaps_from_aplos, is_vm=True)

# Find stale VG snapshots missing cerebro backend snapshot.


add_stale_snapshots(vg_snaps_from_aplos, is_vm=False)

return scoped_snaps_from_cerebro

def __delete_scoped_snap_through_cerebro(self, cerebro_snap_uuid):


"""
Deletes the backup snapshot specified by 'cerebro_snap_uuid' from Cerebro.
"""
cerebro_client = CerebroInterfaceTool()
arg = ModifySnapshotArg()
arg.snapshot_uuid = NutanixUuid.from_hex(cerebro_snap_uuid).bytes
arg.expiry_time_usecs = 0
cerebro_client.modify_snapshot(arg)

def print_scoped_snaps_in_pd(self, pd_name=None):


"""
Formats and prints the scoped snapshots in the specified PD on the
terminal screen.
"""
scoped_snaps = self.__list_backup_snapshots(pd_name)
if not scoped_snaps or not len(scoped_snaps):
print ("There are no backup snapshots to list.")
return
sorted_scoped_snaps = sorted(scoped_snaps)
print ("There are %d backup snapshots.\n" % len(sorted_scoped_snaps))
print_table_of_snapshots(scoped_snaps)

def print_vm_scoped_snaps(self, vm_uuid=None):


"""
Formats and prints the scoped snapshots of the specified VM on the
terminal screen.
"""
scoped_snaps = self.__list_backup_snapshots()
if not scoped_snaps or not len(scoped_snaps):
print ("There are no backup snapshots to list.")
return

scoped_snaps_to_print = set()
for ss in scoped_snaps:
if ss.vm_uuid == vm_uuid:
scoped_snaps_to_print.add(ss)

print ("There are %d backup snapshots.\n" % len(scoped_snaps_to_print))


print_table_of_snapshots(scoped_snaps_to_print)

def print_vg_scoped_snaps(self, vg_uuid = None):


scoped_snaps = self.__list_backup_snapshots()
if not scoped_snaps:
print("There are no backup snapshots for VG %s to list" % vg_uuid)
return

scoped_snaps_to_print = filter(lambda ss: ss.vg_uuid == vg_uuid,


scoped_snaps)

print("There are %d backup snapshots for VG %s." %


(len(scoped_snaps_to_print), vg_uuid))
print("")
print_table_of_snapshots(scoped_snaps_to_print)

def delete_vm_snapshot(self, snapshot_uuid):


"""
Submits a request to delete the snapshot with UUID, 'snapshot_uuid'.
"""
if not snapshot_uuid:
return
rep = self.session.delete(
self.cluster_url + "/vm_snapshots/" + snapshot_uuid,
verify=False)
if rep.status_code in [200, 202]:
print ("Successfully submitted the request to delete VM snapshot %s" %
snapshot_uuid)
else:
print ("Failed to delete VG snapshot %s: %s" %
(snapshot_uuid, rep.status_code))

def delete_vg_snapshot(self, snapshot_uuid):


"""
Submits a request to delete the VG snapshot with UUID 'snapshot_uuid'.
Args:
snapshot_uuid(str): UUID in string format.
Returns:
None
"""
if not snapshot_uuid:
return
rep = self.session.delete(
self.cluster_url + "/volume_group_snapshots/" + snapshot_uuid,
verify=False)
if rep.status_code in [200, 202]:
print("Sucessfully submitted the request to delete VG snapshot %s" %
snapshot_uuid)
else:
print("Failed to delete VG snapshot %s: %s " %
(snapshot_uuid, rep.status_code))

def delete_snapshots_for_vm(self, vm_uuid):


"""
Deletes the backup snapshots of the virtual machine with UUID, 'vm_uuid'.
"""
if not vm_uuid:
print ("Please specify the virtual machine whose snapshots must be "
"deleted")
return
scoped_snaps = self.__list_backup_snapshots()
if not scoped_snaps:
print ("There are no VM backup snapshots to delete")
return
for ss in scoped_snaps:
if ss.vm_uuid == vm_uuid:
self.delete_vm_snapshot(ss.snap_uuid)

def delete_snapshots_for_vg(self, vg_uuid):


"""
Deletes the backup snapshots of the volume group with UUID 'vg_uuid'.
"""
if not vg_uuid:
print("Please specify the volume group whose snapshots must be deleted")
return

backup_snaps = self.__list_backup_snapshots()
if not backup_snaps:
print("There is no VG backup snapshot to delete")
return

for snap in backup_snaps:


if snap.vg_uuid == vg_uuid:
self.delete_vg_snapshot(snap.snap_uuid)

def delete_snapshots_for_pd(self, pd_name):


"""
Deletes all the backup snapshots in the protection domain specified
by 'pd_name'.
"""
if not pd_name:
print ("Please specify the protection domain whose snapshots "
"must be deleted")
return
scoped_snaps = self.__list_backup_snapshots(pd_name)
if not scoped_snaps:
print ("There are no backup snapshots to delete")
return
for ss in scoped_snaps:
if ss.snap_uuid:
# The snapshot has a corresponding intent spec. Hence, we need to
# delete through intent gateway.
if ss.vm_uuid:
self.delete_vm_snapshot(ss.snap_uuid)
else:
self.delete_vg_snapshot(ss.snap_uuid)
else:
# The snapshot does not have a corresponding intent spec. Delete
# the snapshot through Cerebro instead.
self.__delete_scoped_snap_through_cerebro(ss.cerebro_snap_uuid)

def delete_all_snapshots(self):
"""
Deletes all the backup snapshots in the cluster.
"""
scoped_snaps = self.__list_backup_snapshots()
if not scoped_snaps:
print ("There are no backup snapshots to delete")
return
for ss in scoped_snaps:
if ss.snap_uuid:
# The snapshot has a corresponding intent spec. Hence, we need to
# delete through intent gateway.
if ss.vm_uuid:
self.delete_vm_snapshot(ss.snap_uuid)
else:
self.delete_vg_snapshot(ss.snap_uuid)
else:
# The snapshot does not have a corresponding intent spec. Delete
# the snapshot through Cerebro instead.
self.__delete_scoped_snap_through_cerebro(ss.cerebro_snap_uuid)

def delete_scoped_snap_through_cerebro(self, cerebro_snap_uuid):


"""
Deletes the backup snapshots when cerebro snapshot uuid is given,
'cerebro_snap_uuid'.
"""
if not cerebro_snap_uuid:
print ("No uuid provided")
return
vm_snaps_from_aplos = self.__get_vm_snapshots_from_intent_db()
if cerebro_snap_uuid in vm_snaps_from_aplos:
print ("Cannot delete the cerebro snapshot since it has Aplos metadata")
return

vg_snaps_from_aplos = self.__get_vg_snapshots_from_intent_db()
if cerebro_snap_uuid in vg_snaps_from_aplos:
print ("Cannot delete the cerebro snapshot since it has Aplos metadata")
return

self.__delete_scoped_snap_through_cerebro(cerebro_snap_uuid)
print ("Deleted snapshot through cerbro : %s" % cerebro_snap_uuid)

def delete_snapshot_older_than_given_num_of_days(self, num_of_days):


"""
Deletes the backup snapshots older than given number of days,
'num_of_days'.
"""
if not num_of_days:
print ("Please specify number of days")
return

# Get all the backup snapshots.


scoped_snaps = self.__list_backup_snapshots()
if not scoped_snaps:
print ("There are no backup snapshots to delete")
return

# Find all the old and complete snapshots to delete.


current_time = float(round(time.time() * 1000 * 1000))
def to_delete(ss):
"""
Check whether a snapshot should be deleted here
"""
# Ignore stale backup snapshots.
if not ss.snap_uuid or not ss.ctime:
return None

# Return true for snapshots older than given num of days.


age = (current_time - ss.ctime) / (1000 * 1000 * 60 * 60 * 24)
return age > num_of_days
scoped_snaps_to_delete = filter(to_delete, scoped_snaps)

# Remove the complete snapshots that are older than specified num of days.
print("Deleting following snapshots that are older than %s days" %
num_of_days)
print_table_of_snapshots(scoped_snaps_to_delete)
for ss in scoped_snaps_to_delete:
if ss.vm_uuid:
self.delete_vm_snapshot(ss.snap_uuid)
else:
self.delete_vg_snapshot(ss.snap_uuid)

def list_stale_snapshots_missing_snapshot_objects(self):
"""
Lists all stale snapshots that has proper entry in IDF but no
snapshot data, i.e, no cerebro backend snapshot.
"""
# List all backup snapshots in the cluster.
snap_list = self.__list_backup_snapshots()

# Find all stale snapshots with backend snapshot missing.


stale_snapshots_in_idf = filter(
lambda snap: not snap.pd_name and not snap.ctime,
snap_list)

# Format and print the result.


if stale_snapshots_in_idf:
print_table_of_snapshots(stale_snapshots_in_idf)
else:
print ("No stale snapshots missing snapshot data found")

if __name__ == "__main__":
parser = argparse.ArgumentParser("backup_snapshots")
parser.add_argument("user", help="Username of the account")
parser.add_argument("password", action=Password, nargs='?',
help="Password of the account. Do not enter on the "
"command line.")

group = parser.add_mutually_exclusive_group()
group.add_argument("--list_for_pd",
help="List all the backup snapshots of the PD",
metavar="<Name of the PD>", type=str)

group.add_argument("--list_for_vm",
help="List all the backup snapshots of the VM",
metavar="<UUID of the VM>",
type=str)

group.add_argument("--list_for_vg",
help="List all the backup snapshots of the VG",
metavar="<UUID of the VG>",
type=str)

group.add_argument("--list_all",
help="List all backup snapshots in the cluster",
action="store_true")

group.add_argument("--list_stale_snapshots_missing_snapshot_objects",
help="Lists all stale snapshots that its Cerebro "
"backend snapshot is missing",
action="store_true")

group.add_argument("--delete_vm_snapshot",
help="Delete the VM snapshot specified by UUID",
metavar="<VM Snapshot UUID>",
type=str)

group.add_argument("--delete_vg_snapshot",
help="Delete the VG snapshot specified by UUID",
metavar="<VG Snapshot UUID>",
type=str)

group.add_argument("--delete_for_vm",
help="Delete the snapshots of the virtual machine "
"specified by UUID",
metavar="<UUID of the VM>",
type=str)
group.add_argument("--delete_for_vg",
help="Delete the snapshots of the volume group "
"specified by UUID",
metavar="<UUID of the VG>",
type=str)

group.add_argument("--delete_for_pd",
help="Delete the snapshots of the protection domain "
"specified by pd_name",
metavar="<Name of the PD>")

group.add_argument("--delete_all",
help="Delete all backup snapshots in the cluster",
action="store_true")

group.add_argument("--delete_snapshot_from_cerebro",
help="Delete the snapshot specified by cerebro UUID",
metavar="<Cerebro Snapshot UUID>",
type=str)

group.add_argument("--delete_snapshot_older_than",
help="Delete the snapshot older than given number of "
"days",
metavar="<Number of days>",
type=int)

args = parser.parse_args()

client = BackupSnapshotClient(args.user, args.password)

if args.list_all:
client.print_scoped_snaps_in_pd(None)

if args.list_for_pd:
client.print_scoped_snaps_in_pd(args.list_for_pd)

if args.list_for_vm:
client.print_vm_scoped_snaps(args.list_for_vm)

if args.list_for_vg:
client.print_vg_scoped_snaps(args.list_for_vg)

if args.list_stale_snapshots_missing_snapshot_objects:
client.list_stale_snapshots_missing_snapshot_objects()

if args.delete_vm_snapshot:
client.delete_vm_snapshot(args.delete_vm_snapshot)

if args.delete_vg_snapshot:
client.delete_vg_snapshot(args.delete_vg_snapshot)

if args.delete_for_vm:
client.delete_snapshots_for_vm(args.delete_for_vm)

if args.delete_for_vg:
client.delete_snapshots_for_vg(args.delete_for_vg)

if args.delete_for_pd:
client.delete_snapshots_for_pd(args.delete_for_pd)

if args.delete_all:
client.delete_all_snapshots()

if args.delete_snapshot_from_cerebro:
client.delete_scoped_snap_through_cerebro(
args.delete_snapshot_from_cerebro)

if args.delete_snapshot_older_than:
client.delete_snapshot_older_than_given_num_of_days(
args.delete_snapshot_older_than)

You might also like