Compare commits
5 Commits
v0.9.99
...
17f2f4a30c
Author | SHA1 | Date | |
---|---|---|---|
17f2f4a30c | |||
783c9e46c2 | |||
b7f33c1fcb | |||
0f578d7c7d | |||
f87b96887c |
@ -4,4 +4,4 @@ bbuilder:
|
|||||||
published:
|
published:
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- /bin/bash build-stable-deb.sh
|
- /bin/bash build-stable-deb.sh
|
||||||
- sudo /usr/local/bin/deploy-package -C pvc
|
- sudo /usr/local/bin/deploy-package -C pvc -D bookworm
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
## PVC Changelog
|
## PVC Changelog
|
||||||
|
|
||||||
|
###### [v0.9.100](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.100)
|
||||||
|
|
||||||
|
* [API Daemon] Improves the handling of "detect:" disk strings on newer systems by leveraging the "nvme" command
|
||||||
|
* [Meta] Updates deprecation warnings and updates builder to only add this version for Debian 12 (Bookworm)
|
||||||
|
|
||||||
###### [v0.9.99](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.99)
|
###### [v0.9.99](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.99)
|
||||||
|
|
||||||
**Deprecation Warning**: `pvc vm backup` commands are now deprecated and will be removed in **0.9.100**. Use `pvc vm snapshot` commands instead.
|
**Deprecation Warning**: `pvc vm backup` commands are now deprecated and will be removed in a future version. Use `pvc vm snapshot` commands instead.
|
||||||
**Breaking Change**: The on-disk format of VM snapshot exports differs from backup exports, and the PVC autobackup system now leverages these. It is recommended to start fresh with a new tree of backups for `pvc autobackup` for maximum compatibility.
|
**Breaking Change**: The on-disk format of VM snapshot exports differs from backup exports, and the PVC autobackup system now leverages these. It is recommended to start fresh with a new tree of backups for `pvc autobackup` for maximum compatibility.
|
||||||
**Breaking Change**: VM autobackups now run in `pvcworkerd` instead of the CLI client directly, allowing them to be triggerd from any node (or externally). It is important to apply the timer unit changes from the `pvc-ansible` role after upgrading to 0.9.99 to avoid duplicate runs.
|
**Breaking Change**: VM autobackups now run in `pvcworkerd` instead of the CLI client directly, allowing them to be triggerd from any node (or externally). It is important to apply the timer unit changes from the `pvc-ansible` role after upgrading to 0.9.99 to avoid duplicate runs.
|
||||||
**Usage Note**: VM snapshots are displayed in the `pvc vm list` and `pvc vm info` outputs, not in a unique "list" endpoint.
|
**Usage Note**: VM snapshots are displayed in the `pvc vm list` and `pvc vm info` outputs, not in a unique "list" endpoint.
|
||||||
|
@ -27,7 +27,7 @@ from distutils.util import strtobool as dustrtobool
|
|||||||
import daemon_lib.config as cfg
|
import daemon_lib.config as cfg
|
||||||
|
|
||||||
# Daemon version
|
# Daemon version
|
||||||
version = "0.9.99"
|
version = "0.9.100"
|
||||||
|
|
||||||
# API version
|
# API version
|
||||||
API_VERSION = 1.0
|
API_VERSION = 1.0
|
||||||
|
@ -2028,7 +2028,7 @@ def cli_vm_snapshot_import(
|
|||||||
)
|
)
|
||||||
def cli_vm_backup():
|
def cli_vm_backup():
|
||||||
"""
|
"""
|
||||||
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in PVC 0.9.100.
|
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in a future version.
|
||||||
|
|
||||||
Manage backups of VMs in a PVC cluster.
|
Manage backups of VMs in a PVC cluster.
|
||||||
"""
|
"""
|
||||||
@ -2059,7 +2059,7 @@ def cli_vm_backup():
|
|||||||
)
|
)
|
||||||
def cli_vm_backup_create(domain, backup_path, incremental_parent, retain_snapshot):
|
def cli_vm_backup_create(domain, backup_path, incremental_parent, retain_snapshot):
|
||||||
"""
|
"""
|
||||||
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in PVC 0.9.100.
|
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in a future version.
|
||||||
|
|
||||||
Create a backup of virtual machine DOMAIN to BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
Create a backup of virtual machine DOMAIN to BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
||||||
|
|
||||||
@ -2107,7 +2107,7 @@ def cli_vm_backup_create(domain, backup_path, incremental_parent, retain_snapsho
|
|||||||
)
|
)
|
||||||
def cli_vm_backup_restore(domain, backup_datestring, backup_path, retain_snapshot):
|
def cli_vm_backup_restore(domain, backup_datestring, backup_path, retain_snapshot):
|
||||||
"""
|
"""
|
||||||
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in PVC 0.9.100.
|
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in a future version.
|
||||||
|
|
||||||
Restore the backup BACKUP_DATESTRING of virtual machine DOMAIN stored in BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
Restore the backup BACKUP_DATESTRING of virtual machine DOMAIN stored in BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
||||||
|
|
||||||
@ -2147,7 +2147,7 @@ def cli_vm_backup_restore(domain, backup_datestring, backup_path, retain_snapsho
|
|||||||
@click.argument("backup_path")
|
@click.argument("backup_path")
|
||||||
def cli_vm_backup_remove(domain, backup_datestring, backup_path):
|
def cli_vm_backup_remove(domain, backup_datestring, backup_path):
|
||||||
"""
|
"""
|
||||||
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in PVC 0.9.100.
|
DEPRECATED: Use 'pvc vm snapshot' commands instead. 'pvc vm backup' commands will be removed in a future version.
|
||||||
|
|
||||||
Remove the backup BACKUP_DATESTRING, including snapshots, of virtual machine DOMAIN stored in BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
Remove the backup BACKUP_DATESTRING, including snapshots, of virtual machine DOMAIN stored in BACKUP_PATH on the cluster primary coordinator. DOMAIN may be a UUID or name.
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from setuptools import setup
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="pvc",
|
name="pvc",
|
||||||
version="0.9.99",
|
version="0.9.100",
|
||||||
packages=["pvc.cli", "pvc.lib"],
|
packages=["pvc.cli", "pvc.lib"],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"Click",
|
"Click",
|
||||||
|
@ -26,6 +26,7 @@ import subprocess
|
|||||||
import signal
|
import signal
|
||||||
from json import loads
|
from json import loads
|
||||||
from re import match as re_match
|
from re import match as re_match
|
||||||
|
from re import search as re_search
|
||||||
from re import split as re_split
|
from re import split as re_split
|
||||||
from re import sub as re_sub
|
from re import sub as re_sub
|
||||||
from difflib import unified_diff
|
from difflib import unified_diff
|
||||||
@ -1073,7 +1074,7 @@ def sortInterfaceNames(interface_names):
|
|||||||
#
|
#
|
||||||
# Parse a "detect" device into a real block device name
|
# Parse a "detect" device into a real block device name
|
||||||
#
|
#
|
||||||
def get_detect_device(detect_string):
|
def get_detect_device_lsscsi(detect_string):
|
||||||
"""
|
"""
|
||||||
Parses a "detect:" string into a normalized block device path using lsscsi.
|
Parses a "detect:" string into a normalized block device path using lsscsi.
|
||||||
|
|
||||||
@ -1140,3 +1141,96 @@ def get_detect_device(detect_string):
|
|||||||
break
|
break
|
||||||
|
|
||||||
return blockdev
|
return blockdev
|
||||||
|
|
||||||
|
|
||||||
|
def get_detect_device_nvme(detect_string):
|
||||||
|
"""
|
||||||
|
Parses a "detect:" string into a normalized block device path using nvme.
|
||||||
|
|
||||||
|
A detect string is formatted "detect:<NAME>:<SIZE>:<ID>", where
|
||||||
|
NAME is some unique identifier in lsscsi, SIZE is a human-readable
|
||||||
|
size value to within +/- 3% of the real size of the device, and
|
||||||
|
ID is the Nth (0-indexed) matching entry of that NAME and SIZE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
unit_map = {
|
||||||
|
"kB": 1000,
|
||||||
|
"MB": 1000 * 1000,
|
||||||
|
"GB": 1000 * 1000 * 1000,
|
||||||
|
"TB": 1000 * 1000 * 1000 * 1000,
|
||||||
|
"PB": 1000 * 1000 * 1000 * 1000 * 1000,
|
||||||
|
"EB": 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, name, _size, idd = detect_string.split(":")
|
||||||
|
if _ != "detect":
|
||||||
|
return None
|
||||||
|
|
||||||
|
size_re = re_search(r"([\d.]+)([kKMGTP]B)", _size)
|
||||||
|
size_val = float(size_re.group(1))
|
||||||
|
size_unit = size_re.group(2)
|
||||||
|
size_bytes = int(size_val * unit_map[size_unit])
|
||||||
|
|
||||||
|
retcode, stdout, stderr = run_os_command("nvme list --output-format json")
|
||||||
|
if retcode:
|
||||||
|
print(f"Failed to run nvme: {stderr}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Parse the output with json
|
||||||
|
nvme_data = loads(stdout).get("Devices", list())
|
||||||
|
|
||||||
|
# Handle size determination (+/- 3%)
|
||||||
|
size = None
|
||||||
|
nvme_sizes = set()
|
||||||
|
for entry in nvme_data:
|
||||||
|
nvme_sizes.add(entry["PhysicalSize"])
|
||||||
|
for l_size in nvme_sizes:
|
||||||
|
plusthreepct = size_bytes * 1.03
|
||||||
|
minusthreepct = size_bytes * 0.97
|
||||||
|
|
||||||
|
if l_size > minusthreepct and l_size < plusthreepct:
|
||||||
|
size = l_size
|
||||||
|
break
|
||||||
|
if size is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
blockdev = None
|
||||||
|
matches = list()
|
||||||
|
for entry in nvme_data:
|
||||||
|
# Skip if name is not contained in the line (case-insensitive)
|
||||||
|
if name.lower() not in entry["ModelNumber"].lower():
|
||||||
|
continue
|
||||||
|
# Skip if the size does not match
|
||||||
|
if size != entry["PhysicalSize"]:
|
||||||
|
continue
|
||||||
|
# Get our blockdev and append to the list
|
||||||
|
matches.append(entry["DevicePath"])
|
||||||
|
|
||||||
|
blockdev = None
|
||||||
|
# Find the blockdev at index {idd}
|
||||||
|
for idx, _blockdev in enumerate(matches):
|
||||||
|
if int(idx) == int(idd):
|
||||||
|
blockdev = _blockdev
|
||||||
|
break
|
||||||
|
|
||||||
|
return blockdev
|
||||||
|
|
||||||
|
|
||||||
|
def get_detect_device(detect_string):
|
||||||
|
"""
|
||||||
|
Parses a "detect:" string into a normalized block device path.
|
||||||
|
|
||||||
|
First tries to parse using "lsscsi" (get_detect_device_lsscsi). If this returns an invalid
|
||||||
|
block device name, then try to parse using "nvme" (get_detect_device_nvme). This works around
|
||||||
|
issues with more recent devices (e.g. the Dell R6615 series) not properly reporting block
|
||||||
|
device paths for NVMe devices with "lsscsi".
|
||||||
|
"""
|
||||||
|
|
||||||
|
device = get_detect_device_lsscsi(detect_string)
|
||||||
|
if device is None or not re_match(r"^/dev", device):
|
||||||
|
device = get_detect_device_nvme(detect_string)
|
||||||
|
|
||||||
|
if device is not None and re_match(r"^/dev", device):
|
||||||
|
return device
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
7
debian/changelog
vendored
7
debian/changelog
vendored
@ -1,3 +1,10 @@
|
|||||||
|
pvc (0.9.100-0) unstable; urgency=high
|
||||||
|
|
||||||
|
* [API Daemon] Improves the handling of "detect:" disk strings on newer systems by leveraging the "nvme" command
|
||||||
|
* [Meta] Updates deprecation warnings and updates builder to only add this version for Debian 12 (Bookworm)
|
||||||
|
|
||||||
|
-- Joshua M. Boniface <joshua@boniface.me> Fri, 30 Aug 2024 10:58:53 -0400
|
||||||
|
|
||||||
pvc (0.9.99-0) unstable; urgency=high
|
pvc (0.9.99-0) unstable; urgency=high
|
||||||
|
|
||||||
**Deprecation Warning**: `pvc vm backup` commands are now deprecated and will be removed in **0.9.100**. Use `pvc vm snapshot` commands instead.
|
**Deprecation Warning**: `pvc vm backup` commands are now deprecated and will be removed in **0.9.100**. Use `pvc vm snapshot` commands instead.
|
||||||
|
@ -33,7 +33,7 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
|
|
||||||
# Daemon version
|
# Daemon version
|
||||||
version = "0.9.99"
|
version = "0.9.100"
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -49,7 +49,7 @@ import re
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
# Daemon version
|
# Daemon version
|
||||||
version = "0.9.99"
|
version = "0.9.100"
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -52,7 +52,7 @@ from daemon_lib.autobackup import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Daemon version
|
# Daemon version
|
||||||
version = "0.9.99"
|
version = "0.9.100"
|
||||||
|
|
||||||
|
|
||||||
config = cfg.get_configuration()
|
config = cfg.get_configuration()
|
||||||
|
Reference in New Issue
Block a user