From ab0ab60fa5a6b5bcbabb223177e572867377bcdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Dupr=C3=A9?= Date: Mon, 9 Mar 2026 14:14:47 +0100 Subject: [PATCH 1/2] docs: add the Sphinx documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add files to generate API reference and CLI documentation using Sphinx. Update .cqfdrc to add a new flavor for docs generation and the corresponding command. Update the Dockerfile to include Sphinx and its dependencies for building the documentation. Signed-off-by: Mathieu Dupré --- .cqfd/docker/Dockerfile | 5 ++- .cqfdrc | 5 ++- .github/workflows/ci.yml | 6 ++++ .gitignore | 3 ++ CLAUDE.md | 16 ++++++++++ docs/api.rst | 31 ++++++++++++++++++ docs/cli.rst | 23 ++++++++++++++ docs/conf.py | 28 +++++++++++++++++ docs/index.rst | 16 ++++++++++ docs/overview.rst | 52 +++++++++++++++++++++++++++++++ pyproject.toml | 1 + vm_manager/helpers/libvirt_cmd.py | 8 ++++- vm_manager/vm_manager_cmd.py | 8 ++++- 13 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 docs/api.rst create mode 100644 docs/cli.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/overview.rst diff --git a/.cqfd/docker/Dockerfile b/.cqfd/docker/Dockerfile index e38d7ad..b81761b 100644 --- a/.cqfd/docker/Dockerfile +++ b/.cqfd/docker/Dockerfile @@ -9,10 +9,13 @@ RUN set -x \ python3 \ python3-flake8 \ python3-setuptools \ + python3-sphinx \ + python3-pip \ openjdk-8-jre-headless \ unzip \ wget \ - && rm -rf /var/lib/apt/lists/ + && rm -rf /var/lib/apt/lists/ \ + && pip3 install --no-cache-dir sphinx-argparse ARG sonar_version=4.7.0.2747 ARG sonar_repo=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli diff --git a/.cqfdrc b/.cqfdrc index 0f25533..1108732 100644 --- a/.cqfdrc +++ b/.cqfdrc @@ -2,7 +2,7 @@ org='rte' name='vm_manager' -flavors='check sonar check_format format flake' +flavors='check sonar check_format format flake docs' [build] command='/usr/bin/pip install --root-user-action=ignore --prefix=. .' @@ -27,3 +27,6 @@ command='black -l 79 -t py38 .' [flake] command='python3 -m flake8 --ignore=E501,W503' + +[docs] +command='sphinx-build -b html docs docs/_build/html' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b91e13d..d6d84e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,3 +55,9 @@ jobs: - name: Run tests run: sg libvirt -c "pytest tests/ -v --tb=short" + + - name: Install documentation dependencies + run: pip install ".[docs]" + + - name: Build documentation + run: sphinx-build -b html docs/ docs/_build/html diff --git a/.gitignore b/.gitignore index aa62ca8..ea93797 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ __pycache__/ # Ignore IDE files /.idea/ +# Ignore generated documentation +/docs/_build/ + # Ignore sonar files /.scannerwork/ /.sonar/ diff --git a/CLAUDE.md b/CLAUDE.md index 4a3820a..a1a4b5d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,6 +40,22 @@ cqfd -b flake # flake8 cqfd -b check # pylint ``` +## Documentation + +```bash +# Generate HTML docs locally (output: docs/_build/html/) +pip install .[docs] +sphinx-build -b html docs docs/_build/html + +# Via cqfd +cqfd init +cqfd -b docs +``` + +Docs structure: `docs/overview.rst` (project overview), `docs/cli.rst` +(CLI reference via sphinx-argparse), `docs/api.rst` (Python API via autodoc). +sphinx-argparse requires `get_parser()` functions in both CLI modules. + ## Tests Tests are integration scripts requiring a real Ceph/Pacemaker cluster. Run individually: diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..bcb7485 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,31 @@ +Python API Reference +==================== + +Standalone mode +--------------- + +.. automodule:: vm_manager.vm_manager_libvirt + :members: + :undoc-members: + +Cluster mode +------------ + +.. automodule:: vm_manager.vm_manager_cluster + :members: + :undoc-members: + +Helpers +------- + +.. automodule:: vm_manager.helpers.libvirt + :members: + :undoc-members: + +.. automodule:: vm_manager.helpers.pacemaker + :members: + :undoc-members: + +.. automodule:: vm_manager.helpers.rbd_manager + :members: + :undoc-members: diff --git a/docs/cli.rst b/docs/cli.rst new file mode 100644 index 0000000..a4a897c --- /dev/null +++ b/docs/cli.rst @@ -0,0 +1,23 @@ +CLI Reference +============= + +vm_manager_cmd +-------------- + +Main CLI tool for VM management. Available subcommands depend on the +operating mode (standalone or cluster) detected at runtime. + +.. argparse:: + :module: vm_manager.vm_manager_cmd + :func: get_parser + :prog: vm_manager_cmd + +libvirt_cmd +----------- + +Lower-level CLI for direct libvirt operations. + +.. argparse:: + :module: vm_manager.helpers.libvirt_cmd + :func: get_parser + :prog: libvirt_cmd diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..6839e6d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,28 @@ +# Copyright (C) 2026 Savoir-faire Linux Inc. +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) + +project = "vm_manager" +copyright = "2026, Savoir-faire Linux Inc, RTE (http://www.rte-france.com) and contributors" +author = "Mathieu Dupré" + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinxarg.ext", +] + +# Mock imports for optional dependencies unavailable at doc build time +autodoc_mock_imports = [ + "libvirt", + "rados", + "rbd", + "flask", + "flask_wtf", +] + +html_theme = "alabaster" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..67e38b6 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,16 @@ +vm_manager documentation +======================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + overview + cli + api + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` diff --git a/docs/overview.rst b/docs/overview.rst new file mode 100644 index 0000000..483c130 --- /dev/null +++ b/docs/overview.rst @@ -0,0 +1,52 @@ +Overview +======== + +**vm_manager** is a Python tool for managing Virtual Machines on the +`SEAPATH `_ platform. + +Operating modes +--------------- + +The mode is auto-detected at import time based on available dependencies: + +- **Standalone mode** (``vm_manager_libvirt.py``): manages VMs via KVM/libvirt + only. Used when Pacemaker and Ceph RBD dependencies are not present. + +- **Cluster mode** (``vm_manager_cluster.py``): manages VMs on a Pacemaker + HA cluster with Ceph RBD storage. Activated when both ``rados``/``rbd`` + and ``crm`` (Pacemaker) are available. + +Entry points +------------ + +- ``vm_manager_cmd`` — main CLI exposing all VM operations as subcommands +- ``libvirt_cmd`` — lower-level CLI for direct libvirt operations +- ``vm_manager_api`` — Flask REST API (``/``, ``/status/``, + ``/stop/``, ``/start/``) + +Architecture +------------ + +Helper classes (used as context managers): + +- :class:`~vm_manager.helpers.libvirt.LibVirtManager` — wraps + ``libvirt-python`` for domain management +- :class:`~vm_manager.helpers.pacemaker.Pacemaker` — wraps the ``crm`` CLI + via ``subprocess`` +- :class:`~vm_manager.helpers.rbd_manager.RbdManager` — wraps Ceph + ``rados``/``rbd`` Python bindings + +Installation +------------ + +.. code-block:: bash + + pip install . + + # or with documentation dependencies + pip install .[docs] + +License +------- + +Apache-2.0 diff --git a/pyproject.toml b/pyproject.toml index 4d2f303..ce74757 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ readme = "README.md" [project.optional-dependencies] test = ["pytest>=7.0"] +docs = ["sphinx>=4.0", "sphinx-argparse"] [tool.setuptools] packages = ["vm_manager", "vm_manager.helpers", "vm_manager.helpers.tests.pacemaker", "vm_manager.helpers.tests.rbd_manager"] diff --git a/vm_manager/helpers/libvirt_cmd.py b/vm_manager/helpers/libvirt_cmd.py index 7988baf..a067e11 100755 --- a/vm_manager/helpers/libvirt_cmd.py +++ b/vm_manager/helpers/libvirt_cmd.py @@ -10,7 +10,8 @@ from vm_manager.helpers.libvirt import LibVirtManager -def main(): +def get_parser(): + """Return the argument parser for libvirt_cmd.""" parser = argparse.ArgumentParser(description="libvirt helper cli wrapper") subparsers = parser.add_subparsers( help="command", dest="command", required=True, metavar="command" @@ -32,6 +33,11 @@ def main(): help="full path where the configuration is exported", ) define_parser.add_argument("xml", type=str, help="The XML file path") + return parser + + +def main(): + parser = get_parser() args = parser.parse_args() if args.command == "list": with LibVirtManager() as libvirt_manager: diff --git a/vm_manager/vm_manager_cmd.py b/vm_manager/vm_manager_cmd.py index 18884de..37e83f1 100755 --- a/vm_manager/vm_manager_cmd.py +++ b/vm_manager/vm_manager_cmd.py @@ -30,7 +30,8 @@ def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, d) -def main(): +def get_parser(): + """Return the argument parser for vm_manager_cmd.""" parser = argparse.ArgumentParser(description="vm_manager cli wrapper") parser.add_argument( "-v", @@ -501,6 +502,11 @@ def main(): # if cluster_mode end + return parser + + +def main(): + parser = get_parser() args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) From ab81c2f6d77194c54c3c1d09a3f1ef004521b93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Dupr=C3=A9?= Date: Tue, 10 Mar 2026 17:19:18 +0100 Subject: [PATCH 2/2] docs: reformat docstrings in vm_manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mathieu Dupré --- vm_manager/helpers/libvirt.py | 17 ++++++++-- vm_manager/helpers/pacemaker.py | 11 +++++-- vm_manager/vm_manager_cluster.py | 53 ++++++++++++++++++++++++-------- vm_manager/vm_manager_libvirt.py | 12 ++++++-- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/vm_manager/helpers/libvirt.py b/vm_manager/helpers/libvirt.py index 5fbd3a9..99f416e 100644 --- a/vm_manager/helpers/libvirt.py +++ b/vm_manager/helpers/libvirt.py @@ -47,13 +47,15 @@ def close(self): def list(self): """ List all VM - :return the name list of all defined libvirt domain + + :return: the name list of all defined libvirt domain """ return [x.name() for x in self._conn.listAllDomains()] def get_virsh_secrets(self): """ Get the virsh secrets + :return: a dictionary of virsh secrets """ secrets = {} @@ -66,6 +68,7 @@ def define(self, xml): Validate and create a VM from xml configuration Raise an error if the XML is not valid. + :param xml: the libvirt XML string """ try: @@ -77,6 +80,7 @@ def define(self, xml): def undefine(self, vm_name): """ Remove a VM + :param vm_name: the VM to undefined """ domain = self._conn.lookupByName(vm_name) @@ -85,6 +89,7 @@ def undefine(self, vm_name): def set_autostart(self, vm_name, enabled): """ Set the autostart flag on a VM + :param vm_name: the VM name :param enabled: True to enable autostart, False to disable """ @@ -93,6 +98,7 @@ def set_autostart(self, vm_name, enabled): def start(self, vm_name): """ Start a VM + :param vm_name: the VM to start """ self._conn.lookupByName(vm_name).create() @@ -100,6 +106,7 @@ def start(self, vm_name): def stop(self, vm_name): """ Stop a VM + :param vm_name: the VM to be stopped """ self._conn.lookupByName(vm_name).shutdown() @@ -107,6 +114,7 @@ def stop(self, vm_name): def force_stop(self, vm_name): """ Forces a VM to stop + :param vm_name: the VM to be stopped """ self._conn.lookupByName(vm_name).destroy() @@ -114,9 +122,10 @@ def force_stop(self, vm_name): def status(self, vm_name): """ Get the VM status + :param vm_name: the VM for which the status must be checked - :return: the status of the VM, among Starting, Started, Paused, - Stopped, Stopping, Undefined and FAILED + :return: the status of the VM, among Starting, Started, Paused, + Stopped, Stopping, Undefined and FAILED """ if vm_name not in self.list(): logger.info(vm_name + "does not exist") @@ -145,6 +154,7 @@ def status(self, vm_name): def console(self, vm_name): """ Open a console on a VM + :param vm_name: the VM to open the console """ uri = self._conn.getURI() @@ -165,6 +175,7 @@ def console(self, vm_name): def export_configuration(domain, xml_path): """ Dump the libvirt XML configuration + :param domain: the domain whose the configuration is exported :param xml_path: the path where the XML configuration will be exported """ diff --git a/vm_manager/helpers/pacemaker.py b/vm_manager/helpers/pacemaker.py index fc6b0db..87e92f4 100644 --- a/vm_manager/helpers/pacemaker.py +++ b/vm_manager/helpers/pacemaker.py @@ -289,6 +289,7 @@ def manage(self): def disable_location(self, node): """ Define on which nodes a resource must never be run. + Note: It will be used to restrict the VM on the hypervisors. """ args = [ @@ -342,8 +343,9 @@ def add_colocation(self, *resources, strong=False): def default_location(self, node): """ - Set the VM default location. The VM will be deployed on the given node - unless the node is up. + Set the VM default location. + + The VM will be deployed on the given node unless the node is up. """ args = [ "crm", @@ -358,6 +360,7 @@ def default_location(self, node): def wait_for(self, state, periods=0.2, nb_periods=100): """ Wait for a VM enter the given state. + Check every period in s. """ ticker = threading.Event() @@ -386,6 +389,7 @@ def run_crm_cmd(self, cmd): def add_meta(self, key, value): """ Add a meta to the resource + :param meta: the meta to add """ args = ["crm", "resource", "meta", self._resource, "set", key, value] @@ -395,6 +399,7 @@ def add_meta(self, key, value): def remove_meta(self, key): """ Remove a meta from the resource + :param meta: the meta to remove """ args = [ @@ -412,6 +417,7 @@ def remove_meta(self, key): def is_valid_host(host): """ Check if a host is found in the cluster. + :param host: the host to test :return: True if the host is in the cluster, false otherwise """ @@ -424,6 +430,7 @@ def is_valid_host(host): def find_resource(resource): """ Find where a resource is running. + :param resource: the resource to find :return: the node where the resource is running or None if the resource is not running or not found diff --git a/vm_manager/vm_manager_cluster.py b/vm_manager/vm_manager_cluster.py index fd31d3f..17e1477 100644 --- a/vm_manager/vm_manager_cluster.py +++ b/vm_manager/vm_manager_cluster.py @@ -102,9 +102,12 @@ def _create_xml(xml, vm_name, target_disk_bus="virtio"): Creates a libvirt configuration file according to xml and disk_name parameters. - target_disk_bus: bus type of the VM system disk inside the VM. - Should be a valid type recognized by libvirt, see https://libvirt.org/formatdomain.html#devices. - Default: virtio + :param xml: the base libvirt XML string to be used as template for the VM + configuration + :param vm_name: the VM name to be set in the libvirt XML configuration + :param: target_disk_bus: bus type of the VM system disk inside the VM. + Should be a valid type recognized by libvirt, see https://libvirt.org/formatdomain.html#devices. + Default: virtio """ disk_name = OS_DISK_PREFIX + vm_name xml_root = ElementTree.fromstring(xml) @@ -279,6 +282,7 @@ def _get_remote_nodes(): def list_vms(enabled=False): """ Return a list of the VMs. + :param enabled: if True only list enabled VMs, otherwise list all of them :return: the VM list """ @@ -292,6 +296,7 @@ def list_vms(enabled=False): def create(vm_options_with_nones): """ Create a new VM + The VM will never switch to another host """ # Validate parameters and required files @@ -375,14 +380,17 @@ def create(vm_options_with_nones): def add_to_cluster(vm_options_with_nones): """ Add an existing libvirt VM to the cluster. + Retrieves the VM XML from libvirt, strips its disk devices, and calls create() to register it in Ceph/Pacemaker. - :param vm_options_with_nones: dict with keys: - - name: existing libvirt VM name (required) - - image: path to the disk image to import into Ceph (optional, + + :param vm_options_with_nones: dict with the following keys: + + - **name**: existing libvirt VM name (required) + - **image**: path to the disk image to import into Ceph (optional, defaults to the disk path from the libvirt VM definition) - - new_name: optional new VM name (if omitted, keeps original name) - - plus all optional create() args (disable, force, metadata, ...) + - **new_name**: optional new VM name (if omitted, keeps original name) + - plus all optional ``create()`` args (disable, force, metadata, ...) """ vm_options = { k: v for k, v in vm_options_with_nones.items() if v is not None @@ -440,6 +448,7 @@ def add_to_cluster(vm_options_with_nones): def remove(vm_name): """ Remove a VM from cluster + :param vm_name: the VM name to be removed """ @@ -473,6 +482,7 @@ def remove(vm_name): def enable_vm(vm_name, nostart=False): """ Enable a VM in Pacemaker + :param vm_name: the VM name to be enabled """ @@ -664,6 +674,7 @@ def enable_vm(vm_name, nostart=False): def disable_vm(vm_name): """ Stop and disable a VM in Pacemaker without removing it + :param vm_name: the VM name to be disabled """ with Pacemaker(vm_name) as p: @@ -698,6 +709,7 @@ def start(vm_name): """ Start or resume a stopped or paused VM The VM must enabled before being started + :param vm_name: the VM to be started """ @@ -719,6 +731,7 @@ def start(vm_name): def is_enabled(vm_name): """ Ask if the VM is enabled in Pacemaker + :param vm_name: the vm_name to be checked :return: True if the VM is enabled, False otherwise """ @@ -728,6 +741,7 @@ def is_enabled(vm_name): def status(vm_name): """ Get the VM status + :param vm_name: the VM for which the status must be checked :return: the status of the VM, among Starting, Started, Paused, Stopped, Stopping, Disabled, Undefined and FAILED @@ -746,6 +760,7 @@ def status(vm_name): def stop(vm_name, force=False): """ Stop a VM + :param vm_name: the VM to be stopped """ with Pacemaker(vm_name) as p: @@ -948,6 +963,7 @@ def create_snapshot(vm_name, snapshot_name): """ Create a snapshot. The snapshot can be a system disk snapshot only or a VM snapshot (os disk and data disk). + :param vm_name: the VM to be snapshot :param snapshot_name: the snapshot name """ @@ -977,6 +993,7 @@ def create_snapshot(vm_name, snapshot_name): def remove_snapshot(vm_name, snapshot_name): """ Remove a snapshot + :param vm_name: the VM from which the snapshot must be removed :param snapshot_name: the name of the snapshot to be removed """ @@ -995,6 +1012,7 @@ def remove_snapshot(vm_name, snapshot_name): def list_snapshots(vm_name): """ Get the snapshot list of a VM. + :param vm_name: the VM name from which to list the snapshots :return: the snapshot list """ @@ -1006,6 +1024,7 @@ def list_snapshots(vm_name): def purge_image(vm_name, date=None, number=None): """ Remove all snapshots of the given type on the given VM. + :param vm_name: the VM name to be purged :param date: date until snapshots must be removed :param number: number of snapshots to delete starting from the oldest @@ -1074,6 +1093,7 @@ def purge_image(vm_name, date=None, number=None): def rollback_snapshot(vm_name, snapshot_name): """ Restore a VM to a previous state based on the given snapshot. + :param vm_name: the VM name to be restored :param snapshot_name: the snapshot name to be used for rollback """ @@ -1108,6 +1128,7 @@ def rollback_snapshot(vm_name, snapshot_name): def list_metadata(vm_name): """ List all metadata associated to the given VM + :param vm_name: the VM name from which the metadata will be listed :return: the metadata list """ @@ -1119,6 +1140,7 @@ def list_metadata(vm_name): def get_metadata(vm_name, metadata_name): """ Get a metadata value + :param vm_name: the VM name where the metadata is stored :param metadata_name: the metadata name to get :return: the metadata value (a str) @@ -1132,6 +1154,7 @@ def set_metadata(vm_name, metadata_name, metadata_value): """ Set a metadata with the given value. Create it if the metadata does not exist yet + :param vm_name: the VM name where the metadata will be stored :param metadata_name: the metadata name to be set :param metadata_value: the metadata value to set @@ -1156,13 +1179,16 @@ def set_metadata(vm_name, metadata_name, metadata_value): def add_colocation(vm_name, *resources, strong=False): """ Add a colocation constraint to a VM. + :param vm_name: the VM name to constraint :param resources: VMs or other Pacemaker resources to be colocated with the - VM. The resource must already be created and if the resource is a VM, then - it must be enabled. Disabling a VM will remove its constraints. + VM. The resource must already be created and if the + resource is a VM, then it must be enabled. Disabling a VM + will remove its constraints. :param strong: If strong is set to True, add a strong colocation. In a - strong colocation the VM will be started only if all resources colocated - with it are started too and the VM will stop if one of them is stopped. + strong colocation the VM will be started only if all + resources colocated with it are started too and the VM will + stop if one of them is stopped. """ _check_name(vm_name) with Pacemaker(vm_name) as p: @@ -1172,6 +1198,7 @@ def add_colocation(vm_name, *resources, strong=False): def remove_pacemaker_remote(vm_name): """ Remove the pacemaker remote configuration from the VM. + :param vm_name: the VM name to remove the pacemaker remote configuration """ with RbdManager(CEPH_CONF, POOL_NAME, NAMESPACE) as rbd: @@ -1199,6 +1226,7 @@ def add_pacemaker_remote( ): """ Add a pacemaker-remote configuration to the VM. + :param vm_name: the VM name to add the pacemaker remote configuration :param remote_node: name to identify the pacemaker-remote resource :param remote_node_address: the address of the pacemaker-remote resource @@ -1233,6 +1261,7 @@ def add_pacemaker_remote( def console(vm_name, ssh_user="libvirtadmin"): """ Open a virsh console for the given VM + :param vm_name: the VM name to open the console """ # First we need to get the hypervisor where the VM is running diff --git a/vm_manager/vm_manager_libvirt.py b/vm_manager/vm_manager_libvirt.py index f720fdd..8cb2f8d 100644 --- a/vm_manager/vm_manager_libvirt.py +++ b/vm_manager/vm_manager_libvirt.py @@ -15,6 +15,7 @@ def list_vms(): """ Return a list of the VMs. + :return: the VM list """ with LibVirtManager() as lvm: @@ -43,6 +44,7 @@ def _create_xml(xml, vm_name): def create(args): """ Create a new VM + :param vm_name: the VM name :param base_xml: the VM libvirt xml configuration """ @@ -59,6 +61,7 @@ def create(args): def remove(vm_name): """ Remove a VM + :param vm_name: the VM name to be removed """ with LibVirtManager() as lvm: @@ -75,6 +78,7 @@ def start(vm_name): """ Start or resume a stopped or paused VM The VM must enabled before being started + :param vm_name: the VM to be started :param autostart: if True, enable autostart on the VM """ @@ -87,6 +91,7 @@ def start(vm_name): def autostart(vm_name, enabled): """ Set the autostart flag on a VM + :param vm_name: the VM name :param enabled: True to enable autostart, False to disable """ @@ -100,6 +105,7 @@ def autostart(vm_name, enabled): def stop(vm_name, force=False): """ Stop a VM + :param vm_name: the VM to be stopped :param force: Set to True to force stop (virtually unplug the VM) """ @@ -115,9 +121,10 @@ def stop(vm_name, force=False): def status(vm_name): """ Get the VM status + :param vm_name: the VM for which the status must be checked - :return: the status of the VM, among Starting, Started, Paused, - Stopped, Stopping, Undefined and FAILED + :return: the status of the VM, among Starting, Started, Paused, Stopped, + Stopping, Undefined and FAILED """ with LibVirtManager() as lvm: return lvm.status(vm_name) @@ -126,6 +133,7 @@ def status(vm_name): def console(vm_name): """ Open a virsh console for the given VM + :param vm_name: the VM name to open the console """ with LibVirtManager() as lvm: