Compare commits

...

17 Commits

Author SHA1 Message Date
6c407d54c3 Bump version to 0.9.70 2023-08-31 14:15:54 -04:00
9ba7aa5b08 [Bookworm] Remove obsolete package 2023-08-31 14:13:05 -04:00
cb413e5ce6 [Bookworm] Fix Ceph 16 OSD stat parsing 2023-08-31 00:45:03 -04:00
123499f75f [Bookworm] Specify YAML loader explicitly 2023-08-31 00:16:19 -04:00
83b8ce7b62 Bump version to 0.9.69 (nice) 2023-08-29 22:02:13 -04:00
5e43f9bd7c Ensure Patroni failures do not block takeover 2023-08-29 22:00:11 -04:00
ed087d83c2 Found cpuload to 2 decimal places 2023-08-29 21:41:44 -04:00
83d475bd15 Bump version to 0.9.68 2023-08-27 20:59:23 -04:00
3d5cdf2b23 Fix missing function parameter 2023-08-27 20:57:27 -04:00
705ec802a3 Bump version to 0.9.67 2023-08-27 14:47:20 -04:00
47d7b23763 Fix missing re import 2023-08-27 14:45:51 -04:00
0bae729a18 Better handle empty diffs 2023-08-27 14:44:21 -04:00
b968110e9f Add missing import for difflib unified_diff 2023-08-27 14:40:52 -04:00
4898ae5082 Fix missing import of colorama Fore 2023-08-27 14:34:47 -04:00
249e1568a1 Fix incorrect echo() calls 2023-08-27 14:33:42 -04:00
0b90f37518 Bump version to 0.9.66 2023-08-27 11:41:22 -04:00
33205273dc Fix missing YAML load 2023-08-27 11:41:10 -04:00
13 changed files with 180 additions and 76 deletions

View File

@ -1 +1 @@
0.9.65 0.9.70

View File

@ -1,5 +1,26 @@
## PVC Changelog ## PVC Changelog
###### [v0.9.70](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.70)
* [Node Daemon] Fixes several compatibility issues for Debian 12 "Bookworm"
###### [v0.9.69](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.69)
* [Node Daemon] Ensures that system load is always 2 decimal places on Bookworm
* [Node Daemon] Fixes bug blocking primary takeover at DNS Aggregator start if Patroni is down
###### [v0.9.68](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.68)
* [CLI] Fixes another bug with network info view
###### [v0.9.67](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.67)
* [CLI] Fixes several more bugs in the refactored CLI
###### [v0.9.66](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.66)
* [CLI] Fixes a missing YAML import in CLI
###### [v0.9.65](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.65) ###### [v0.9.65](https://github.com/parallelvirtualcluster/pvc/releases/tag/v0.9.65)
* [CLI] Fixes a bug in the node list filtering command * [CLI] Fixes a bug in the node list filtering command

View File

@ -19,8 +19,7 @@
# #
############################################################################### ###############################################################################
from flask_migrate import Migrate, MigrateCommand from flask_migrate import Migrate, MigrateCommand, Manager
from flask_script import Manager
from pvcapid.flaskapi import app, db from pvcapid.flaskapi import app, db
from pvcapid.models import * # noqa F401,F403 from pvcapid.models import * # noqa F401,F403

View File

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

View File

