Compare commits

..

4 Commits

Author SHA1 Message Date
221af3f241 Bump version to 0.9.79 2023-10-24 02:10:24 -04:00
35f80e544c Use more hierarchical backup path structure 2023-10-24 02:04:16 -04:00
83b937654c Avoid removing nonexistent snapshots
Store retain_snapshot in JSON and use that to check during delete.
2023-10-24 01:35:00 -04:00
714bde89e6 Fix incorrect variable ref 2023-10-24 01:25:01 -04:00
7 changed files with 54 additions and 37 deletions

View File

@ -1 +1 @@
0.9.78
0.9.79

View File

@ -1,5 +1,15 @@
## PVC Changelog
###### [v0.9.79](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.79)
**API Changes**: New endpoints /vm/{vm}/backup, /vm/{vm}/restore
* [CLI Client] Fixes some storage pool help text messages
* [Node Daemon] Increases the IPMI monitoring plugin timeout
* [All] Adds support for VM backups, including creation, removal, and restore
* [Repository] Fixes shebangs in scripts to be consistent
* [Daemon Library] Improves the handling of VM list arguments (default None)
###### [v0.9.78](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.78)
* [API, Client CLI] Fixes several bugs around image uploads; adds a new query parameter for non-raw images

View File

@ -27,7 +27,7 @@ from ssl import SSLContext, TLSVersion
from distutils.util import strtobool as dustrtobool
# Daemon version
version = "0.9.78"
version = "0.9.79"
# API version
API_VERSION = 1.0

View File

