Add VM snapshot removal
This commit is contained in:
parent
553c1e670e
commit
0c240a5129
|
@ -3130,6 +3130,48 @@ class API_VM_Snapshot(Resource):
|
||||||
snapshot_name = reqargs.get("snapshot_name", None)
|
snapshot_name = reqargs.get("snapshot_name", None)
|
||||||
return api_helper.create_vm_snapshot(vm, snapshot_name=snapshot_name)
|
return api_helper.create_vm_snapshot(vm, snapshot_name=snapshot_name)
|
||||||
|
|
||||||
|
@RequestParser(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "snapshot_name",
|
||||||
|
"required": True,
|
||||||
|
"helptext": "A snapshot name must be specified",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@Authenticator
|
||||||
|
def delete(self, vm, reqargs):
|
||||||
|
"""
|
||||||
|
Remove a snapshot of a VM's disks and configuration
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- vm
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: snapshot_name
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: The name of the snapshot to remove
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
400:
|
||||||
|
description: Execution error
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
404:
|
||||||
|
description: Not found
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
"""
|
||||||
|
snapshot_name = reqargs.get("snapshot_name", None)
|
||||||
|
return api_helper.remove_vm_snapshot(vm, snapshot_name)
|
||||||
|
|
||||||
|
|
||||||
api.add_resource(API_VM_Snapshot, "/vm/<vm>/snapshot")
|
api.add_resource(API_VM_Snapshot, "/vm/<vm>/snapshot")
|
||||||
|
|
||||||
|
|
|
@ -789,6 +789,30 @@ def create_vm_snapshot(
|
||||||
return output, retcode
|
return output, retcode
|
||||||
|
|
||||||
|
|
||||||
|
@ZKConnection(config)
|
||||||
|
def remove_vm_snapshot(
|
||||||
|
zkhandler,
|
||||||
|
domain,
|
||||||
|
snapshot_name,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Take a snapshot of a VM.
|
||||||
|
"""
|
||||||
|
retflag, retdata = pvc_vm.remove_vm_snapshot(
|
||||||
|
zkhandler,
|
||||||
|
domain,
|
||||||
|
snapshot_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
if retflag:
|
||||||
|
retcode = 200
|
||||||
|
else:
|
||||||
|
retcode = 400
|
||||||
|
|
||||||
|
output = {"message": retdata.replace('"', "'")}
|
||||||
|
return output, retcode
|
||||||
|
|
||||||
|
|
||||||
@ZKConnection(config)
|
@ZKConnection(config)
|
||||||
def vm_attach_device(zkhandler, vm, device_spec_xml):
|
def vm_attach_device(zkhandler, vm, device_spec_xml):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1787,10 +1787,10 @@ def cli_vm_snapshot():
|
||||||
@connection_req
|
@connection_req
|
||||||
@click.argument("domain")
|
@click.argument("domain")
|
||||||
@click.argument("snapshot_name", required=False, default=None)
|
@click.argument("snapshot_name", required=False, default=None)
|
||||||
def cli_vm_snapshot_create(domain, snapshot_name):
|
def cli_vm_snapshot_remove(domain, snapshot_name):
|
||||||
"""
|
"""
|
||||||
Create a snapshot of the disks and XML configuration of virtual machine DOMAIN, with the
|
Create a snapshot of the disks and XML configuration of virtual machine DOMAIN, with the
|
||||||
optional name SNAPSHOT_NAME. DOMAIN mayb e a UUID or name.
|
optional name SNAPSHOT_NAME. DOMAIN may be a UUID or name.
|
||||||
|
|
||||||
WARNING: RBD snapshots are crash-consistent but not filesystem-aware. If a snapshot was taken
|
WARNING: RBD snapshots are crash-consistent but not filesystem-aware. If a snapshot was taken
|
||||||
of a running VM, restoring that snapshot will be equivalent to having forcibly restarted the
|
of a running VM, restoring that snapshot will be equivalent to having forcibly restarted the
|
||||||
|
@ -1812,6 +1812,32 @@ def cli_vm_snapshot_create(domain, snapshot_name):
|
||||||
finish(retcode, retmsg)
|
finish(retcode, retmsg)
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# > pvc vm snapshot remove
|
||||||
|
###############################################################################
|
||||||
|
@click.command(name="remove", short_help="Remove a snapshot of a virtual machine.")
|
||||||
|
@connection_req
|
||||||
|
@click.argument("domain")
|
||||||
|
@click.argument("snapshot_name")
|
||||||
|
def cli_vm_snapshot_create(domain, snapshot_name):
|
||||||
|
"""
|
||||||
|
Remove the snapshot SNAPSHOT_NAME of the disks and XML configuration of virtual machine DOMAIN,
|
||||||
|
DOMAIN may be a UUID or name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
echo(
|
||||||
|
CLI_CONFIG,
|
||||||
|
f"Removing snapshot '{snapshot_name}' of VM '{domain}'... ",
|
||||||
|
newline=False,
|
||||||
|
)
|
||||||
|
retcode, retmsg = pvc.lib.vm.vm_remove_snapshot(CLI_CONFIG, domain, snapshot_name)
|
||||||
|
if retcode:
|
||||||
|
echo(CLI_CONFIG, "done.")
|
||||||
|
else:
|
||||||
|
echo(CLI_CONFIG, "failed.")
|
||||||
|
finish(retcode, retmsg)
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# > pvc vm backup
|
# > pvc vm backup
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -6350,6 +6376,7 @@ cli_vm.add_command(cli_vm_migrate)
|
||||||
cli_vm.add_command(cli_vm_unmigrate)
|
cli_vm.add_command(cli_vm_unmigrate)
|
||||||
cli_vm.add_command(cli_vm_flush_locks)
|
cli_vm.add_command(cli_vm_flush_locks)
|
||||||
cli_vm_snapshot.add_command(cli_vm_snapshot_create)
|
cli_vm_snapshot.add_command(cli_vm_snapshot_create)
|
||||||
|
cli_vm_snapshot.add_command(cli_vm_snapshot_remove)
|
||||||
cli_vm.add_command(cli_vm_snapshot)
|
cli_vm.add_command(cli_vm_snapshot)
|
||||||
cli_vm_backup.add_command(cli_vm_backup_create)
|
cli_vm_backup.add_command(cli_vm_backup_create)
|
||||||
cli_vm_backup.add_command(cli_vm_backup_restore)
|
cli_vm_backup.add_command(cli_vm_backup_restore)
|
||||||
|
|
|
@ -519,6 +519,25 @@ def vm_create_snapshot(config, vm, snapshot_name=None):
|
||||||
return True, response.json().get("message", "")
|
return True, response.json().get("message", "")
|
||||||
|
|
||||||
|
|
||||||
|
def vm_remove_snapshot(config, vm, snapshot_name):
|
||||||
|
"""
|
||||||
|
Remove a snapshot of a VM's disks and configuration
|
||||||
|
|
||||||
|
API endpoint: DELETE /vm/{vm}/snapshot
|
||||||
|
API arguments: snapshot_name=snapshot_name
|
||||||
|
API schema: {"message":"{data}"}
|
||||||
|
"""
|
||||||
|
params = {"snapshot_name": snapshot_name}
|
||||||
|
response = call_api(
|
||||||
|
config, "delete", "/vm/{vm}/snapshot".format(vm=vm), params=params
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
return False, response.json().get("message", "")
|
||||||
|
else:
|
||||||
|
return True, response.json().get("message", "")
|
||||||
|
|
||||||
|
|
||||||
def vm_vcpus_set(config, vm, vcpus, topology, restart):
|
def vm_vcpus_set(config, vm, vcpus, topology, restart):
|
||||||
"""
|
"""
|
||||||
Set the vCPU count of the VM with topology
|
Set the vCPU count of the VM with topology
|
||||||
|
|
|
@ -1249,7 +1249,7 @@ def get_list(
|
||||||
#
|
#
|
||||||
# VM Snapshot Tasks
|
# VM Snapshot Tasks
|
||||||
#
|
#
|
||||||
def create_vm_snapshot(zkhandler, domain, snapshot_name=None):
|
def create_vm_snapshot(zkhandler, domain, snapshot_name=None, is_backup=False):
|
||||||
# Validate that VM exists in cluster
|
# Validate that VM exists in cluster
|
||||||
dom_uuid = getDomainUUID(zkhandler, domain)
|
dom_uuid = getDomainUUID(zkhandler, domain)
|
||||||
if not dom_uuid:
|
if not dom_uuid:
|
||||||
|
@ -1310,7 +1310,7 @@ def create_vm_snapshot(zkhandler, domain, snapshot_name=None):
|
||||||
"domain_snapshot.is_backup",
|
"domain_snapshot.is_backup",
|
||||||
snapshot_name,
|
snapshot_name,
|
||||||
),
|
),
|
||||||
False,
|
is_backup,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
("domain.snapshots", dom_uuid, "domain_snapshot.xml", snapshot_name),
|
("domain.snapshots", dom_uuid, "domain_snapshot.xml", snapshot_name),
|
||||||
|
@ -1336,14 +1336,66 @@ def create_vm_snapshot(zkhandler, domain, snapshot_name=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_vm_snapshot(zkhandler, domain, snapshot_name, remove_backup=False):
|
||||||
|
# Validate that VM exists in cluster
|
||||||
|
dom_uuid = getDomainUUID(zkhandler, domain)
|
||||||
|
if not dom_uuid:
|
||||||
|
return False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain)
|
||||||
|
|
||||||
|
if not zkhandler.exists(
|
||||||
|
("domain.snapshots", dom_uuid, "domain_snapshot.name", snapshot_name)
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
False,
|
||||||
|
f'ERROR: Could not find snapshot "{snapshot_name}" of VM "{domain}"!',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
zkhandler.read(
|
||||||
|
("domain.snapshots", dom_uuid, "domain_snapshot.is_backup", snapshot_name)
|
||||||
|
)
|
||||||
|
and not remove_backup
|
||||||
|
):
|
||||||
|
# Disallow removing backups normally, but expose `remove_backup` flag for internal usage by refactored backup handlers
|
||||||
|
return (
|
||||||
|
False,
|
||||||
|
f'ERROR: Snapshot "{snapshot_name}" of VM "{domain}" is a backup; please remove with "pvc backup"!',
|
||||||
|
)
|
||||||
|
|
||||||
|
tstart = time.time()
|
||||||
|
|
||||||
|
_snapshots = zkhandler.read(
|
||||||
|
("domain.snapshots", dom_uuid, "domain_snapshot.rbd_snapshots", snapshot_name)
|
||||||
|
)
|
||||||
|
rbd_snapshots = _snapshots.split(",")
|
||||||
|
for snap in rbd_snapshots:
|
||||||
|
name, rbd = snap.split("@")
|
||||||
|
pool, volume = rbd.split("/")
|
||||||
|
ret, msg = ceph.remove_snapshot(zkhandler, pool, volume, name)
|
||||||
|
if not ret:
|
||||||
|
return False, msg
|
||||||
|
|
||||||
|
ret = zkhandler.delete(
|
||||||
|
("domain.snapshots", dom_uuid, "domain_snapshot.name", snapshot_name)
|
||||||
|
)
|
||||||
|
if not ret:
|
||||||
|
return (
|
||||||
|
False,
|
||||||
|
f'ERROR: Failed to delete snapshot "{snapshot_name}" of VM "{domain}" in Zookeeper.',
|
||||||
|
)
|
||||||
|
|
||||||
|
tend = time.time()
|
||||||
|
ttot = round(tend - tstart, 2)
|
||||||
|
return (
|
||||||
|
True,
|
||||||
|
f'Successfully removed snapshot "{snapshot_name}" of VM "{domain}" in {ttot}s.',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def rollback_vm_snapshot(zkhandler, domain, snapshot_name):
|
def rollback_vm_snapshot(zkhandler, domain, snapshot_name):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def remove_vm_snapshot(zkhandler, domain, snapshot_name):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# VM Backup Tasks
|
# VM Backup Tasks
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in New Issue