@ -19,6 +19,8 @@
# #
############################################################################### ###############################################################################
from colorama import Fore
from difflib import unified_diff
from functools import wraps from functools import wraps
from json import dump as jdump from json import dump as jdump
from json import dumps as jdumps from json import dumps as jdumps
@ -26,7 +28,9 @@ from json import loads as jloads
from os import environ, makedirs, path from os import environ, makedirs, path
from pkg_resources import get_distribution from pkg_resources import get_distribution
from lxml.etree import fromstring, tostring from lxml.etree import fromstring, tostring
from re import sub from re import sub, match
from yaml import load as yload
from yaml import SafeLoader as SafeYAMLLoader
from pvc.cli.helpers import * from pvc.cli.helpers import *
from pvc.cli.waiters import * from pvc.cli.waiters import *
@ -1194,7 +1198,7 @@ def cli_vm_modify(
text=current_vm_cfgfile, require_save=True, extension=".xml" text=current_vm_cfgfile, require_save=True, extension=".xml"
) )
if new_vm_cfgfile is None: if new_vm_cfgfile is None:
echo("Aborting with no modifications.") echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0) exit(0)
else: else:
new_vm_cfgfile = new_vm_cfgfile.strip() new_vm_cfgfile = new_vm_cfgfile.strip()
@ -1206,16 +1210,14 @@ def cli_vm_modify(
cfgfile.close() cfgfile.close()
echo( echo(
CLI_CONFIG,
'Replacing configuration of VM "{}" with file "{}".'.format( 'Replacing configuration of VM "{}" with file "{}".'.format(
dom_name, cfgfile.name dom_name, cfgfile.name
) ),
) )
# Show a diff and confirm
echo("Pending modifications:")
echo("")
diff = list( diff = list(
difflib.unified_diff( unified_diff(
current_vm_cfgfile.split("\n"), current_vm_cfgfile.split("\n"),
new_vm_cfgfile.split("\n"), new_vm_cfgfile.split("\n"),
fromfile="current", fromfile="current",
@ -1226,16 +1228,23 @@ def cli_vm_modify(
lineterm="", lineterm="",
) )
) )
if len(diff) < 1:
echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0)
# Show a diff and confirm
echo(CLI_CONFIG, "Pending modifications:")
echo(CLI_CONFIG, "")
for line in diff: for line in diff:
if re.match(r"^\+", line) is not None: if match(r"^\+", line) is not None:
echo(colorama.Fore.GREEN + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET)
elif re.match(r"^\-", line) is not None: elif match(r"^\-", line) is not None:
echo(colorama.Fore.RED + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.RED + line + Fore.RESET)
elif re.match(r"^\^", line) is not None: elif match(r"^\^", line) is not None:
echo(colorama.Fore.BLUE + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET)
else: else:
echo(line) echo(CLI_CONFIG, line)
echo("") echo(CLI_CONFIG, "")
# Verify our XML is sensible # Verify our XML is sensible
try: try:
@ -3592,7 +3601,7 @@ def cli_storage_volume_upload(pool, name, image_format, image_file):
""" """
if not os.path.exists(image_file): if not os.path.exists(image_file):
echo("ERROR: File '{}' does not exist!".format(image_file)) echo(CLI_CONFIG, "ERROR: File '{}' does not exist!".format(image_file))
exit(1) exit(1)
retcode, retmsg = pvc.lib.storage.ceph_volume_upload( retcode, retmsg = pvc.lib.storage.ceph_volume_upload(
@ -4430,7 +4439,8 @@ def cli_provisioner_template_storage_disk_add(
if source_volume and (size or filesystem or mountpoint): if source_volume and (size or filesystem or mountpoint):
echo( echo(
'The "--source-volume" option is not compatible with the "--size", "--filesystem", or "--mountpoint" options.' CLI_CONFIG,
'The "--source-volume" option is not compatible with the "--size", "--filesystem", or "--mountpoint" options.',
) )
exit(1) exit(1)
@ -4510,9 +4520,9 @@ def cli_provisioner_userdata_add(name, filename):
userdata = filename.read() userdata = filename.read()
filename.close() filename.close()
try: try:
yaml.load(userdata, Loader=yaml.SafeLoader) yload(userdata, Loader=SafeYAMLLoader)
except Exception as e: except Exception as e:
echo("Error: Userdata document is malformed") echo(CLI_CONFIG, "Error: Userdata document is malformed")
cleanup(False, e) cleanup(False, e)
params = dict() params = dict()
@ -4549,7 +4559,7 @@ def cli_provisioner_userdata_modify(name, filename, editor):
# Grab the current config # Grab the current config
retcode, retdata = pvc.lib.provisioner.userdata_info(CLI_CONFIG, name) retcode, retdata = pvc.lib.provisioner.userdata_info(CLI_CONFIG, name)
if not retcode: if not retcode:
echo(retdata) echo(CLI_CONFIG, retdata)
exit(1) exit(1)
current_userdata = retdata["userdata"].strip() current_userdata = retdata["userdata"].strip()
@ -4557,16 +4567,14 @@ def cli_provisioner_userdata_modify(name, filename, editor):
text=current_userdata, require_save=True, extension=".yaml" text=current_userdata, require_save=True, extension=".yaml"
) )
if new_userdata is None: if new_userdata is None:
echo("Aborting with no modifications.") echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0) exit(0)
else: else:
new_userdata = new_userdata.strip() new_userdata = new_userdata.strip()
# Show a diff and confirm # Show a diff and confirm
echo("Pending modifications:")
echo("")
diff = list( diff = list(
difflib.unified_diff( unified_diff(
current_userdata.split("\n"), current_userdata.split("\n"),
new_userdata.split("\n"), new_userdata.split("\n"),
fromfile="current", fromfile="current",
@ -4577,16 +4585,22 @@ def cli_provisioner_userdata_modify(name, filename, editor):
lineterm="", lineterm="",
) )
) )
if len(diff) < 1:
echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0)
echo(CLI_CONFIG, "Pending modifications:")
echo(CLI_CONFIG, "")
for line in diff: for line in diff:
if re.match(r"^\+", line) is not None: if match(r"^\+", line) is not None:
echo(colorama.Fore.GREEN + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET)
elif re.match(r"^\-", line) is not None: elif match(r"^\-", line) is not None:
echo(colorama.Fore.RED + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.RED + line + Fore.RESET)
elif re.match(r"^\^", line) is not None: elif match(r"^\^", line) is not None:
echo(colorama.Fore.BLUE + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET)
else: else:
echo(line) echo(CLI_CONFIG, line)
echo("") echo(CLI_CONFIG, "")
click.confirm("Write modifications to cluster?", abort=True) click.confirm("Write modifications to cluster?", abort=True)
@ -4599,9 +4613,9 @@ def cli_provisioner_userdata_modify(name, filename, editor):
filename.close() filename.close()
try: try:
yaml.load(userdata, Loader=yaml.SafeLoader) yload(userdata, Loader=SafeYAMLLoader)
except Exception as e: except Exception as e:
echo("Error: Userdata document is malformed") echo(CLI_CONFIG, "Error: Userdata document is malformed")
cleanup(False, e) cleanup(False, e)
params = dict() params = dict()
@ -4739,22 +4753,20 @@ def cli_provisioner_script_modify(name, filename, editor):
# Grab the current config # Grab the current config
retcode, retdata = pvc.lib.provisioner.script_info(CLI_CONFIG, name) retcode, retdata = pvc.lib.provisioner.script_info(CLI_CONFIG, name)
if not retcode: if not retcode:
echo(retdata) echo(CLI_CONFIG, retdata)
exit(1) exit(1)
current_script = retdata["script"].strip() current_script = retdata["script"].strip()
new_script = click.edit(text=current_script, require_save=True, extension=".py") new_script = click.edit(text=current_script, require_save=True, extension=".py")
if new_script is None: if new_script is None:
echo("Aborting with no modifications.") echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0) exit(0)
else: else:
new_script = new_script.strip() new_script = new_script.strip()
# Show a diff and confirm # Show a diff and confirm
echo("Pending modifications:")
echo("")
diff = list( diff = list(
difflib.unified_diff( unified_diff(
current_script.split("\n"), current_script.split("\n"),
new_script.split("\n"), new_script.split("\n"),
fromfile="current", fromfile="current",
@ -4765,16 +4777,22 @@ def cli_provisioner_script_modify(name, filename, editor):
lineterm="", lineterm="",
) )
) )
if len(diff) < 1:
echo(CLI_CONFIG, "Aborting with no modifications.")
exit(0)
echo(CLI_CONFIG, "Pending modifications:")
echo(CLI_CONFIG, "")
for line in diff: for line in diff:
if re.match(r"^\+", line) is not None: if match(r"^\+", line) is not None:
echo(colorama.Fore.GREEN + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET)
elif re.match(r"^\-", line) is not None: elif match(r"^\-", line) is not None:
echo(colorama.Fore.RED + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.RED + line + Fore.RESET)
elif re.match(r"^\^", line) is not None: elif match(r"^\^", line) is not None:
echo(colorama.Fore.BLUE + line + colorama.Fore.RESET) echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET)
else: else:
echo(line) echo(CLI_CONFIG, line)
echo("") echo(CLI_CONFIG, "")
click.confirm("Write modifications to cluster?", abort=True) click.confirm("Write modifications to cluster?", abort=True)
@ -4895,7 +4913,7 @@ def cli_provisioner_ova_upload(name, filename, pool):
""" """
if not os.path.exists(filename): if not os.path.exists(filename):
echo("ERROR: File '{}' does not exist!".format(filename)) echo(CLI_CONFIG, "ERROR: File '{}' does not exist!".format(filename))
exit(1) exit(1)
params = dict() params = dict()

