From 52aa351c6063a47f30aa70654f7e59b0a838a84a Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Thu, 13 Mar 2025 00:26:47 -0400 Subject: [PATCH] Move to lazy imports and custom API client --- client-cli/pvc/cli/cli.py | 471 +++++++++++++++-------------- client-cli/pvc/lib/common.py | 281 +++++++++++++---- client-cli/pvc/lib/lazy_imports.py | 17 ++ 3 files changed, 487 insertions(+), 282 deletions(-) create mode 100644 client-cli/pvc/lib/lazy_imports.py diff --git a/client-cli/pvc/cli/cli.py b/client-cli/pvc/cli/cli.py index 181171e2..85c0bbca 100644 --- a/client-cli/pvc/cli/cli.py +++ b/client-cli/pvc/cli/cli.py @@ -19,32 +19,43 @@ # ############################################################################### -from colorama import Fore -from difflib import unified_diff -from functools import wraps -from json import dump as jdump -from json import dumps as jdumps -from json import loads as jloads +# Import only essential modules at the top level from os import environ, makedirs, path -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.waiters import * -from pvc.cli.parsers import * -from pvc.cli.formatters import * - -import pvc.lib.cluster -import pvc.lib.faults -import pvc.lib.node -import pvc.lib.vm -import pvc.lib.network -import pvc.lib.storage -import pvc.lib.provisioner - +from json import dumps as jdumps import click +# Import helpers that are needed for CLI definition +from pvc.cli.helpers import MAX_CONTENT_WIDTH, connection_req, confirm_opt, restart_opt, format_opt, echo, finish + +# Create lazy imports for modules that are only needed during command execution +from pvc.lib.lazy_imports import LazyModule + +# Lazy load heavy modules +colorama = LazyModule('colorama') +difflib = LazyModule('difflib') +functools = LazyModule('functools') +json_module = LazyModule('json') +yaml = LazyModule('yaml') +re_module = LazyModule('re') + +# Lazy load PVC modules that aren't needed immediately +pvc_lib_cluster = LazyModule('pvc.lib.cluster') +pvc_lib_faults = LazyModule('pvc.lib.faults') +pvc_lib_node = LazyModule('pvc.lib.node') +pvc_lib_vm = LazyModule('pvc.lib.vm') +pvc_lib_network = LazyModule('pvc.lib.network') +pvc_lib_storage = LazyModule('pvc.lib.storage') +pvc_lib_provisioner = LazyModule('pvc.lib.provisioner') + +# Lazy load CLI modules +pvc_cli_waiters = LazyModule('pvc.cli.waiters') +pvc_cli_parsers = LazyModule('pvc.cli.parsers') +pvc_cli_formatters = LazyModule('pvc.cli.formatters') + +# Define aliases for commonly used functions to avoid attribute lookups +jdump = lambda obj, fp: json_module.dump(obj, fp) +jloads = lambda s: json_module.loads(s) +yload = lambda stream: yaml.load(stream, yaml.SafeLoader) ############################################################################### # Context and completion handler, globals @@ -115,7 +126,7 @@ def connection_req(function): Wraps a Click command which requires a connection to be set and validates that it is present """ - @wraps(function) + @functools.wraps(function) def validate_connection(*args, **kwargs): if CLI_CONFIG.get("badcfg", None) and CLI_CONFIG.get("connection"): echo( @@ -166,7 +177,7 @@ def restart_opt(function): show_default=False, help="Immediately restart VM to apply changes or do not restart VM, or prompt if unspecified.", ) - @wraps(function) + @functools.wraps(function) def confirm_action(*args, **kwargs): restart_state = kwargs.get("restart_flag", None) live_state = kwargs.get("live_flag", False) @@ -211,7 +222,7 @@ def confirm_opt(message): default=False, help="Pre-confirm any unsafe operations.", ) - @wraps(function) + @functools.wraps(function) def confirm_action(*args, **kwargs): confirm_action = True if "confirm_flag" in kwargs: @@ -239,7 +250,7 @@ def confirm_opt(message): # Try to interpolate any variables in the message from the kwargs # This is slightly messy but allows for nicer specification of the variables # in the calling {message} string - _message = sub(r"{([^{}]*)}", r"\"{kwargs['\1']}\"", message) + _message = re_module.sub(r"{([^{}]*)}", r"\"{kwargs['\1']}\"", message) _message = eval(f"""f'''{_message}'''""") click.confirm(_message, prompt_suffix="? ", abort=True) @@ -281,7 +292,7 @@ def format_opt(formats, default_format="pretty"): type=click.Choice(formats.keys()), help="Output information in this format.", ) - @wraps(function) + @functools.wraps(function) def format_action(*args, **kwargs): kwargs["format_function"] = formats[kwargs["output_format"]] @@ -381,7 +392,7 @@ def cli_cluster_init( echo(CLI_CONFIG, "Some music while we're Layin' Pipe? https://youtu.be/sw8S_Kv89IU") - retcode, retmsg = pvc.lib.cluster.initialize(CLI_CONFIG, overwrite_flag) + retcode, retmsg = pvc_lib_cluster.initialize(CLI_CONFIG, overwrite_flag) finish(retcode, retmsg) @@ -408,7 +419,7 @@ def cli_cluster_backup( Create a JSON-format backup of the cluster Zookeeper state database. """ - retcode, retdata = pvc.lib.cluster.backup(CLI_CONFIG) + retcode, retdata = pvc_lib_cluster.backup(CLI_CONFIG) json_data = jloads(retdata) if retcode and filename is not None: jdump(json_data, filename) @@ -481,7 +492,7 @@ def cli_cluster_status( "json-pretty": Output in formatted JSON. """ - retcode, retdata = pvc.lib.cluster.get_info(CLI_CONFIG) + retcode, retdata = pvc_lib_cluster.get_info(CLI_CONFIG) finish(retcode, retdata, format_function) @@ -523,7 +534,7 @@ def cli_cluster_fault_list(limit, format_function): List all faults in the PVC cluster, optionally limited to fault ID LIMIT. """ - retcode, retdata = pvc.lib.faults.get_list( + retcode, retdata = pvc_lib_faults.get_list( CLI_CONFIG, limit=limit, ) @@ -545,7 +556,7 @@ def cli_cluster_fault_acknowledge(fault_id): """ faults = list(fault_id) - retcode, retdata = pvc.lib.faults.acknowledge(CLI_CONFIG, faults) + retcode, retdata = pvc_lib_faults.acknowledge(CLI_CONFIG, faults) finish(retcode, retdata) @@ -563,7 +574,7 @@ def cli_cluster_fault_acknowledge_all(): Acknowledge all cluster faults. """ - retcode, retdata = pvc.lib.faults.acknowledge_all(CLI_CONFIG) + retcode, retdata = pvc_lib_faults.acknowledge_all(CLI_CONFIG) finish(retcode, retdata) @@ -582,7 +593,7 @@ def cli_cluster_fault_delete(fault_id): """ faults = list(fault_id) - retcode, retdata = pvc.lib.faults.delete(CLI_CONFIG, faults) + retcode, retdata = pvc_lib_faults.delete(CLI_CONFIG, faults) finish(retcode, retdata) @@ -600,7 +611,7 @@ def cli_cluster_fault_delete_all(): Delete all cluster faults. """ - retcode, retdata = pvc.lib.faults.delete_all(CLI_CONFIG) + retcode, retdata = pvc_lib_faults.delete_all(CLI_CONFIG) finish(retcode, retdata) @@ -632,7 +643,7 @@ def cli_cluster_maintenance_on(): Enable maintenance mode on a PVC cluster. """ - retcode, retdata = pvc.lib.cluster.maintenance_mode(CLI_CONFIG, "true") + retcode, retdata = pvc_lib_cluster.maintenance_mode(CLI_CONFIG, "true") finish(retcode, retdata) @@ -649,7 +660,7 @@ def cli_cluster_maintenance_off(): Disable maintenance mode on a PVC cluster. """ - retcode, retdata = pvc.lib.cluster.maintenance_mode(CLI_CONFIG, "false") + retcode, retdata = pvc_lib_cluster.maintenance_mode(CLI_CONFIG, "false") finish(retcode, retdata) @@ -687,12 +698,12 @@ def cli_cluster_task(task_id, wait_flag, format_function): if wait_flag: # First validate that this is actually a valid task that is running echo(CLI_CONFIG, "Querying cluster for tasks...", newline=False) - retcode, retdata = pvc.lib.common.task_status(CLI_CONFIG, None) + retcode, retdata = pvc_lib_cluster.task_status(CLI_CONFIG, None) echo(CLI_CONFIG, " done.") echo(CLI_CONFIG, "") if task_id in [i["id"] for i in retdata]: task = [i for i in retdata if i["id"] == task_id][0] - retmsg = wait_for_celery_task( + retmsg = pvc_cli_waiters.wait_for_celery_task( CLI_CONFIG, {"task_id": task["id"], "task_name": task["name"]}, start_late=True, @@ -702,7 +713,7 @@ def cli_cluster_task(task_id, wait_flag, format_function): finish(retcode, retmsg) else: echo(CLI_CONFIG, "Querying cluster for tasks...", newline=False) - retcode, retdata = pvc.lib.common.task_status(CLI_CONFIG, task_id) + retcode, retdata = pvc_lib_cluster.task_status(CLI_CONFIG, task_id) echo(CLI_CONFIG, " done.") echo(CLI_CONFIG, "") finish(retcode, retdata, format_function) @@ -742,7 +753,7 @@ def cli_node_is_primary( is primary, and 1 if it is not. """ - _, primary_node = pvc.lib.cluster.get_primary_node(CLI_CONFIG) + _, primary_node = pvc_lib_cluster.get_primary_node(CLI_CONFIG) if primary_node == node: exit(0) @@ -776,7 +787,7 @@ def cli_node_primary( Set NODE in primary coordinator state, making it the primary coordinator for the cluster. """ - retcode, retdata = pvc.lib.node.node_coordinator_state(CLI_CONFIG, node, "primary") + retcode, retdata = pvc_lib_node.node_coordinator_state(CLI_CONFIG, node, "primary") if not retcode or "already" in retdata: finish(retcode, retdata) @@ -814,7 +825,7 @@ def cli_node_secondary( Set NODE in secondary coordinator state, making another active node the primary node for the cluster. """ - retcode, retdata = pvc.lib.node.node_coordinator_state( + retcode, retdata = pvc_lib_node.node_coordinator_state( CLI_CONFIG, node, "secondary" ) if not retcode or "already" in retdata: @@ -854,7 +865,7 @@ def cli_node_flush( Take NODE out of service, migrating all VMs on it to other nodes. """ - retcode, retdata = pvc.lib.node.node_domain_state(CLI_CONFIG, node, "flush") + retcode, retdata = pvc_lib_node.node_domain_state(CLI_CONFIG, node, "flush") if not retcode or "already" in retdata: finish(retcode, retdata) @@ -892,7 +903,7 @@ def cli_node_ready( Restore NODE to service, returning all previous VMs to it from other nodes. """ - retcode, retdata = pvc.lib.node.node_domain_state(CLI_CONFIG, node, "ready") + retcode, retdata = pvc_lib_node.node_domain_state(CLI_CONFIG, node, "ready") if not retcode or "already" in retdata: finish(retcode, retdata) @@ -957,10 +968,10 @@ def cli_node_log( if follow_flag: # This command blocks following the logs until cancelled - retcode, retmsg = pvc.lib.node.follow_node_log(CLI_CONFIG, node, lines) + retcode, retmsg = pvc_lib_node.follow_node_log(CLI_CONFIG, node, lines) retmsg = "" else: - retcode, retmsg = pvc.lib.node.view_node_log(CLI_CONFIG, node, lines) + retcode, retmsg = pvc_lib_node.view_node_log(CLI_CONFIG, node, lines) click.echo_via_pager(retmsg) retmsg = "" @@ -999,7 +1010,7 @@ def cli_node_info( "json-pretty": Output in formatted JSON. """ - retcode, retdata = pvc.lib.node.node_info(CLI_CONFIG, node) + retcode, retdata = pvc_lib_node.node_info(CLI_CONFIG, node) finish(retcode, retdata, format_function) @@ -1059,7 +1070,7 @@ def cli_node_list( "json-pretty": Output in formatted JSON. """ - retcode, retdata = pvc.lib.node.node_list( + retcode, retdata = pvc_lib_node.node_list( CLI_CONFIG, limit, daemon_state_filter, @@ -1198,7 +1209,7 @@ def cli_vm_define( except Exception: finish(False, "Error: XML is malformed or invalid") - retcode, retmsg = pvc.lib.vm.vm_define( + retcode, retmsg = pvc_lib_vm.vm_define( CLI_CONFIG, new_cfg, target_node, @@ -1293,7 +1304,7 @@ def cli_vm_meta( ): finish(False, "At least one metadata option must be specified to update.") - retcode, retmsg = pvc.lib.vm.vm_metadata( + retcode, retmsg = pvc_lib_vm.vm_metadata( CLI_CONFIG, domain, node_limit, @@ -1370,7 +1381,7 @@ def cli_vm_modify( 'Either an XML config file or the "--editor" option must be specified.', ) - retcode, vm_information = pvc.lib.vm.vm_info(CLI_CONFIG, domain) + retcode, vm_information = pvc_lib_vm.vm_info(CLI_CONFIG, domain) if not retcode or not vm_information.get("name", None): finish(False, 'ERROR: Could not find VM "{}"!'.format(domain)) @@ -1408,7 +1419,7 @@ def cli_vm_modify( ) diff = list( - unified_diff( + difflib.unified_diff( current_vm_cfgfile.split("\n"), new_vm_cfgfile.split("\n"), fromfile="current", @@ -1427,12 +1438,12 @@ def cli_vm_modify( echo(CLI_CONFIG, "Pending modifications:") echo(CLI_CONFIG, "") for line in diff: - if match(r"^\+", line) is not None: - echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET) - elif match(r"^\-", line) is not None: - echo(CLI_CONFIG, Fore.RED + line + Fore.RESET) - elif match(r"^\^", line) is not None: - echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET) + if re_module.match(r"^\+", line) is not None: + echo(CLI_CONFIG, colorama.Fore.GREEN + line + colorama.Fore.RESET) + elif re_module.match(r"^\-", line) is not None: + echo(CLI_CONFIG, colorama.Fore.RED + line + colorama.Fore.RESET) + elif re_module.match(r"^\^", line) is not None: + echo(CLI_CONFIG, colorama.Fore.BLUE + line + colorama.Fore.RESET) else: echo(CLI_CONFIG, line) echo(CLI_CONFIG, "") @@ -1462,7 +1473,7 @@ def cli_vm_modify( except Exception: restart = False - retcode, retmsg = pvc.lib.vm.vm_modify(CLI_CONFIG, domain, new_cfg, restart) + retcode, retmsg = pvc_lib_vm.vm_modify(CLI_CONFIG, domain, new_cfg, restart) if retcode and not restart: retmsg = retmsg + " Changes will be applied on next VM start/restart." finish(retcode, retmsg) @@ -1481,7 +1492,7 @@ def cli_vm_rename(domain, new_name): Rename virtual machine DOMAIN, and all its connected disk volumes, to NEW_NAME. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_rename(CLI_CONFIG, domain, new_name) + retcode, retmsg = pvc_lib_vm.vm_rename(CLI_CONFIG, domain, new_name) finish(retcode, retmsg) @@ -1497,7 +1508,7 @@ def cli_vm_undefine(domain): Stop virtual machine DOMAIN and remove it database, preserving disks. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_remove(CLI_CONFIG, domain, delete_disks=False) + retcode, retmsg = pvc_lib_vm.vm_remove(CLI_CONFIG, domain, delete_disks=False) finish(retcode, retmsg) @@ -1513,7 +1524,7 @@ def cli_vm_remove(domain): Stop virtual machine DOMAIN and remove it, along with all disks,. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_remove(CLI_CONFIG, domain, delete_disks=True) + retcode, retmsg = pvc_lib_vm.vm_remove(CLI_CONFIG, domain, delete_disks=True) finish(retcode, retmsg) @@ -1537,7 +1548,7 @@ def cli_vm_start(domain, force_flag): If the VM is a snapshot mirror, "--force" allows a manual state change to the mirror. """ - retcode, retmsg = pvc.lib.vm.vm_state(CLI_CONFIG, domain, "start", force=force_flag) + retcode, retmsg = pvc_lib_vm.vm_state(CLI_CONFIG, domain, "start", force=force_flag) finish(retcode, retmsg) @@ -1561,7 +1572,7 @@ def cli_vm_restart(domain, wait): Restart running virtual machine DOMAIN. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_state(CLI_CONFIG, domain, "restart", wait=wait) + retcode, retmsg = pvc_lib_vm.vm_state(CLI_CONFIG, domain, "restart", wait=wait) finish(retcode, retmsg) @@ -1587,7 +1598,7 @@ def cli_vm_shutdown(domain, wait): Gracefully shut down virtual machine DOMAIN. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_state(CLI_CONFIG, domain, "shutdown", wait=wait) + retcode, retmsg = pvc_lib_vm.vm_state(CLI_CONFIG, domain, "shutdown", wait=wait) finish(retcode, retmsg) @@ -1612,7 +1623,7 @@ def cli_vm_stop(domain, force_flag): If the VM is a snapshot mirror, "--force" allows a manual state change to the mirror. """ - retcode, retmsg = pvc.lib.vm.vm_state(CLI_CONFIG, domain, "stop", force=force_flag) + retcode, retmsg = pvc_lib_vm.vm_state(CLI_CONFIG, domain, "stop", force=force_flag) finish(retcode, retmsg) @@ -1637,7 +1648,7 @@ def cli_vm_disable(domain, force_flag): If "--force" is specified, and the VM is running, it will be forcibly stopped instead of waiting for a graceful ACPI shutdown. If the VM is a snapshot mirror, "--force" allows a manual state change to the mirror. """ - retcode, retmsg = pvc.lib.vm.vm_state( + retcode, retmsg = pvc_lib_vm.vm_state( CLI_CONFIG, domain, "disable", force=force_flag ) finish(retcode, retmsg) @@ -1678,7 +1689,7 @@ def cli_vm_move(domain, target_node, wait, force_live): Permanently move virtual machine DOMAIN, via live migration if running and possible, to another node. DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_node( + retcode, retmsg = pvc_lib_vm.vm_node( CLI_CONFIG, domain, target_node, @@ -1733,7 +1744,7 @@ def cli_vm_migrate(domain, target_node, force_migrate, wait, force_live): Temporarily migrate running virtual machine DOMAIN, via live migration if possible, to another node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node. """ - retcode, retmsg = pvc.lib.vm.vm_node( + retcode, retmsg = pvc_lib_vm.vm_node( CLI_CONFIG, domain, target_node, @@ -1774,7 +1785,7 @@ def cli_vm_unmigrate(domain, wait, force_live): Restore previously migrated virtual machine DOMAIN, via live migration if possible, to its original node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node. """ - retcode, retmsg = pvc.lib.vm.vm_node( + retcode, retmsg = pvc_lib_vm.vm_node( CLI_CONFIG, domain, None, @@ -1809,10 +1820,10 @@ def cli_vm_flush_locks(domain, wait_flag): (†) NOTE: This is a task-based command. The "--wait" flag (default) will block and show progress. Specifying the "--no-wait" flag will return immediately with a job ID instead, which can be queried externally later. """ - retcode, retmsg = pvc.lib.vm.vm_locks(CLI_CONFIG, domain, wait_flag=wait_flag) + retcode, retmsg = pvc_lib_vm.vm_locks(CLI_CONFIG, domain, wait_flag=wait_flag) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -1856,12 +1867,12 @@ def cli_vm_snapshot_create(domain, snapshot_name, wait_flag): VM at the moment of the snapshot. """ - retcode, retmsg = pvc.lib.vm.vm_create_snapshot( + retcode, retmsg = pvc_lib_vm.vm_create_snapshot( CLI_CONFIG, domain, snapshot_name=snapshot_name, wait_flag=wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -1887,12 +1898,12 @@ def cli_vm_snapshot_remove(domain, snapshot_name, wait_flag): DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_remove_snapshot( + retcode, retmsg = pvc_lib_vm.vm_remove_snapshot( CLI_CONFIG, domain, snapshot_name, wait_flag=wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -1922,12 +1933,12 @@ def cli_vm_snapshot_rollback(domain, snapshot_name, wait_flag): DOMAIN may be a UUID or name. """ - retcode, retmsg = pvc.lib.vm.vm_rollback_snapshot( + retcode, retmsg = pvc_lib_vm.vm_rollback_snapshot( CLI_CONFIG, domain, snapshot_name, wait_flag=wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -1972,7 +1983,7 @@ def cli_vm_snapshot_export( Full export volume images are sparse-allocated, however it is recommended for safety to consider their maximum allocated size when allocated space for the EXPORT_PATH. Incremental volume images are generally small but are dependent entirely on the rate of data change in each volume. """ - retcode, retmsg = pvc.lib.vm.vm_export_snapshot( + retcode, retmsg = pvc_lib_vm.vm_export_snapshot( CLI_CONFIG, domain, snapshot_name, @@ -1982,7 +1993,7 @@ def cli_vm_snapshot_export( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -2028,7 +2039,7 @@ def cli_vm_snapshot_import( (!) WARNING: The "-R"/"--remove-snapshot" option will invalidate any existing incremental snapshots based on the same incremental parent for the imported VM. """ - retcode, retmsg = pvc.lib.vm.vm_import_snapshot( + retcode, retmsg = pvc_lib_vm.vm_import_snapshot( CLI_CONFIG, domain, snapshot_name, @@ -2038,7 +2049,7 @@ def cli_vm_snapshot_import( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -2107,7 +2118,7 @@ def cli_vm_snapshot_send( (!) WARNING: This functionality has no automatic backout on the remote side. While a properly configured cluster should not fail any step in the process, a situation like an intermittent network connection might cause a failure which would have to be manually corrected on that side, usually by removing the mirrored VM and retrying, or rolling back to a previous snapshot and retrying. Future versions may enhance automatic recovery, but for now this would be up to the administrator. """ - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) if destination in connections_config.keys(): destination_cluster_config = connections_config[destination] destination_api_uri = "{}://{}:{}{}".format( @@ -2125,7 +2136,7 @@ def cli_vm_snapshot_send( destination_api_uri = destination destination_api_key = destination_api_key - retcode, retmsg = pvc.lib.vm.vm_send_snapshot( + retcode, retmsg = pvc_lib_vm.vm_send_snapshot( CLI_CONFIG, domain, snapshot_name, @@ -2138,7 +2149,7 @@ def cli_vm_snapshot_send( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -2214,7 +2225,7 @@ def cli_vm_mirror_create( (!) WARNING: This functionality has no automatic backout on the remote side. While a properly configured cluster should not fail any step in the process, a situation like an intermittent network connection might cause a failure which would have to be manually corrected on that side, usually by removing the mirrored VM and retrying, or rolling back to a previous snapshot and retrying. Future versions may enhance automatic recovery, but for now this would be up to the administrator. """ - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) if destination in connections_config.keys(): destination_cluster_config = connections_config[destination] destination_api_uri = "{}://{}:{}{}".format( @@ -2232,7 +2243,7 @@ def cli_vm_mirror_create( destination_api_uri = destination destination_api_key = destination_api_key - retcode, retmsg = pvc.lib.vm.vm_create_mirror( + retcode, retmsg = pvc_lib_vm.vm_create_mirror( CLI_CONFIG, domain, destination_api_uri, @@ -2243,7 +2254,7 @@ def cli_vm_mirror_create( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -2316,7 +2327,7 @@ def cli_vm_mirror_promote( (!) WARNING: This functionality has no automatic backout on the remote side. While a properly configured cluster should not fail any step in the process, a situation like an intermittent network connection might cause a failure which would have to be manually corrected on that side, usually by removing the mirrored VM and retrying, or rolling back to a previous snapshot and retrying. Future versions may enhance automatic recovery, but for now this would be up to the administrator. """ - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) if destination in connections_config.keys(): destination_cluster_config = connections_config[destination] destination_api_uri = "{}://{}:{}{}".format( @@ -2334,7 +2345,7 @@ def cli_vm_mirror_promote( destination_api_uri = destination destination_api_key = destination_api_key - retcode, retmsg = pvc.lib.vm.vm_promote_mirror( + retcode, retmsg = pvc_lib_vm.vm_promote_mirror( CLI_CONFIG, domain, destination_api_uri, @@ -2346,7 +2357,7 @@ def cli_vm_mirror_promote( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -2411,7 +2422,7 @@ def cli_vm_backup_create(domain, backup_path, incremental_parent, retain_snapsho f"Backing up VM '{domain}'... ", newline=False, ) - retcode, retmsg = pvc.lib.vm.vm_backup( + retcode, retmsg = pvc_lib_vm.vm_backup( CLI_CONFIG, domain, backup_path, incremental_parent, retain_snapshot ) if retcode: @@ -2459,7 +2470,7 @@ def cli_vm_backup_restore(domain, backup_datestring, backup_path, retain_snapsho f"Restoring backup {backup_datestring} of VM '{domain}'... ", newline=False, ) - retcode, retmsg = pvc.lib.vm.vm_restore( + retcode, retmsg = pvc_lib_vm.vm_restore( CLI_CONFIG, domain, backup_path, backup_datestring, retain_snapshot ) if retcode: @@ -2491,7 +2502,7 @@ def cli_vm_backup_remove(domain, backup_datestring, backup_path): f"Removing backup {backup_datestring} of VM '{domain}'... ", newline=False, ) - retcode, retmsg = pvc.lib.vm.vm_remove_backup( + retcode, retmsg = pvc_lib_vm.vm_remove_backup( CLI_CONFIG, domain, backup_path, backup_datestring ) if retcode: @@ -2577,7 +2588,7 @@ def cli_vm_autobackup(email_report, force_full_flag, wait_flag, cron_flag): else: email_recipients = None - retcode, retmsg = pvc.lib.vm.vm_autobackup( + retcode, retmsg = pvc_lib_vm.vm_autobackup( CLI_CONFIG, email_recipients=email_recipients, force_full_flag=force_full_flag, @@ -2585,7 +2596,7 @@ def cli_vm_autobackup(email_report, force_full_flag, wait_flag, cron_flag): ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) if cron_flag: finish(retcode, None) @@ -2665,7 +2676,7 @@ def cli_vm_automirror(email_report, email_errors_only_flag, wait_flag, cron_flag else: email_recipients = None - retcode, retmsg = pvc.lib.vm.vm_automirror( + retcode, retmsg = pvc_lib_vm.vm_automirror( CLI_CONFIG, email_recipients=email_recipients, email_errors_only_flag=email_errors_only_flag, @@ -2673,7 +2684,7 @@ def cli_vm_automirror(email_report, email_errors_only_flag, wait_flag, cron_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) if cron_flag: finish(retcode, None) @@ -2715,7 +2726,7 @@ def cli_vm_tag_get(domain, format_function): Get the current tags of the virtual machine DOMAIN. """ - retcode, retdata = pvc.lib.vm.vm_tags_get(CLI_CONFIG, domain) + retcode, retdata = pvc_lib_vm.vm_tags_get(CLI_CONFIG, domain) finish(retcode, retdata, format_function) @@ -2740,7 +2751,7 @@ def cli_vm_tag_add(domain, tag, protected): Add TAG to the virtual machine DOMAIN. """ - retcode, retmsg = pvc.lib.vm.vm_tag_set(CLI_CONFIG, domain, "add", tag, protected) + retcode, retmsg = pvc_lib_vm.vm_tag_set(CLI_CONFIG, domain, "add", tag, protected) finish(retcode, retmsg) @@ -2756,7 +2767,7 @@ def cli_vm_tag_remove(domain, tag): Remove TAG from the virtual machine DOMAIN. """ - retcode, retmsg = pvc.lib.vm.vm_tag_set(CLI_CONFIG, domain, "remove", tag) + retcode, retmsg = pvc_lib_vm.vm_tag_set(CLI_CONFIG, domain, "remove", tag) finish(retcode, retmsg) @@ -2796,7 +2807,7 @@ def cli_vm_vcpu_get(domain, format_function): Get the current vCPU count of the virtual machine DOMAIN. """ - retcode, retmsg = pvc.lib.vm.vm_vcpus_get(CLI_CONFIG, domain) + retcode, retmsg = pvc_lib_vm.vm_vcpus_get(CLI_CONFIG, domain) finish(retcode, retmsg, format_function) @@ -2833,7 +2844,7 @@ def cli_vm_vcpu_set(domain, vcpus, topology, restart_flag): else: topology = (1, vcpus, 1) - retcode, retmsg = pvc.lib.vm.vm_vcpus_set( + retcode, retmsg = pvc_lib_vm.vm_vcpus_set( CLI_CONFIG, domain, vcpus, topology, restart_flag ) finish(retcode, retmsg) @@ -2875,7 +2886,7 @@ def cli_vm_memory_get(domain, format_function): Get the current provisioned memory of the virtual machine DOMAIN. """ - retcode, retmsg = pvc.lib.vm.vm_memory_get(CLI_CONFIG, domain) + retcode, retmsg = pvc_lib_vm.vm_memory_get(CLI_CONFIG, domain) finish(retcode, retmsg, format_function) @@ -2895,7 +2906,7 @@ def cli_vm_memory_set(domain, memory, restart_flag): Set the provisioned memory of the virtual machine DOMAIN to MEMORY; MEMORY must be an integer in MB. """ - retcode, retmsg = pvc.lib.vm.vm_memory_set(CLI_CONFIG, domain, memory, restart_flag) + retcode, retmsg = pvc_lib_vm.vm_memory_set(CLI_CONFIG, domain, memory, restart_flag) finish(retcode, retmsg) @@ -2933,7 +2944,7 @@ def cli_vm_network_get(domain, format_function): Get the networks of the virtual machine DOMAIN. """ - retcode, retdata = pvc.lib.vm.vm_networks_get(CLI_CONFIG, domain) + retcode, retdata = pvc_lib_vm.vm_networks_get(CLI_CONFIG, domain) finish(retcode, retdata, format_function) @@ -3011,7 +3022,7 @@ def cli_vm_network_add( if restart_flag and live_flag: live_flag = False - retcode, retmsg = pvc.lib.vm.vm_networks_add( + retcode, retmsg = pvc_lib_vm.vm_networks_add( CLI_CONFIG, domain, net, @@ -3070,7 +3081,7 @@ def cli_vm_network_remove(domain, net, macaddr, sriov_flag, live_flag, restart_f if restart_flag and live_flag: live_flag = False - retcode, retmsg = pvc.lib.vm.vm_networks_remove( + retcode, retmsg = pvc_lib_vm.vm_networks_remove( CLI_CONFIG, domain, net, macaddr, sriov_flag, live_flag, restart_flag ) finish(retcode, retmsg) @@ -3112,7 +3123,7 @@ def cli_vm_volume_get(domain, format_function): Get the volumes of the virtual machine DOMAIN. """ - retcode, retdata = pvc.lib.vm.vm_volumes_get(CLI_CONFIG, domain) + retcode, retdata = pvc_lib_vm.vm_volumes_get(CLI_CONFIG, domain) finish(retcode, retdata, format_function) @@ -3167,7 +3178,7 @@ def cli_vm_volume_add(domain, volume, disk_id, bus, disk_type, live_flag, restar if restart_flag and live_flag: live_flag = False - retcode, retmsg = pvc.lib.vm.vm_volumes_add( + retcode, retmsg = pvc_lib_vm.vm_volumes_add( CLI_CONFIG, domain, volume, disk_id, bus, disk_type, live_flag, restart_flag ) finish(retcode, retmsg) @@ -3197,7 +3208,7 @@ def cli_vm_volume_remove(domain, volume, live_flag, restart_flag): if restart_flag and live_flag: live_flag = False - retcode, retmsg = pvc.lib.vm.vm_volumes_remove( + retcode, retmsg = pvc_lib_vm.vm_volumes_remove( CLI_CONFIG, domain, volume, live_flag, restart_flag ) finish(retcode, retmsg) @@ -3239,9 +3250,9 @@ def cli_vm_log(domain, lines, follow): lines = 1000 if follow: - retcode, retmsg = pvc.lib.vm.follow_console_log(CLI_CONFIG, domain, lines) + retcode, retmsg = pvc_lib_vm.follow_console_log(CLI_CONFIG, domain, lines) else: - retcode, retmsg = pvc.lib.vm.view_console_log(CLI_CONFIG, domain, lines) + retcode, retmsg = pvc_lib_vm.view_console_log(CLI_CONFIG, domain, lines) click.echo_via_pager(retmsg) retmsg = "" finish(retcode, retmsg) @@ -3266,7 +3277,7 @@ def cli_vm_dump(filename, domain): Dump the Libvirt XML definition of virtual machine DOMAIN to stdout. DOMAIN may be a UUID or name. """ - retcode, retdata = pvc.lib.vm.vm_info(CLI_CONFIG, domain) + retcode, retdata = pvc_lib_vm.vm_info(CLI_CONFIG, domain) if not retcode or not retdata.get("name", None): finish(False, 'ERROR: Could not find VM "{}"!'.format(domain)) @@ -3304,7 +3315,7 @@ def cli_vm_info(domain, format_function): Show information about virtual machine DOMAIN. DOMAIN may be a UUID or name. """ - retcode, retdata = pvc.lib.vm.vm_info(CLI_CONFIG, domain) + retcode, retdata = pvc_lib_vm.vm_info(CLI_CONFIG, domain) finish(retcode, retdata, format_function) @@ -3358,7 +3369,7 @@ def cli_vm_list(target_node, target_state, target_tag, limit, negate, format_fun (†) NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid. """ - retcode, retdata = pvc.lib.vm.vm_list( + retcode, retdata = pvc_lib_vm.vm_list( CLI_CONFIG, limit, target_node, target_state, target_tag, negate ) finish(retcode, retdata, format_function) @@ -3484,7 +3495,7 @@ def cli_network_add( IPv6 is fully supported with --ipnet6 and --gateway6 in addition to or instead of IPv4. PVC will configure DHCPv6 in a semi-managed configuration for the network if set. """ - retcode, retmsg = pvc.lib.network.net_add( + retcode, retmsg = pvc_lib_network.net_add( CLI_CONFIG, vni, description, @@ -3589,7 +3600,7 @@ def cli_network_modify( pvc network modify 1001 --gateway 10.1.1.1 --dhcp """ - retcode, retmsg = pvc.lib.network.net_modify( + retcode, retmsg = pvc_lib_network.net_modify( CLI_CONFIG, vni, description, @@ -3622,7 +3633,7 @@ def cli_network_remove(net): that all client VMs have been removed from the network or undefined behaviour may occur. """ - retcode, retmsg = pvc.lib.network.net_remove(CLI_CONFIG, net) + retcode, retmsg = pvc_lib_network.net_remove(CLI_CONFIG, net) finish(retcode, retmsg) @@ -3645,7 +3656,7 @@ def cli_network_info(vni, format_function): Show information about virtual network VNI. """ - retcode, retdata = pvc.lib.network.net_info(CLI_CONFIG, vni) + retcode, retdata = pvc_lib_network.net_info(CLI_CONFIG, vni) finish(retcode, retdata, format_function) @@ -3668,7 +3679,7 @@ def cli_network_list(limit, format_function): List all virtual networks; optionally only match VNIs or Descriptions matching regex LIMIT. """ - retcode, retdata = pvc.lib.network.net_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_network.net_list(CLI_CONFIG, limit) finish(retcode, retdata, format_function) @@ -3701,7 +3712,7 @@ def cli_network_dhcp_add(net, ipaddr, macaddr, hostname): Add a new DHCP static reservation of IP address IPADDR with hostname HOSTNAME for MAC address MACADDR to virtual network NET; NET must be a VNI. """ - retcode, retmsg = pvc.lib.network.net_dhcp_add( + retcode, retmsg = pvc_lib_network.net_dhcp_add( CLI_CONFIG, net, ipaddr, macaddr, hostname ) finish(retcode, retmsg) @@ -3720,7 +3731,7 @@ def cli_network_dhcp_remove(net, macaddr): Remove a DHCP lease for MACADDR from virtual network NET; NET must be a VNI. """ - retcode, retmsg = pvc.lib.network.net_dhcp_remove(CLI_CONFIG, net, macaddr) + retcode, retmsg = pvc_lib_network.net_dhcp_remove(CLI_CONFIG, net, macaddr) finish(retcode, retmsg) @@ -3754,7 +3765,7 @@ def cli_network_dhcp_list(net, limit, only_static, format_function): List all DHCP leases in virtual network NET; optionally only match elements matching regex LIMIT; NET must be a VNI. """ - retcode, retdata = pvc.lib.network.net_dhcp_list( + retcode, retdata = pvc_lib_network.net_dhcp_list( CLI_CONFIG, net, limit, only_static ) finish(retcode, retdata, format_function) @@ -3822,7 +3833,7 @@ def cli_network_acl_add(net, direction, description, rule, order): else: direction = "out" - retcode, retmsg = pvc.lib.network.net_acl_add( + retcode, retmsg = pvc_lib_network.net_acl_add( CLI_CONFIG, net, direction, description, rule, order ) finish(retcode, retmsg) @@ -3843,7 +3854,7 @@ def cli_network_acl_remove(net, rule): Remove an NFT firewall rule RULE from network NET; RULE must be a description; NET must be a VNI. """ - retcode, retmsg = pvc.lib.network.net_acl_remove(CLI_CONFIG, net, rule) + retcode, retmsg = pvc_lib_network.net_acl_remove(CLI_CONFIG, net, rule) finish(retcode, retmsg) @@ -3882,7 +3893,7 @@ def cli_network_acl_list(net, limit, direction, format_function): else: direction = "out" - retcode, retdata = pvc.lib.network.net_acl_list(CLI_CONFIG, net, limit, direction) + retcode, retdata = pvc_lib_network.net_acl_list(CLI_CONFIG, net, limit, direction) finish(retcode, retdata, format_function) @@ -3932,7 +3943,7 @@ def cli_network_sriov_pf_list(node, format_function): """ List all SR-IOV PFs on NODE. """ - retcode, retdata = pvc.lib.network.net_sriov_pf_list(CLI_CONFIG, node) + retcode, retdata = pvc_lib_network.net_sriov_pf_list(CLI_CONFIG, node) finish(retcode, retdata, format_function) @@ -4045,7 +4056,7 @@ def net_sriov_vf_set( False, "At least one configuration property must be specified to update." ) - retcode, retmsg = pvc.lib.network.net_sriov_vf_set( + retcode, retmsg = pvc_lib_network.net_sriov_vf_set( CLI_CONFIG, node, vf, @@ -4079,7 +4090,7 @@ def cli_network_sriov_vf_info(node, vf, format_function): """ Show details of the SR-IOV VF on NODE. """ - retcode, retdata = pvc.lib.network.net_sriov_vf_info(CLI_CONFIG, node, vf) + retcode, retdata = pvc_lib_network.net_sriov_vf_info(CLI_CONFIG, node, vf) finish(retcode, retdata, format_function) @@ -4102,7 +4113,7 @@ def cli_network_sriov_vf_list(node, pf, format_function): """ List all SR-IOV VFs on NODE, optionally limited to device PF. """ - retcode, retdata = pvc.lib.network.net_sriov_vf_list(CLI_CONFIG, node, pf) + retcode, retdata = pvc_lib_network.net_sriov_vf_list(CLI_CONFIG, node, pf) finish(retcode, retdata, format_function) @@ -4139,7 +4150,7 @@ def cli_storage_status(format_function): Show detailed status of the storage cluster. """ - retcode, retdata = pvc.lib.storage.ceph_status(CLI_CONFIG) + retcode, retdata = pvc_lib_storage.ceph_status(CLI_CONFIG) finish(retcode, retdata, format_function) @@ -4161,7 +4172,7 @@ def cli_storage_util(format_function): Show utilization of the storage cluster. """ - retcode, retdata = pvc.lib.storage.ceph_util(CLI_CONFIG) + retcode, retdata = pvc_lib_storage.ceph_util(CLI_CONFIG) finish(retcode, retdata, format_function) @@ -4205,12 +4216,12 @@ def cli_storage_benchmark_run(pool, name, wait_flag): Run a storage benchmark on POOL in the background. """ - retcode, retmsg = pvc.lib.storage.ceph_benchmark_run( + retcode, retmsg = pvc_lib_storage.ceph_benchmark_run( CLI_CONFIG, pool, name, wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4232,7 +4243,7 @@ def cli_storage_benchmark_info(job, format_function): Show full details of storage benchmark JOB. """ - retcode, retdata = pvc.lib.storage.ceph_benchmark_list(CLI_CONFIG, job) + retcode, retdata = pvc_lib_storage.ceph_benchmark_list(CLI_CONFIG, job) finish(retcode, retdata, format_function) @@ -4254,7 +4265,7 @@ def cli_storage_benchmark_list(job, format_function): List all Ceph storage benchmarks; optionally only match JOB. """ - retcode, retdata = pvc.lib.storage.ceph_benchmark_list(CLI_CONFIG, job) + retcode, retdata = pvc_lib_storage.ceph_benchmark_list(CLI_CONFIG, job) finish(retcode, retdata, format_function) @@ -4304,12 +4315,12 @@ def cli_storage_osd_create_db_vg(node, device, wait_flag): (!) WARNING: If the OSD database device fails, all OSDs on the node using it will be lost and must be recreated. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_db_vg_add( + retcode, retmsg = pvc_lib_storage.ceph_osd_db_vg_add( CLI_CONFIG, node, device, wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4385,7 +4396,7 @@ def cli_storage_osd_add( (†) NOTE: This command may take a long time to complete. Observe the node logs of the hosting OSD node for detailed status. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_add( + retcode, retmsg = pvc_lib_storage.ceph_osd_add( CLI_CONFIG, node, device, @@ -4397,7 +4408,7 @@ def cli_storage_osd_add( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4468,7 +4479,7 @@ def cli_storage_osd_replace( (†) NOTE: This command may take a long time to complete. Observe the node logs of the hosting OSD node for detailed status. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_replace( + retcode, retmsg = pvc_lib_storage.ceph_osd_replace( CLI_CONFIG, osdid, new_device, @@ -4480,7 +4491,7 @@ def cli_storage_osd_replace( ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4513,12 +4524,12 @@ def cli_storage_osd_refresh(osdid, device, wait_flag): (†) NOTE: This command may take a long time to complete. Observe the node logs of the hosting OSD node for detailed status. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_refresh( + retcode, retmsg = pvc_lib_storage.ceph_osd_refresh( CLI_CONFIG, osdid, device, wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4556,12 +4567,12 @@ def cli_storage_osd_remove(osdid, force_flag, wait_flag): (†) NOTE: This command may take a long time to complete. Observe the node logs of the hosting OSD node for detailed status. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_remove( + retcode, retmsg = pvc_lib_storage.ceph_osd_remove( CLI_CONFIG, osdid, force_flag, wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -4576,7 +4587,7 @@ def cli_storage_osd_in(osdid): Set a Ceph OSD with ID OSDID online. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_state(CLI_CONFIG, osdid, "in") + retcode, retmsg = pvc_lib_storage.ceph_osd_state(CLI_CONFIG, osdid, "in") finish(retcode, retmsg) @@ -4591,7 +4602,7 @@ def cli_storage_osd_out(osdid): Set a Ceph OSD with ID OSDID offline. """ - retcode, retmsg = pvc.lib.storage.ceph_osd_state(CLI_CONFIG, osdid, "out") + retcode, retmsg = pvc_lib_storage.ceph_osd_state(CLI_CONFIG, osdid, "out") finish(retcode, retmsg) @@ -4610,7 +4621,7 @@ def cli_storage_osd_set(osd_property): full|pause|noup|nodown|noout|noin|nobackfill|norebalance|norecover|noscrub|nodeep-scrub|notieragent|sortbitwise|recovery_deletes|require_jewel_osds|require_kraken_osds """ - retcode, retmsg = pvc.lib.storage.ceph_osd_option(CLI_CONFIG, osd_property, "set") + retcode, retmsg = pvc_lib_storage.ceph_osd_option(CLI_CONFIG, osd_property, "set") finish(retcode, retmsg) @@ -4629,7 +4640,7 @@ def cli_storage_osd_unset(osd_property): full|pause|noup|nodown|noout|noin|nobackfill|norebalance|norecover|noscrub|nodeep-scrub|notieragent|sortbitwise|recovery_deletes|require_jewel_osds|require_kraken_osds """ - retcode, retmsg = pvc.lib.storage.ceph_osd_option(CLI_CONFIG, osd_property, "unset") + retcode, retmsg = pvc_lib_storage.ceph_osd_option(CLI_CONFIG, osd_property, "unset") finish(retcode, retmsg) @@ -4658,7 +4669,7 @@ def cli_storage_osd_list(limit, format_function): List all Ceph OSDs; optionally only match elements matching ID regex LIMIT. """ - retcode, retdata = pvc.lib.storage.ceph_osd_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_storage.ceph_osd_list(CLI_CONFIG, limit) finish(retcode, retdata, format_function) @@ -4712,7 +4723,7 @@ def cli_storage_pool_add(name, pgs, tier, replcfg): The placement group count must be a non-zero power of 2. Generally you should choose a PGS number such that there will be 50-150 PGs on each OSD in a single node (before replicas); 64, 128, or 256 are good values for small clusters (1-5 OSDs per node); higher values are recommended for higher node or OSD counts. For additional details please see the documentation. """ - retcode, retmsg = pvc.lib.storage.ceph_pool_add( + retcode, retmsg = pvc_lib_storage.ceph_pool_add( CLI_CONFIG, name, pgs, replcfg, tier ) finish(retcode, retmsg) @@ -4732,7 +4743,7 @@ def cli_storage_pool_remove(name): DANGER: This will completely remove the pool and all volumes contained in it from the cluster. """ - retcode, retmsg = pvc.lib.storage.ceph_pool_remove(CLI_CONFIG, name) + retcode, retmsg = pvc_lib_storage.ceph_pool_remove(CLI_CONFIG, name) finish(retcode, retmsg) @@ -4753,7 +4764,7 @@ def cli_storage_pool_set_pgs(name, pgs): Placement group counts may be increased or decreased as required though frequent alteration is not recommended. Placement group alterations are intensive operations on the storage cluster. """ - retcode, retmsg = pvc.lib.storage.ceph_pool_set_pgs(CLI_CONFIG, name, pgs) + retcode, retmsg = pvc_lib_storage.ceph_pool_set_pgs(CLI_CONFIG, name, pgs) finish(retcode, retmsg) @@ -4782,7 +4793,7 @@ def cli_storage_pool_list(limit, format_function): List all Ceph RBD pools; optionally only match elements matching name regex LIMIT. """ - retcode, retdata = pvc.lib.storage.ceph_pool_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_storage.ceph_pool_list(CLI_CONFIG, limit) finish(retcode, retdata, format_function) @@ -4826,7 +4837,7 @@ def cli_storage_volume_add(pool, name, size, force_flag): PVC will prevent the creation of a volume who's size is greater than the 80% full safe free space on the pool. This can be overridden with the "-f"/"--force" option but this may be dangerous! """ - retcode, retmsg = pvc.lib.storage.ceph_volume_add( + retcode, retmsg = pvc_lib_storage.ceph_volume_add( CLI_CONFIG, pool, name, size, force_flag=force_flag ) finish(retcode, retmsg) @@ -4861,7 +4872,7 @@ def cli_storage_volume_upload(pool, name, image_format, image_file): echo(CLI_CONFIG, "ERROR: File '{}' does not exist!".format(image_file)) exit(1) - retcode, retmsg = pvc.lib.storage.ceph_volume_upload( + retcode, retmsg = pvc_lib_storage.ceph_volume_upload( CLI_CONFIG, pool, name, image_format, image_file ) finish(retcode, retmsg) @@ -4882,7 +4893,7 @@ def cli_storage_volume_remove(pool, name): DANGER: This will completely remove the volume and all data contained in it. """ - retcode, retmsg = pvc.lib.storage.ceph_volume_remove(CLI_CONFIG, pool, name) + retcode, retmsg = pvc_lib_storage.ceph_volume_remove(CLI_CONFIG, pool, name) finish(retcode, retmsg) @@ -4912,7 +4923,7 @@ def cli_storage_volume_resize(pool, name, size, force_flag): PVC will prevent the resize of a volume who's new size is greater than the 80% full safe free space on the pool. This can be overridden with the "-f"/"--force" option but this may be dangerous! """ - retcode, retmsg = pvc.lib.storage.ceph_volume_modify( + retcode, retmsg = pvc_lib_storage.ceph_volume_modify( CLI_CONFIG, pool, name, new_size=size, force_flag=force_flag ) finish(retcode, retmsg) @@ -4932,7 +4943,7 @@ def cli_storage_volume_rename(pool, name, new_name): Rename an existing Ceph RBD volume with name NAME in pool POOL to name NEW_NAME. """ - retcode, retmsg = pvc.lib.storage.ceph_volume_modify( + retcode, retmsg = pvc_lib_storage.ceph_volume_modify( CLI_CONFIG, pool, name, new_name=new_name ) finish(retcode, retmsg) @@ -4963,7 +4974,7 @@ def cli_storage_volume_clone(pool, name, new_name, force_flag): PVC will prevent the clone of a volume who's new size is greater than the 80% full safe free space on the pool. This can be overridden with the "-f"/"--force" option but this may be dangerous! """ - retcode, retmsg = pvc.lib.storage.ceph_volume_clone( + retcode, retmsg = pvc_lib_storage.ceph_volume_clone( CLI_CONFIG, pool, name, new_name, force_flag=force_flag ) finish(retcode, retmsg) @@ -5002,7 +5013,7 @@ def cli_storage_volume_list(limit, pool, format_function): List all Ceph RBD volumes; optionally only match elements matching name regex LIMIT. """ - retcode, retdata = pvc.lib.storage.ceph_volume_list(CLI_CONFIG, limit, pool) + retcode, retdata = pvc_lib_storage.ceph_volume_list(CLI_CONFIG, limit, pool) finish(retcode, retdata, format_function) @@ -5038,7 +5049,7 @@ def cli_storage_volume_snapshot_add(pool, volume, name): VM at the moment of the snapshot. """ - retcode, retmsg = pvc.lib.storage.ceph_snapshot_add(CLI_CONFIG, pool, volume, name) + retcode, retmsg = pvc_lib_storage.ceph_snapshot_add(CLI_CONFIG, pool, volume, name) finish(retcode, retmsg) @@ -5055,7 +5066,7 @@ def cli_storage_volume_snapshot_rename(pool, volume, name, new_name): """ Rename an existing Ceph RBD volume snapshot with name NAME to name NEW_NAME for volume VOLUME in pool POOL. """ - retcode, retmsg = pvc.lib.storage.ceph_snapshot_modify( + retcode, retmsg = pvc_lib_storage.ceph_snapshot_modify( CLI_CONFIG, pool, volume, name, new_name=new_name ) finish(retcode, retmsg) @@ -5077,7 +5088,7 @@ def cli_storage_volume_snapshot_remove(pool, volume, name): DANGER: This will completely remove the snapshot. """ - retcode, retmsg = pvc.lib.storage.ceph_snapshot_remove( + retcode, retmsg = pvc_lib_storage.ceph_snapshot_remove( CLI_CONFIG, pool, volume, name ) finish(retcode, retmsg) @@ -5107,7 +5118,7 @@ def cli_storage_volume_snapshot_rollback(pool, volume, name): VM at the moment of the snapshot. """ - retcode, retmsg = pvc.lib.storage.ceph_snapshot_rollback( + retcode, retmsg = pvc_lib_storage.ceph_snapshot_rollback( CLI_CONFIG, pool, volume, name ) finish(retcode, retmsg) @@ -5150,7 +5161,7 @@ def cli_storage_volume_snapshot_list(pool, volume, limit, format_function): List all Ceph RBD volume snapshots; optionally only match elements matching name regex LIMIT. """ - retcode, retdata = pvc.lib.storage.ceph_snapshot_list( + retcode, retdata = pvc_lib_storage.ceph_snapshot_list( CLI_CONFIG, limit, volume, pool ) finish(retcode, retdata, format_function) @@ -5309,7 +5320,7 @@ def cli_provisioner_template_system_add( if migration_max_downtime: params["migration_max_downtime"] = migration_max_downtime - retcode, retdata = pvc.lib.provisioner.template_add( + retcode, retdata = pvc_lib_provisioner.template_add( CLI_CONFIG, params, template_type="system" ) finish(retcode, retdata) @@ -5406,7 +5417,7 @@ def cli_provisioner_template_system_modify( params["migration_method"] = migration_method params["migration_max_downtime"] = migration_max_downtime - retcode, retdata = pvc.lib.provisioner.template_modify( + retcode, retdata = pvc_lib_provisioner.template_modify( CLI_CONFIG, params, name, template_type="system" ) finish(retcode, retdata) @@ -5424,7 +5435,7 @@ def cli_provisioner_template_system_remove(name): Remove system template NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_remove( + retcode, retdata = pvc_lib_provisioner.template_remove( CLI_CONFIG, name, template_type="system" ) finish(retcode, retdata) @@ -5448,7 +5459,7 @@ def cli_provisioner_template_system_list(limit, format_function): """ List all system templates in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_list( + retcode, retdata = pvc_lib_provisioner.template_list( CLI_CONFIG, limit, template_type="system" ) finish(retcode, retdata, format_function) @@ -5516,7 +5527,7 @@ def cli_provisioner_template_network_add(name, mac_template): params["name"] = name params["mac_template"] = mac_template - retcode, retdata = pvc.lib.provisioner.template_add( + retcode, retdata = pvc_lib_provisioner.template_add( CLI_CONFIG, params, template_type="network" ) finish(retcode, retdata) @@ -5540,7 +5551,7 @@ def cli_provisioner_template_network_remove(name): Remove network template MAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_remove( + retcode, retdata = pvc_lib_provisioner.template_remove( CLI_CONFIG, name, template_type="network" ) finish(retcode, retdata) @@ -5564,7 +5575,7 @@ def cli_provisioner_template_network_list(limit, format_function): """ List all network templates in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_list( + retcode, retdata = pvc_lib_provisioner.template_list( CLI_CONFIG, limit, template_type="network" ) finish(retcode, retdata, format_function) @@ -5614,7 +5625,7 @@ def cli_provisioner_template_network_vni_add(name, vni, permit_duplicate_flag): if permit_duplicate_flag: params["permit_duplicate"] = True - retcode, retdata = pvc.lib.provisioner.template_element_add( + retcode, retdata = pvc_lib_provisioner.template_element_add( CLI_CONFIG, name, vni, params, element_type="net", template_type="network" ) finish(retcode, retdata) @@ -5633,7 +5644,7 @@ def cli_provisioner_template_network_vni_remove(name, vni): Remove network VNI from network template NAME. """ - retcode, retdata = pvc.lib.provisioner.template_element_remove( + retcode, retdata = pvc_lib_provisioner.template_element_remove( CLI_CONFIG, name, vni, element_type="net", template_type="network" ) finish(retcode, retdata) @@ -5667,7 +5678,7 @@ def cli_provisioner_template_storage_add(name): params = dict() params["name"] = name - retcode, retdata = pvc.lib.provisioner.template_add( + retcode, retdata = pvc_lib_provisioner.template_add( CLI_CONFIG, params, template_type="storage" ) finish(retcode, retdata) @@ -5691,7 +5702,7 @@ def cli_provisioner_template_storage_remove(name): Remove storage template NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_remove( + retcode, retdata = pvc_lib_provisioner.template_remove( CLI_CONFIG, name, template_type="storage" ) finish(retcode, retdata) @@ -5715,7 +5726,7 @@ def cli_provisioner_template_storage_list(limit, format_function): """ List all storage templates in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.template_list( + retcode, retdata = pvc_lib_provisioner.template_list( CLI_CONFIG, limit, template_type="storage" ) finish(retcode, retdata, format_function) @@ -5809,7 +5820,7 @@ def cli_provisioner_template_storage_disk_add( if filesystem and mountpoint: params["mountpoint"] = mountpoint - retcode, retdata = pvc.lib.provisioner.template_element_add( + retcode, retdata = pvc_lib_provisioner.template_element_add( CLI_CONFIG, name, disk, params, element_type="disk", template_type="storage" ) finish(retcode, retdata) @@ -5830,7 +5841,7 @@ def cli_provisioner_template_storage_disk_remove(name, disk): DISK must be a Linux-style disk identifier such as "sda" or "vdb". """ - retcode, retdata = pvc.lib.provisioner.template_element_remove( + retcode, retdata = pvc_lib_provisioner.template_element_remove( CLI_CONFIG, name, disk, element_type="disk", template_type="storage" ) finish(retcode, retdata) @@ -5867,7 +5878,7 @@ def cli_provisioner_userdata_add(name, filename): userdata = filename.read() filename.close() try: - yload(userdata, Loader=SafeYAMLLoader) + yload(userdata, Loader=yaml.SafeLoader) except Exception as e: echo(CLI_CONFIG, "Error: Userdata document is malformed") cleanup(False, e) @@ -5876,7 +5887,7 @@ def cli_provisioner_userdata_add(name, filename): params["name"] = name params["data"] = userdata.strip() - retcode, retmsg = pvc.lib.provisioner.userdata_add(CLI_CONFIG, params) + retcode, retmsg = pvc_lib_provisioner.userdata_add(CLI_CONFIG, params) finish(retcode, retmsg) @@ -5904,7 +5915,7 @@ def cli_provisioner_userdata_modify(name, filename, editor): if editor is True: # 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: echo(CLI_CONFIG, retdata) exit(1) @@ -5921,7 +5932,7 @@ def cli_provisioner_userdata_modify(name, filename, editor): # Show a diff and confirm diff = list( - unified_diff( + difflib.unified_diff( current_userdata.split("\n"), new_userdata.split("\n"), fromfile="current", @@ -5939,12 +5950,12 @@ def cli_provisioner_userdata_modify(name, filename, editor): echo(CLI_CONFIG, "Pending modifications:") echo(CLI_CONFIG, "") for line in diff: - if match(r"^\+", line) is not None: - echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET) - elif match(r"^\-", line) is not None: - echo(CLI_CONFIG, Fore.RED + line + Fore.RESET) - elif match(r"^\^", line) is not None: - echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET) + if re_module.match(r"^\+", line) is not None: + echo(CLI_CONFIG, colorama.Fore.GREEN + line + colorama.Fore.RESET) + elif re_module.match(r"^\-", line) is not None: + echo(CLI_CONFIG, colorama.Fore.RED + line + colorama.Fore.RESET) + elif re_module.match(r"^\^", line) is not None: + echo(CLI_CONFIG, colorama.Fore.BLUE + line + colorama.Fore.RESET) else: echo(CLI_CONFIG, line) echo(CLI_CONFIG, "") @@ -5960,7 +5971,7 @@ def cli_provisioner_userdata_modify(name, filename, editor): filename.close() try: - yload(userdata, Loader=SafeYAMLLoader) + yload(userdata, Loader=yaml.SafeLoader) except Exception as e: echo(CLI_CONFIG, "Error: Userdata document is malformed") cleanup(False, e) @@ -5968,7 +5979,7 @@ def cli_provisioner_userdata_modify(name, filename, editor): params = dict() params["data"] = userdata - retcode, retmsg = pvc.lib.provisioner.userdata_modify(CLI_CONFIG, name, params) + retcode, retmsg = pvc_lib_provisioner.userdata_modify(CLI_CONFIG, name, params) finish(retcode, retmsg) @@ -5984,7 +5995,7 @@ def cli_provisioner_userdata_remove(name): Remove userdata document NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.userdata_remove(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.userdata_remove(CLI_CONFIG, name) finish(retcode, retdata) @@ -5999,7 +6010,7 @@ def cli_provisioner_userdata_show(name): Show the full contents of userdata document NAME. """ - retcode, retdata = pvc.lib.provisioner.userdata_show(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.userdata_show(CLI_CONFIG, name) finish(retcode, retdata) @@ -6030,7 +6041,7 @@ def cli_provisioner_userdata_list(limit, long_output, format_function): List all userdata documents in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.userdata_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_provisioner.userdata_list(CLI_CONFIG, limit) CLI_CONFIG["long_output"] = long_output finish(retcode, retdata, format_function) @@ -6070,7 +6081,7 @@ def cli_provisioner_script_add(name, filename): params["name"] = name params["data"] = script.strip() - retcode, retmsg = pvc.lib.provisioner.script_add(CLI_CONFIG, params) + retcode, retmsg = pvc_lib_provisioner.script_add(CLI_CONFIG, params) finish(retcode, retmsg) @@ -6098,7 +6109,7 @@ def cli_provisioner_script_modify(name, filename, editor): if editor is True: # 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: echo(CLI_CONFIG, retdata) exit(1) @@ -6113,7 +6124,7 @@ def cli_provisioner_script_modify(name, filename, editor): # Show a diff and confirm diff = list( - unified_diff( + difflib.unified_diff( current_script.split("\n"), new_script.split("\n"), fromfile="current", @@ -6131,12 +6142,12 @@ def cli_provisioner_script_modify(name, filename, editor): echo(CLI_CONFIG, "Pending modifications:") echo(CLI_CONFIG, "") for line in diff: - if match(r"^\+", line) is not None: - echo(CLI_CONFIG, Fore.GREEN + line + Fore.RESET) - elif match(r"^\-", line) is not None: - echo(CLI_CONFIG, Fore.RED + line + Fore.RESET) - elif match(r"^\^", line) is not None: - echo(CLI_CONFIG, Fore.BLUE + line + Fore.RESET) + if re_module.match(r"^\+", line) is not None: + echo(CLI_CONFIG, colorama.Fore.GREEN + line + colorama.Fore.RESET) + elif re_module.match(r"^\-", line) is not None: + echo(CLI_CONFIG, colorama.Fore.RED + line + colorama.Fore.RESET) + elif re_module.match(r"^\^", line) is not None: + echo(CLI_CONFIG, colorama.Fore.BLUE + line + colorama.Fore.RESET) else: echo(CLI_CONFIG, line) echo(CLI_CONFIG, "") @@ -6154,7 +6165,7 @@ def cli_provisioner_script_modify(name, filename, editor): params = dict() params["data"] = script - retcode, retmsg = pvc.lib.provisioner.script_modify(CLI_CONFIG, name, params) + retcode, retmsg = pvc_lib_provisioner.script_modify(CLI_CONFIG, name, params) finish(retcode, retmsg) @@ -6170,7 +6181,7 @@ def cli_provisioner_script_remove(name): Remove script NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.script_remove(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.script_remove(CLI_CONFIG, name) finish(retcode, retdata) @@ -6185,7 +6196,7 @@ def cli_provisioner_script_show(name): Show the full contents of script document NAME. """ - retcode, retdata = pvc.lib.provisioner.script_show(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.script_show(CLI_CONFIG, name) finish(retcode, retdata) @@ -6216,7 +6227,7 @@ def cli_provisioner_script_list(limit, long_output, format_function): List all scripts in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.script_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_provisioner.script_list(CLI_CONFIG, limit) CLI_CONFIG["long_output"] = long_output finish(retcode, retdata, format_function) @@ -6267,7 +6278,7 @@ def cli_provisioner_ova_upload(name, filename, pool): params["pool"] = pool params["ova_size"] = path.getsize(filename) - retcode, retdata = pvc.lib.provisioner.ova_upload( + retcode, retdata = pvc_lib_provisioner.ova_upload( CLI_CONFIG, name, filename, params ) finish(retcode, retdata) @@ -6285,7 +6296,7 @@ def cli_provisioner_ova_remove(name): Remove OVA image NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.ova_remove(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.ova_remove(CLI_CONFIG, name) finish(retcode, retdata) @@ -6314,7 +6325,7 @@ def cli_provisioner_ova_list(limit, format_function): List all OVA images in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.ova_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_provisioner.ova_list(CLI_CONFIG, limit) finish(retcode, retdata, format_function) @@ -6420,7 +6431,7 @@ def cli_provisioner_profile_add( params["ova"] = ova params["arg"] = script_args - retcode, retdata = pvc.lib.provisioner.profile_add(CLI_CONFIG, params) + retcode, retdata = pvc_lib_provisioner.profile_add(CLI_CONFIG, params) finish(retcode, retdata) @@ -6507,7 +6518,7 @@ def cli_provisioner_profile_modify( if script_args is not None: params["arg"] = script_args - retcode, retdata = pvc.lib.provisioner.profile_modify(CLI_CONFIG, name, params) + retcode, retdata = pvc_lib_provisioner.profile_modify(CLI_CONFIG, name, params) finish(retcode, retdata) @@ -6523,7 +6534,7 @@ def cli_provisioner_profile_remove(name): Remove profile NAME from the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.profile_remove(CLI_CONFIG, name) + retcode, retdata = pvc_lib_provisioner.profile_remove(CLI_CONFIG, name) finish(retcode, retdata) @@ -6551,7 +6562,7 @@ def cli_provisioner_profile_list(limit, format_function): """ List all profiles in the PVC cluster provisioner. """ - retcode, retdata = pvc.lib.provisioner.profile_list(CLI_CONFIG, limit) + retcode, retdata = pvc_lib_provisioner.profile_list(CLI_CONFIG, limit) finish(retcode, retdata, format_function) @@ -6618,12 +6629,12 @@ def cli_provisioner_create( if not define_flag: start_flag = False - retcode, retmsg = pvc.lib.provisioner.vm_create( + retcode, retmsg = pvc_lib_provisioner.vm_create( CLI_CONFIG, name, profile, define_flag, start_flag, script_args, wait_flag ) if retcode and wait_flag: - retmsg = wait_for_celery_task(CLI_CONFIG, retmsg) + retmsg = pvc_cli_waiters.wait_for_celery_task(CLI_CONFIG, retmsg) finish(retcode, retmsg) @@ -6708,7 +6719,7 @@ def cli_connection_add( scheme = "https" if ssl_flag else "http" # Get the store data - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) # Add (or update) the new connection details connections_config[name] = { @@ -6720,7 +6731,7 @@ def cli_connection_add( } # Update the store data - update_store(CLI_CONFIG["store_path"], connections_config) + pvc_lib_provisioner.update_store(CLI_CONFIG["store_path"], connections_config) finish( True, @@ -6744,7 +6755,7 @@ def cli_connection_remove( """ # Get the store data - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) # Remove the entry matching the name try: @@ -6753,7 +6764,7 @@ def cli_connection_remove( finish(False, f"""No connection found with name "{name}" in local database""") # Update the store data - update_store(CLI_CONFIG["store_path"], connections_config) + pvc_lib_provisioner.update_store(CLI_CONFIG["store_path"], connections_config) finish(True, f"""Removed connection "{name}" from client database""") @@ -6798,7 +6809,7 @@ def cli_connection_list( "json-prometheus": Output in Prometheus file service discovery JSON format. """ - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) connections_data = cli_connection_list_parser(connections_config, show_keys_flag) finish(True, connections_data, format_function) @@ -6836,7 +6847,7 @@ def cli_connection_detail( newline=False, stderr=True, ) - connections_config = get_store(CLI_CONFIG["store_path"]) + connections_config = pvc_lib_provisioner.get_store(CLI_CONFIG["store_path"]) connections_data = cli_connection_detail_parser(connections_config) echo(CLI_CONFIG, "done.", stderr=True) echo(CLI_CONFIG, "", stderr=True) @@ -6960,15 +6971,15 @@ def cli( makedirs(store_path) if not path.isfile(f"{store_path}/{DEFAULT_STORE_FILENAME}"): - update_store(store_path, {"local": DEFAULT_STORE_DATA}) + pvc_lib_provisioner.update_store(store_path, {"local": DEFAULT_STORE_DATA}) - store_data = get_store(store_path) + store_data = pvc_lib_provisioner.get_store(store_path) # If the connection isn't in the store, mark it bad but pass the value if _connection is not None and _connection not in store_data.keys(): CLI_CONFIG = {"badcfg": True, "connection": _connection} else: - CLI_CONFIG = get_config(store_data, _connection) + CLI_CONFIG = pvc_lib_cluster.get_config(store_data, _connection) CLI_CONFIG["store_path"] = store_path diff --git a/client-cli/pvc/lib/common.py b/client-cli/pvc/lib/common.py index a918a1e7..0b79b7e8 100644 --- a/client-cli/pvc/lib/common.py +++ b/client-cli/pvc/lib/common.py @@ -23,10 +23,11 @@ from ast import literal_eval from click import echo, progressbar from math import ceil from os.path import getsize -from requests import get, post, put, patch, delete, Response -from requests.exceptions import ConnectionError from time import time -from urllib3 import disable_warnings +import socket +import json +import ssl +import base64 def format_bytes(size_bytes): @@ -139,14 +140,186 @@ class UploadProgressBar(object): echo(self.end_message + self.end_suffix, nl=self.end_nl) -class ErrorResponse(Response): - def __init__(self, json_data, status_code, headers): - self.json_data = json_data +class Response: + """Minimal Response class to replace requests.Response""" + def __init__(self, status_code, headers, content): self.status_code = status_code self.headers = headers - + self.content = content + self._json = None + def json(self): - return self.json_data + if self._json is None: + try: + self._json = json.loads(self.content.decode('utf-8')) + except json.JSONDecodeError: + self._json = {} + return self._json + + +class ConnectionError(Exception): + """Simple ConnectionError class to replace requests.exceptions.ConnectionError""" + pass + + +class ErrorResponse(Response): + def __init__(self, json_data, status_code, headers): + self.status_code = status_code + self.headers = headers + self._json = json_data + self.content = json.dumps(json_data).encode('utf-8') if json_data else b'' + + def json(self): + return self._json + + +def _parse_url(url): + """Simple URL parser without using urllib""" + if '://' in url: + scheme, rest = url.split('://', 1) + else: + scheme = 'http' + rest = url + + if '/' in rest: + host_port, path = rest.split('/', 1) + path = '/' + path + else: + host_port = rest + path = '/' + + if ':' in host_port: + host, port_str = host_port.split(':', 1) + port = int(port_str) + else: + host = host_port + port = 443 if scheme == 'https' else 80 + + return scheme, host, port, path + + +def _encode_params(params): + """Simple URL parameter encoder""" + if not params: + return '' + + parts = [] + for key, value in params.items(): + if isinstance(value, bool): + value = str(value).lower() + elif value is None: + value = '' + else: + value = str(value) + parts.append(f"{key}={value}") + + return '?' + '&'.join(parts) + + +def _make_request(method, url, headers=None, params=None, data=None, files=None, timeout=5, verify=True): + """Simple HTTP client using sockets""" + headers = headers or {} + scheme, host, port, path = _parse_url(url) + + # Add query parameters + path += _encode_params(params) + + # Prepare body + body = None + if data is not None and files is None: + if isinstance(data, dict): + body = json.dumps(data).encode('utf-8') + if 'Content-Type' not in headers: + headers['Content-Type'] = 'application/json' + else: + body = data.encode('utf-8') if isinstance(data, str) else data + + # Handle file uploads + if files: + boundary = f'----WebKitFormBoundary{int(time())}' + headers['Content-Type'] = f'multipart/form-data; boundary={boundary}' + + body = b'' + # Add form fields + if data: + for key, value in data.items(): + body += f'--{boundary}\r\n'.encode() + body += f'Content-Disposition: form-data; name="{key}"\r\n\r\n'.encode() + body += f'{value}\r\n'.encode() + + # Add files + for key, file_tuple in files.items(): + filename, fileobj, content_type = file_tuple + body += f'--{boundary}\r\n'.encode() + body += f'Content-Disposition: form-data; name="{key}"; filename="{filename}"\r\n'.encode() + body += f'Content-Type: {content_type}\r\n\r\n'.encode() + body += fileobj.read() + body += b'\r\n' + + body += f'--{boundary}--\r\n'.encode() + + # Create socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(timeout) + + try: + # Handle SSL for HTTPS + if scheme == 'https': + context = ssl.create_default_context() + if not verify: + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + + # Connect + s.connect((host, port)) + + # Build request + request = f"{method} {path} HTTP/1.1\r\n" + request += f"Host: {host}\r\n" + + for key, value in headers.items(): + request += f"{key}: {value}\r\n" + + if body: + request += f"Content-Length: {len(body)}\r\n" + + request += "Connection: close\r\n\r\n" + + # Send request + s.sendall(request.encode('utf-8')) + if body: + s.sendall(body) + + # Read response + response_data = b"" + while True: + chunk = s.recv(4096) + if not chunk: + break + response_data += chunk + + # Parse response + header_end = response_data.find(b'\r\n\r\n') + headers_raw = response_data[:header_end].decode('utf-8') + body_raw = response_data[header_end + 4:] + + # Parse status code + status_line = headers_raw.split('\r\n')[0] + status_code = int(status_line.split(' ')[1]) + + # Parse headers + headers_dict = {} + for line in headers_raw.split('\r\n')[1:]: + if not line: + continue + key, value = line.split(':', 1) + headers_dict[key.strip()] = value.strip() + + return Response(status_code, headers_dict, body_raw) + + finally: + s.close() def call_api( @@ -159,7 +332,7 @@ def call_api( files=None, ): # Set the connect timeout to 2 seconds but extremely long (48 hour) data timeout - timeout = (2.05, 172800) + timeout = 2.05 # Craft the URI uri = "{}://{}{}{}".format( @@ -171,7 +344,6 @@ def call_api( headers["X-Api-Key"] = config["api_key"] # Determine the request type and hit the API - disable_warnings() try: response = None if operation == "get": @@ -179,61 +351,66 @@ def call_api( for i in range(3): failed = False try: - response = get( - uri, - timeout=timeout, - headers=headers, - params=params, - data=data, - verify=config["verify_ssl"], + response = _make_request( + "GET", + uri, + headers=headers, + params=params, + data=data, + timeout=timeout, + verify=config["verify_ssl"] ) if response.status_code in retry_on_code: failed = True continue break - except ConnectionError: + except Exception: failed = True continue if failed: error = f"Code {response.status_code}" if response else "Timeout" raise ConnectionError(f"Failed to connect after 3 tries ({error})") - if operation == "post": - response = post( - uri, - timeout=timeout, - headers=headers, - params=params, - data=data, - files=files, - verify=config["verify_ssl"], + elif operation == "post": + response = _make_request( + "POST", + uri, + headers=headers, + params=params, + data=data, + files=files, + timeout=timeout, + verify=config["verify_ssl"] ) - if operation == "put": - response = put( - uri, - timeout=timeout, - headers=headers, - params=params, - data=data, - files=files, - verify=config["verify_ssl"], + elif operation == "put": + response = _make_request( + "PUT", + uri, + headers=headers, + params=params, + data=data, + files=files, + timeout=timeout, + verify=config["verify_ssl"] ) - if operation == "patch": - response = patch( - uri, - timeout=timeout, - headers=headers, - params=params, - data=data, - verify=config["verify_ssl"], + elif operation == "patch": + response = _make_request( + "PATCH", + uri, + headers=headers, + params=params, + data=data, + timeout=timeout, + verify=config["verify_ssl"] ) - if operation == "delete": - response = patch, delete( - uri, - timeout=timeout, - headers=headers, - params=params, - data=data, - verify=config["verify_ssl"], + elif operation == "delete": + response = _make_request( + "DELETE", + uri, + headers=headers, + params=params, + data=data, + timeout=timeout, + verify=config["verify_ssl"] ) except Exception as e: message = "Failed to connect to the API: {}".format(e) diff --git a/client-cli/pvc/lib/lazy_imports.py b/client-cli/pvc/lib/lazy_imports.py new file mode 100644 index 00000000..73b45e73 --- /dev/null +++ b/client-cli/pvc/lib/lazy_imports.py @@ -0,0 +1,17 @@ +""" +Lazy import mechanism for PVC CLI to reduce startup time +""" + +class LazyModule: + """ + A proxy for a module that is loaded only when actually used + """ + def __init__(self, name): + self.name = name + self._module = None + + def __getattr__(self, attr): + if self._module is None: + import importlib + self._module = importlib.import_module(self.name) + return getattr(self._module, attr) \ No newline at end of file