@ -2,7 +2,7 @@ from setuptools import setup
setup(
name="pvc",
version="0.9.78",
version="0.9.79",
packages=["pvc.cli", "pvc.lib"],
install_requires=[
"Click",

View File

@ -30,7 +30,6 @@ from datetime import datetime
from distutils.util import strtobool
from json import dump as jdump
from json import load as jload
from os import remove
from shutil import rmtree
from socket import gethostname
from uuid import UUID
@ -1403,7 +1402,7 @@ def backup_vm(
# 4. Create destination directory
vm_target_root = f"{backup_path}/{domain}"
vm_target_backup = f"{backup_path}/{domain}/{domain}.{datestring}.pvcdisks"
vm_target_backup = f"{backup_path}/{domain}/{datestring}/pvcdisks"
if not os.path.isdir(vm_target_backup):
try:
os.makedirs(vm_target_backup)
@ -1468,13 +1467,13 @@ def backup_vm(
"type": backup_type,
"datestring": datestring,
"incremental_parent": incremental_parent,
"retained_snapshot": retain_snapshot,
"vm_detail": vm_detail,
"backup_files": [
(f"{domain}.{datestring}.pvcdisks/{p}.{v}.{export_fileext}", s)
for p, v, s in vm_volumes
(f"pvcdisks/{p}.{v}.{export_fileext}", s) for p, v, s in vm_volumes
],
}
with open(f"{vm_target_root}/{domain}.{datestring}.pvcbackup", "w") as fh:
with open(f"{vm_target_root}/{datestring}/pvcbackup.json", "w") as fh:
jdump(vm_backup, fh)
# 8. Remove snapshots if retain_snapshot is False
@ -1535,18 +1534,16 @@ def remove_backup(zkhandler, domain, backup_path, datestring):
return False, f"ERROR: Source path {backup_path} does not exist!"
# Ensure that domain path (on this node) exists
backup_backup_path = f"{backup_path}/{domain}"
if not os.path.isdir(backup_backup_path):
return False, f"ERROR: Source VM path {backup_backup_path} does not exist!"
vm_backup_path = f"{backup_path}/{domain}"
if not os.path.isdir(vm_backup_path):
return False, f"ERROR: Source VM path {vm_backup_path} does not exist!"
# Ensure that the archives are present
backup_source_pvcbackup_file = (
f"{backup_backup_path}/{domain}.{datestring}.pvcbackup"
)
backup_source_pvcbackup_file = f"{vm_backup_path}/{datestring}/pvcbackup.json"
if not os.path.isfile(backup_source_pvcbackup_file):
return False, "ERROR: The specified source backup files do not exist!"
backup_source_pvcdisks_path = f"{backup_backup_path}/{domain}.{datestring}.pvcdisks"
backup_source_pvcdisks_path = f"{vm_backup_path}/{datestring}/pvcdisks"
if not os.path.isdir(backup_source_pvcdisks_path):
return False, "ERROR: The specified source backup files do not exist!"
@ -1561,21 +1558,21 @@ def remove_backup(zkhandler, domain, backup_path, datestring):
is_snapshot_remove_failed = False
which_snapshot_remove_failed = list()
msg_snapshot_remove_failed = list()
for volume_file, _ in backup_source_details.get("backup_files"):
pool, volume, _ = volume_file.split("/")[-1].split(".")
snapshot = f"backup_{datestring}"
retcode, retmsg = ceph.remove_snapshot(zkhandler, pool, volume, snapshot)
if not retcode:
is_snapshot_remove_failed = True
which_snapshot_remove_failed.append(f"{pool}/{volume}")
msg_snapshot_remove_failed.append(retmsg)
if backup_source_details["retained_snapshot"]:
for volume_file, _ in backup_source_details.get("backup_files"):
pool, volume, _ = volume_file.split("/")[-1].split(".")
snapshot = f"backup_{datestring}"
retcode, retmsg = ceph.remove_snapshot(zkhandler, pool, volume, snapshot)
if not retcode:
is_snapshot_remove_failed = True
which_snapshot_remove_failed.append(f"{pool}/{volume}")
msg_snapshot_remove_failed.append(retmsg)
# 3. Remove files
is_files_remove_failed = False
msg_files_remove_failed = None
try:
remove(backup_source_pvcbackup_file)
rmtree(backup_source_pvcdisks_path)
rmtree(f"{vm_backup_path}/{datestring}")
except Exception as e:
is_files_remove_failed = True
msg_files_remove_failed = e
@ -1626,14 +1623,12 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
return False, f"ERROR: Source path {backup_path} does not exist!"
# Ensure that domain path (on this node) exists
backup_backup_path = f"{backup_path}/{domain}"
if not os.path.isdir(backup_backup_path):
return False, f"ERROR: Source VM path {backup_backup_path} does not exist!"
vm_backup_path = f"{backup_path}/{domain}"
if not os.path.isdir(vm_backup_path):
return False, f"ERROR: Source VM path {vm_backup_path} does not exist!"
# Ensure that the archives are present
backup_source_pvcbackup_file = (
f"{backup_backup_path}/{domain}.{datestring}.pvcbackup"
)
backup_source_pvcbackup_file = f"{vm_backup_path}/{datestring}/pvcbackup.json"
if not os.path.isfile(backup_source_pvcbackup_file):
return False, "ERROR: The specified source backup files do not exist!"
@ -1648,7 +1643,7 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
incremental_parent = backup_source_details.get("incremental_parent", None)
if incremental_parent is not None:
backup_source_parent_pvcbackup_file = (
f"{backup_backup_path}/{domain}.{incremental_parent}.pvcbackup"
f"{vm_backup_path}/{incremental_parent}/pvcbackup.json"
)
if not os.path.isfile(backup_source_parent_pvcbackup_file):
return (
@ -1724,7 +1719,7 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
# Next we import the parent images
retcode, stdout, stderr = common.run_os_command(
f"rbd import --export-format 2 --dest-pool {pool} {backup_path}/{domain}/{parent_volume_file} {volume}"
f"rbd import --export-format 2 --dest-pool {pool} {backup_path}/{domain}/{incremental_parent}/{parent_volume_file} {volume}"
)
if retcode:
return (
@ -1734,7 +1729,7 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
# Then we import the incremental diffs
retcode, stdout, stderr = common.run_os_command(
f"rbd import-diff {backup_path}/{domain}/{volume_file} {pool}/{volume}"
f"rbd import-diff {backup_path}/{domain}/{datestring}/{volume_file} {pool}/{volume}"
)
if retcode:
return (
@ -1796,7 +1791,7 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
# Then we perform the actual import
retcode, stdout, stderr = common.run_os_command(
f"rbd import --export-format 2 --dest-pool {pool} {backup_path}/{domain}/{volume_file} {volume}"
f"rbd import --export-format 2 --dest-pool {pool} {backup_path}/{domain}/{datestring}/{volume_file} {volume}"
)
if retcode:
return (
@ -1810,7 +1805,7 @@ def restore_vm(zkhandler, domain, backup_path, datestring, retain_snapshot=False
zkhandler,
pool,
volume,
f"backup_{incremental_parent}",
f"backup_{datestring}",
zk_only=True,
)
if not retcode:

12
debian/changelog vendored
View File

@ -1,3 +1,15 @@
pvc (0.9.79-0) unstable; urgency=high
**API Changes**: New endpoints /vm/{vm}/backup, /vm/{vm}/restore
* [CLI Client] Fixes some storage pool help text messages
* [Node Daemon] Increases the IPMI monitoring plugin timeout
* [All] Adds support for VM backups, including creation, removal, and restore
* [Repository] Fixes shebangs in scripts to be consistent
* [Daemon Library] Improves the handling of VM list arguments (default None)
-- Joshua M. Boniface <joshua@boniface.me> Tue, 24 Oct 2023 02:10:24 -0400
pvc (0.9.78-0) unstable; urgency=high
* [API, Client CLI] Fixes several bugs around image uploads; adds a new query parameter for non-raw images

View File

@ -49,7 +49,7 @@ import re
import json
# Daemon version
version = "0.9.78"
version = "0.9.79"
##########################################################