View File

@ -700,7 +700,7 @@ def format_info(config, network_information, long_output):
ainformation.append("") ainformation.append("")
if retcode: if retcode:
dhcp4_reservations_string = format_list_dhcp( dhcp4_reservations_string = format_list_dhcp(
dhcp4_reservations_list config, dhcp4_reservations_list
) )
for line in dhcp4_reservations_string.split("\n"): for line in dhcp4_reservations_string.split("\n"):
ainformation.append(line) ainformation.append(line)

View File

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

31
debian/changelog vendored
View File

@ -1,3 +1,34 @@
pvc (0.9.70-0) unstable; urgency=high
* [Node Daemon] Fixes several compatibility issues for Debian 12 "Bookworm"
-- Joshua M. Boniface <joshua@boniface.me> Thu, 31 Aug 2023 14:15:54 -0400
pvc (0.9.69-0) unstable; urgency=high
* [Node Daemon] Ensures that system load is always 2 decimal places on Bookworm
* [Node Daemon] Fixes bug blocking primary takeover at DNS Aggregator start if Patroni is down
-- Joshua M. Boniface <joshua@boniface.me> Tue, 29 Aug 2023 22:01:22 -0400
pvc (0.9.68-0) unstable; urgency=high
* [CLI] Fixes another bug with network info view
-- Joshua M. Boniface <joshua@boniface.me> Sun, 27 Aug 2023 20:59:23 -0400
pvc (0.9.67-0) unstable; urgency=high
* [CLI] Fixes several more bugs in the refactored CLI
-- Joshua M. Boniface <joshua@boniface.me> Sun, 27 Aug 2023 14:47:20 -0400
pvc (0.9.66-0) unstable; urgency=high
* [CLI] Fixes a missing YAML import in CLI
-- Joshua M. Boniface <joshua@boniface.me> Sun, 27 Aug 2023 11:36:05 -0400
pvc (0.9.65-0) unstable; urgency=high pvc (0.9.65-0) unstable; urgency=high
* [CLI] Fixes a bug in the node list filtering command * [CLI] Fixes a bug in the node list filtering command

2
debian/control vendored
View File

@ -16,7 +16,7 @@ Description: Parallel Virtual Cluster node daemon (Python 3)
Package: pvc-daemon-api Package: pvc-daemon-api
Architecture: all Architecture: all
Depends: systemd, pvc-daemon-common, python3-yaml, python3-flask, python3-flask-restful, python3-celery, python-celery-common, python3-distutils, redis, python3-redis, python3-lxml, python3-flask-migrate, python3-flask-script, fio Depends: systemd, pvc-daemon-common, python3-yaml, python3-flask, python3-flask-restful, python3-celery, python-celery-common, python3-distutils, redis, python3-redis, python3-lxml, python3-flask-migrate, fio
Description: Parallel Virtual Cluster API daemon (Python 3) Description: Parallel Virtual Cluster API daemon (Python 3)
A KVM/Zookeeper/Ceph-based VM and private cloud manager A KVM/Zookeeper/Ceph-based VM and private cloud manager
. .

View File

@ -49,7 +49,7 @@ import re
import json import json
# Daemon version # Daemon version
version = "0.9.65" version = "0.9.70"
########################################################## ##########################################################

View File

@ -77,7 +77,7 @@ def connect_zookeeper():
with open(pvcnoded_config_file, "r") as cfgfile: with open(pvcnoded_config_file, "r") as cfgfile:
try: try:
o_config = yaml.load(cfgfile) o_config = yaml.load(cfgfile, yaml.SafeLoader)
except Exception as e: except Exception as e:
print( print(
"ERROR: Failed to parse configuration file: {}".format(e), "ERROR: Failed to parse configuration file: {}".format(e),

View File

@ -620,9 +620,12 @@ class NodeInstance(object):
for network in self.d_network: for network in self.d_network:
self.d_network[network].startDHCPServer() self.d_network[network].startDHCPServer()
# 9. Start DNS aggregator; just continue if we fail # 9. Start DNS aggregator; just continue if we fail
if not patroni_failed: try:
self.dns_aggregator.start_aggregator() if not patroni_failed:
else: self.dns_aggregator.start_aggregator()
else:
raise
except Exception:
self.logger.out( self.logger.out(
"Not starting DNS aggregator due to Patroni failures", state="e" "Not starting DNS aggregator due to Patroni failures", state="e"
) )

View File

@ -338,8 +338,21 @@ def collect_ceph_stats(logger, config, zkhandler, this_node, queue):
line = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", line) line = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", line)
# Split it for parsing # Split it for parsing
line = line.split() line = line.split()
if len(line) > 1 and line[1].isdigit():
# This is an OSD line so parse it # Ceph 14 format:
# ['|', '0', '|', 'hv1.p.u.bonilan.net', '|', '318G', '|', '463G', '|', '213', '|', '1430k', '|', '22', '|', '124k', '|', 'exists,up', '|']
# Ceph 16 format:
# ['0', 'hv1.t.u.bonilan.net', '2489M', '236G', '0', '0', '0', '0', 'exists,up']
# Bypass obviously invalid lines
if len(line) < 1:
continue
elif line[0] == "+":
continue
# If line begins with | and second entry is a digit (i.e. OSD ID)
if line[0] == "|" and line[1].isdigit():
# Parse the line in Ceph 14 format
osd_id = line[1] osd_id = line[1]
node = line[3].split(".")[0] node = line[3].split(".")[0]
used = line[5] used = line[5]
@ -349,20 +362,39 @@ def collect_ceph_stats(logger, config, zkhandler, this_node, queue):
rd_ops = line[13] rd_ops = line[13]
rd_data = line[15] rd_data = line[15]
state = line[17] state = line[17]
osd_status.update( # If first entry is a digit (i.e. OSD ID)
{ elif line[0].isdigit():
str(osd_id): { # Parse the line in Ceph 16 format
"node": node, osd_id = line[0]
"used": used, node = line[1].split(".")[0]
"avail": avail, used = line[2]
"wr_ops": wr_ops, avail = line[3]
"wr_data": wr_data, wr_ops = line[4]
"rd_ops": rd_ops, wr_data = line[5]
"rd_data": rd_data, rd_ops = line[6]
"state": state, rd_data = line[7]
} state = line[8]
# Otherwise, it's the header line and is ignored
else:
continue
# I don't know why 2018 me used this construct instead of a normal
# dictionary update, but it works so not changing it.
# ref: bfbe9188ce830381f3f2fa1da11f1973f08eca8c
osd_status.update(
{
str(osd_id): {
"node": node,
"used": used,
"avail": avail,
"wr_ops": wr_ops,
"wr_data": wr_data,
"rd_ops": rd_ops,
"rd_data": rd_data,
"state": state,
} }
) }
)
# Merge them together into a single meaningful dict # Merge them together into a single meaningful dict
if debug: if debug:
@ -753,7 +785,7 @@ def node_keepalive(logger, config, zkhandler, this_node, monitoring_instance):
this_node.memtotal = int(psutil.virtual_memory().total / 1024 / 1024) this_node.memtotal = int(psutil.virtual_memory().total / 1024 / 1024)
this_node.memused = int(psutil.virtual_memory().used / 1024 / 1024) this_node.memused = int(psutil.virtual_memory().used / 1024 / 1024)
this_node.memfree = int(psutil.virtual_memory().free / 1024 / 1024) this_node.memfree = int(psutil.virtual_memory().free / 1024 / 1024)
this_node.cpuload = os.getloadavg()[0] this_node.cpuload = round(os.getloadavg()[0], 2)
# Join against running threads # Join against running threads
if config["enable_hypervisor"]: if config["enable_hypervisor"]: