65598582f5
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=179
1189 lines
44 KiB
Diff
1189 lines
44 KiB
Diff
From acee2074e9fe4da2731e61a554639e773c04e43a Mon Sep 17 00:00:00 2001
|
|
From: Cedric Bosdonnat <cbosdonnat@suse.com>
|
|
Date: Mon, 5 Oct 2020 16:49:59 +0200
|
|
Subject: [PATCH] Backport a few virt PRs (#272)
|
|
|
|
* Fix virt update when cpu and memory are changed
|
|
|
|
If CPU is changed, the memory change would be short circuited. This is a
|
|
regression introduced by PR #58332
|
|
|
|
* virt: add VM memory tunning support
|
|
|
|
* avoid comparing string with integer
|
|
|
|
* fix pre-commit failure
|
|
|
|
* Properly fix memory setting regression in virt.update
|
|
|
|
The 'mem' property in the virt.update value should indicate the result
|
|
of a live memory setting. The value should be an int in KiB. Fixing the
|
|
code and tests for this.
|
|
|
|
* virt: add stop_on_reboot parameter in guest states and definition
|
|
|
|
It can be needed to force a VM to stop instead of rebooting. A typical
|
|
example of this is when creating a VM using a install CDROM ISO or when
|
|
using an autoinstallation profile. Forcing a shutdown allows libvirt to
|
|
pick up another XML definition for the new start to remove the
|
|
firstboot-only options.
|
|
|
|
* virt: expose live parameter in virt.defined state
|
|
|
|
Allow updating the definition of a VM without touching the live
|
|
instance. This can be helpful since live update may change the device
|
|
names in the guest.
|
|
|
|
Co-authored-by: firefly <guoqing_li@pm.me>
|
|
Co-authored-by: gqlo <escita@pm.me>
|
|
---
|
|
changelog/57639.added | 1 +
|
|
changelog/58589.added | 1 +
|
|
salt/modules/virt.py | 284 ++++++++++++++++++--
|
|
salt/states/virt.py | 71 ++++-
|
|
salt/templates/virt/libvirt_domain.jinja | 30 ++-
|
|
salt/utils/xmlutil.py | 2 +-
|
|
tests/unit/modules/test_virt.py | 318 ++++++++++++++++++++++-
|
|
tests/unit/states/test_virt.py | 14 +-
|
|
8 files changed, 687 insertions(+), 34 deletions(-)
|
|
create mode 100644 changelog/57639.added
|
|
create mode 100644 changelog/58589.added
|
|
|
|
diff --git a/changelog/57639.added b/changelog/57639.added
|
|
new file mode 100644
|
|
index 0000000000..c0281e9319
|
|
--- /dev/null
|
|
+++ b/changelog/57639.added
|
|
@@ -0,0 +1 @@
|
|
+Memory Tuning Support which allows much greater control of memory allocation
|
|
diff --git a/changelog/58589.added b/changelog/58589.added
|
|
new file mode 100644
|
|
index 0000000000..5960555ec6
|
|
--- /dev/null
|
|
+++ b/changelog/58589.added
|
|
@@ -0,0 +1 @@
|
|
+Allow handling special first boot definition on virtual machine
|
|
diff --git a/salt/modules/virt.py b/salt/modules/virt.py
|
|
index e306bc0679..8e2180608a 100644
|
|
--- a/salt/modules/virt.py
|
|
+++ b/salt/modules/virt.py
|
|
@@ -71,6 +71,50 @@ The calls not using the libvirt connection setup are:
|
|
- `libvirt URI format <http://libvirt.org/uri.html#URI_config>`_
|
|
- `libvirt authentication configuration <http://libvirt.org/auth.html#Auth_client_config>`_
|
|
|
|
+Units
|
|
+==========
|
|
+.. _virt-units:
|
|
+.. rubric:: Units specification
|
|
+.. versionadded:: Magnesium
|
|
+
|
|
+The string should contain a number optionally followed
|
|
+by a unit. The number may have a decimal fraction. If
|
|
+the unit is not given then MiB are set by default.
|
|
+Units can optionally be given in IEC style (such as MiB),
|
|
+although the standard single letter style (such as M) is
|
|
+more convenient.
|
|
+
|
|
+Valid units include:
|
|
+
|
|
+========== ===== ========== ========== ======
|
|
+Standard IEC Standard IEC
|
|
+ Unit Unit Name Name Factor
|
|
+========== ===== ========== ========== ======
|
|
+ B Bytes 1
|
|
+ K KiB Kilobytes Kibibytes 2**10
|
|
+ M MiB Megabytes Mebibytes 2**20
|
|
+ G GiB Gigabytes Gibibytes 2**30
|
|
+ T TiB Terabytes Tebibytes 2**40
|
|
+ P PiB Petabytes Pebibytes 2**50
|
|
+ E EiB Exabytes Exbibytes 2**60
|
|
+ Z ZiB Zettabytes Zebibytes 2**70
|
|
+ Y YiB Yottabytes Yobibytes 2**80
|
|
+========== ===== ========== ========== ======
|
|
+
|
|
+Additional decimal based units:
|
|
+
|
|
+====== =======
|
|
+Unit Factor
|
|
+====== =======
|
|
+KB 10**3
|
|
+MB 10**6
|
|
+GB 10**9
|
|
+TB 10**12
|
|
+PB 10**15
|
|
+EB 10**18
|
|
+ZB 10**21
|
|
+YB 10**24
|
|
+====== =======
|
|
"""
|
|
# Special Thanks to Michael Dehann, many of the concepts, and a few structures
|
|
# of his in the virt func module have been used
|
|
@@ -719,6 +763,39 @@ def _disk_from_pool(conn, pool, pool_xml, volume_name):
|
|
return disk_context
|
|
|
|
|
|
+def _handle_unit(s, def_unit="m"):
|
|
+ """
|
|
+ Handle the unit conversion, return the value in bytes
|
|
+ """
|
|
+ m = re.match(r"(?P<value>[0-9.]*)\s*(?P<unit>.*)$", str(s).strip())
|
|
+ value = m.group("value")
|
|
+ # default unit
|
|
+ unit = m.group("unit").lower() or def_unit
|
|
+ try:
|
|
+ value = int(value)
|
|
+ except ValueError:
|
|
+ try:
|
|
+ value = float(value)
|
|
+ except ValueError:
|
|
+ raise SaltInvocationError("invalid number")
|
|
+ # flag for base ten
|
|
+ dec = False
|
|
+ if re.match(r"[kmgtpezy]b$", unit):
|
|
+ dec = True
|
|
+ elif not re.match(r"(b|[kmgtpezy](ib)?)$", unit):
|
|
+ raise SaltInvocationError("invalid units")
|
|
+ p = "bkmgtpezy".index(unit[0])
|
|
+ value *= 10 ** (p * 3) if dec else 2 ** (p * 10)
|
|
+ return int(value)
|
|
+
|
|
+
|
|
+def nesthash():
|
|
+ """
|
|
+ create default dict that allows arbitrary level of nesting
|
|
+ """
|
|
+ return collections.defaultdict(nesthash)
|
|
+
|
|
+
|
|
def _gen_xml(
|
|
conn,
|
|
name,
|
|
@@ -732,18 +809,32 @@ def _gen_xml(
|
|
graphics=None,
|
|
boot=None,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
**kwargs
|
|
):
|
|
"""
|
|
Generate the XML string to define a libvirt VM
|
|
"""
|
|
- mem = int(mem) * 1024 # MB
|
|
context = {
|
|
"hypervisor": hypervisor,
|
|
"name": name,
|
|
"cpu": str(cpu),
|
|
- "mem": str(mem),
|
|
+ "on_reboot": "destroy" if stop_on_reboot else "restart",
|
|
}
|
|
+
|
|
+ context["mem"] = nesthash()
|
|
+ if isinstance(mem, int):
|
|
+ mem = int(mem) * 1024 # MB
|
|
+ context["mem"]["boot"] = str(mem)
|
|
+ context["mem"]["current"] = str(mem)
|
|
+ elif isinstance(mem, dict):
|
|
+ for tag, val in mem.items():
|
|
+ if val:
|
|
+ if tag == "slots":
|
|
+ context["mem"]["slots"] = "{}='{}'".format(tag, val)
|
|
+ else:
|
|
+ context["mem"][tag] = str(int(_handle_unit(val) / 1024))
|
|
+
|
|
if hypervisor in ["qemu", "kvm"]:
|
|
context["controller_model"] = False
|
|
elif hypervisor == "vmware":
|
|
@@ -863,7 +954,6 @@ def _gen_xml(
|
|
except jinja2.exceptions.TemplateNotFound:
|
|
log.error("Could not load template %s", fn_)
|
|
return ""
|
|
-
|
|
return template.render(**context)
|
|
|
|
|
|
@@ -1662,6 +1752,7 @@ def init(
|
|
arch=None,
|
|
boot=None,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
**kwargs
|
|
):
|
|
"""
|
|
@@ -1669,7 +1760,28 @@ def init(
|
|
|
|
:param name: name of the virtual machine to create
|
|
:param cpu: Number of virtual CPUs to assign to the virtual machine
|
|
- :param mem: Amount of memory to allocate to the virtual machine in MiB.
|
|
+ :param mem: Amount of memory to allocate to the virtual machine in MiB. Since Magnesium, a dictionary can be used to
|
|
+ contain detailed configuration which support memory allocation or tuning. Supported parameters are ``boot``,
|
|
+ ``current``, ``max``, ``slots``, ``hard_limit``, ``soft_limit``, ``swap_hard_limit`` and ``min_guarantee``. The
|
|
+ structure of the dictionary is documented in :ref:`init-mem-def`. Both decimal and binary base are supported.
|
|
+ Detail unit specification is documented in :ref:`virt-units`. Please note that the value for ``slots`` must be
|
|
+ an integer.
|
|
+
|
|
+ .. code-block:: python
|
|
+
|
|
+ {
|
|
+ 'boot': 1g,
|
|
+ 'current': 1g,
|
|
+ 'max': 1g,
|
|
+ 'slots': 10,
|
|
+ 'hard_limit': '1024'
|
|
+ 'soft_limit': '512m'
|
|
+ 'swap_hard_limit': '1g'
|
|
+ 'min_guarantee': '512mib'
|
|
+ }
|
|
+
|
|
+ .. versionchanged:: Magnesium
|
|
+
|
|
:param nic: NIC profile to use (Default: ``'default'``).
|
|
The profile interfaces can be customized / extended with the interfaces parameter.
|
|
If set to ``None``, no profile will be used.
|
|
@@ -1726,6 +1838,15 @@ def init(
|
|
:param password: password to connect with, overriding defaults
|
|
|
|
.. versionadded:: 2019.2.0
|
|
+
|
|
+ :param stop_on_reboot:
|
|
+ If set to ``True`` the guest will stop instead of rebooting.
|
|
+ This is specially useful when creating a virtual machine with an installation cdrom or
|
|
+ an autoinstallation needing a special first boot configuration.
|
|
+ Defaults to ``False``
|
|
+
|
|
+ .. versionadded:: Aluminium
|
|
+
|
|
:param boot:
|
|
Specifies kernel, initial ramdisk and kernel command line parameters for the virtual machine.
|
|
This is an optional parameter, all of the keys are optional within the dictionary. The structure of
|
|
@@ -1782,6 +1903,36 @@ def init(
|
|
|
|
.. versionadded:: sodium
|
|
|
|
+ .. _init-mem-def:
|
|
+
|
|
+ .. rubric:: Memory parameter definition
|
|
+
|
|
+ Memory parameter can contain the following properties:
|
|
+
|
|
+ boot
|
|
+ The maximum allocation of memory for the guest at boot time
|
|
+
|
|
+ current
|
|
+ The actual allocation of memory for the guest
|
|
+
|
|
+ max
|
|
+ The run time maximum memory allocation of the guest
|
|
+
|
|
+ slots
|
|
+ specifies the number of slots available for adding memory to the guest
|
|
+
|
|
+ hard_limit
|
|
+ the maximum memory the guest can use
|
|
+
|
|
+ soft_limit
|
|
+ memory limit to enforce during memory contention
|
|
+
|
|
+ swap_hard_limit
|
|
+ the maximum memory plus swap the guest can use
|
|
+
|
|
+ min_guarantee
|
|
+ the guaranteed minimum memory allocation for the guest
|
|
+
|
|
.. _init-nic-def:
|
|
|
|
.. rubric:: Network Interfaces Definitions
|
|
@@ -2076,6 +2227,7 @@ def init(
|
|
graphics,
|
|
boot,
|
|
boot_dev,
|
|
+ stop_on_reboot,
|
|
**kwargs
|
|
)
|
|
log.debug("New virtual machine definition: %s", vm_xml)
|
|
@@ -2305,6 +2457,7 @@ def update(
|
|
boot=None,
|
|
test=False,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
**kwargs
|
|
):
|
|
"""
|
|
@@ -2312,7 +2465,7 @@ def update(
|
|
|
|
:param name: Name of the domain to update
|
|
:param cpu: Number of virtual CPUs to assign to the virtual machine
|
|
- :param mem: Amount of memory to allocate to the virtual machine in MiB. Since 3002, a dictionary can be used to
|
|
+ :param mem: Amount of memory to allocate to the virtual machine in MiB. Since Magnesium, a dictionary can be used to
|
|
contain detailed configuration which support memory allocation or tuning. Supported parameters are ``boot``,
|
|
``current``, ``max``, ``slots``, ``hard_limit``, ``soft_limit``, ``swap_hard_limit`` and ``min_guarantee``. The
|
|
structure of the dictionary is documented in :ref:`init-mem-def`. Both decimal and binary base are supported.
|
|
@@ -2328,7 +2481,7 @@ def update(
|
|
hard_limit: null
|
|
soft_limit: null
|
|
|
|
- .. versionchanged:: 3002
|
|
+ .. versionchanged:: Magnesium
|
|
|
|
:param disk_profile: disk profile to use
|
|
:param disks:
|
|
@@ -2386,6 +2539,14 @@ def update(
|
|
|
|
.. versionadded:: Magnesium
|
|
|
|
+ :param stop_on_reboot:
|
|
+ If set to ``True`` the guest will stop instead of rebooting.
|
|
+ This is specially useful when creating a virtual machine with an installation cdrom or
|
|
+ an autoinstallation needing a special first boot configuration.
|
|
+ Defaults to ``False``
|
|
+
|
|
+ .. versionadded:: Aluminium
|
|
+
|
|
:param test: run in dry-run mode if set to True
|
|
|
|
.. versionadded:: sodium
|
|
@@ -2449,6 +2610,8 @@ def update(
|
|
desc.find(".//os/type").get("arch"),
|
|
graphics,
|
|
boot,
|
|
+ boot_dev,
|
|
+ stop_on_reboot,
|
|
**kwargs
|
|
)
|
|
)
|
|
@@ -2469,12 +2632,26 @@ def update(
|
|
def _set_nvram(node, value):
|
|
node.set("template", value)
|
|
|
|
- def _set_with_mib_unit(node, value):
|
|
+ def _set_with_byte_unit(node, value):
|
|
node.text = str(value)
|
|
- node.set("unit", "MiB")
|
|
+ node.set("unit", "bytes")
|
|
+
|
|
+ def _get_with_unit(node):
|
|
+ unit = node.get("unit", "KiB")
|
|
+ # _handle_unit treats bytes as invalid unit for the purpose of consistency
|
|
+ unit = unit if unit != "bytes" else "b"
|
|
+ value = node.get("memory") or node.text
|
|
+ return _handle_unit("{}{}".format(value, unit)) if value else None
|
|
+
|
|
+ old_mem = int(_get_with_unit(desc.find("memory")) / 1024)
|
|
|
|
# Update the kernel boot parameters
|
|
params_mapping = [
|
|
+ {
|
|
+ "path": "stop_on_reboot",
|
|
+ "xpath": "on_reboot",
|
|
+ "convert": lambda v: "destroy" if v else "restart",
|
|
+ },
|
|
{"path": "boot:kernel", "xpath": "os/kernel"},
|
|
{"path": "boot:initrd", "xpath": "os/initrd"},
|
|
{"path": "boot:cmdline", "xpath": "os/cmdline"},
|
|
@@ -2484,14 +2661,72 @@ def update(
|
|
{
|
|
"path": "mem",
|
|
"xpath": "memory",
|
|
- "get": lambda n: int(n.text) / 1024,
|
|
- "set": _set_with_mib_unit,
|
|
+ "convert": _handle_unit,
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
},
|
|
{
|
|
"path": "mem",
|
|
"xpath": "currentMemory",
|
|
- "get": lambda n: int(n.text) / 1024,
|
|
- "set": _set_with_mib_unit,
|
|
+ "convert": _handle_unit,
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:max",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "maxMemory",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:boot",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "memory",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:current",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "currentMemory",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:slots",
|
|
+ "xpath": "maxMemory",
|
|
+ "get": lambda n: n.get("slots"),
|
|
+ "set": lambda n, v: n.set("slots", str(v)),
|
|
+ "del": salt.utils.xmlutil.del_attribute("slots", ["unit"]),
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:hard_limit",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "memtune/hard_limit",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:soft_limit",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "memtune/soft_limit",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:swap_hard_limit",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "memtune/swap_hard_limit",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
+ },
|
|
+ {
|
|
+ "path": "mem:min_guarantee",
|
|
+ "convert": _handle_unit,
|
|
+ "xpath": "memtune/min_guarantee",
|
|
+ "get": _get_with_unit,
|
|
+ "set": _set_with_byte_unit,
|
|
},
|
|
{
|
|
"path": "boot_dev:{dev}",
|
|
@@ -2577,13 +2812,24 @@ def update(
|
|
}
|
|
)
|
|
if mem:
|
|
- commands.append(
|
|
- {
|
|
- "device": "mem",
|
|
- "cmd": "setMemoryFlags",
|
|
- "args": [mem * 1024, libvirt.VIR_DOMAIN_AFFECT_LIVE],
|
|
- }
|
|
- )
|
|
+ if isinstance(mem, dict):
|
|
+ # setMemoryFlags takes memory amount in KiB
|
|
+ new_mem = (
|
|
+ int(_handle_unit(mem.get("current")) / 1024)
|
|
+ if "current" in mem
|
|
+ else None
|
|
+ )
|
|
+ elif isinstance(mem, int):
|
|
+ new_mem = int(mem * 1024)
|
|
+
|
|
+ if old_mem != new_mem and new_mem is not None:
|
|
+ commands.append(
|
|
+ {
|
|
+ "device": "mem",
|
|
+ "cmd": "setMemoryFlags",
|
|
+ "args": [new_mem, libvirt.VIR_DOMAIN_AFFECT_LIVE],
|
|
+ }
|
|
+ )
|
|
|
|
# Look for removable device source changes
|
|
new_disks = []
|
|
diff --git a/salt/states/virt.py b/salt/states/virt.py
|
|
index df7ebb63e6..20ea1c25f1 100644
|
|
--- a/salt/states/virt.py
|
|
+++ b/salt/states/virt.py
|
|
@@ -289,6 +289,8 @@ def defined(
|
|
boot=None,
|
|
update=True,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
+ live=True,
|
|
):
|
|
"""
|
|
Starts an existing guest, or defines and starts a new VM with specified arguments.
|
|
@@ -297,7 +299,28 @@ def defined(
|
|
|
|
:param name: name of the virtual machine to run
|
|
:param cpu: number of CPUs for the virtual machine to create
|
|
- :param mem: amount of memory in MiB for the new virtual machine
|
|
+ :param mem: Amount of memory to allocate to the virtual machine in MiB. Since Magnesium, a dictionary can be used to
|
|
+ contain detailed configuration which support memory allocation or tuning. Supported parameters are ``boot``,
|
|
+ ``current``, ``max``, ``slots``, ``hard_limit``, ``soft_limit``, ``swap_hard_limit`` and ``min_guarantee``. The
|
|
+ structure of the dictionary is documented in :ref:`init-mem-def`. Both decimal and binary base are supported.
|
|
+ Detail unit specification is documented in :ref:`virt-units`. Please note that the value for ``slots`` must be
|
|
+ an integer.
|
|
+
|
|
+ .. code-block:: python
|
|
+
|
|
+ {
|
|
+ 'boot': 1g,
|
|
+ 'current': 1g,
|
|
+ 'max': 1g,
|
|
+ 'slots': 10,
|
|
+ 'hard_limit': '1024'
|
|
+ 'soft_limit': '512m'
|
|
+ 'swap_hard_limit': '1g'
|
|
+ 'min_guarantee': '512mib'
|
|
+ }
|
|
+
|
|
+ .. versionchanged:: Magnesium
|
|
+
|
|
:param vm_type: force virtual machine type for the new VM. The default value is taken from
|
|
the host capabilities. This could be useful for example to use ``'qemu'`` type instead
|
|
of the ``'kvm'`` one.
|
|
@@ -357,6 +380,20 @@ def defined(
|
|
|
|
.. versionadded:: Magnesium
|
|
|
|
+ :param stop_on_reboot:
|
|
+ If set to ``True`` the guest will stop instead of rebooting.
|
|
+ This is specially useful when creating a virtual machine with an installation cdrom or
|
|
+ an autoinstallation needing a special first boot configuration.
|
|
+ Defaults to ``False``
|
|
+
|
|
+ .. versionadded:: Aluminium
|
|
+
|
|
+ :param live:
|
|
+ If set to ``False`` the changes will not be applied live to the running instance, but will
|
|
+ only apply at the next start. Note that reboot will not take those changes.
|
|
+
|
|
+ .. versionadded:: Aluminium
|
|
+
|
|
.. rubric:: Example States
|
|
|
|
Make sure a virtual machine called ``domain_name`` is defined:
|
|
@@ -414,13 +451,14 @@ def defined(
|
|
nic_profile=nic_profile,
|
|
interfaces=interfaces,
|
|
graphics=graphics,
|
|
- live=True,
|
|
+ live=live,
|
|
connection=connection,
|
|
username=username,
|
|
password=password,
|
|
boot=boot,
|
|
test=__opts__["test"],
|
|
boot_dev=boot_dev,
|
|
+ stop_on_reboot=stop_on_reboot,
|
|
)
|
|
ret["changes"][name] = status
|
|
if not status.get("definition"):
|
|
@@ -456,6 +494,7 @@ def defined(
|
|
boot=boot,
|
|
start=False,
|
|
boot_dev=boot_dev,
|
|
+ stop_on_reboot=stop_on_reboot,
|
|
)
|
|
ret["changes"][name] = {"definition": True}
|
|
ret["comment"] = "Domain {} defined".format(name)
|
|
@@ -489,6 +528,7 @@ def running(
|
|
arch=None,
|
|
boot=None,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
):
|
|
"""
|
|
Starts an existing guest, or defines and starts a new VM with specified arguments.
|
|
@@ -497,7 +537,23 @@ def running(
|
|
|
|
:param name: name of the virtual machine to run
|
|
:param cpu: number of CPUs for the virtual machine to create
|
|
- :param mem: amount of memory in MiB for the new virtual machine
|
|
+ :param mem: Amount of memory to allocate to the virtual machine in MiB. Since Magnesium, a dictionary can be used to
|
|
+ contain detailed configuration which support memory allocation or tuning. Supported parameters are ``boot``,
|
|
+ ``current``, ``max``, ``slots``, ``hard_limit``, ``soft_limit``, ``swap_hard_limit`` and ``min_guarantee``. The
|
|
+ structure of the dictionary is documented in :ref:`init-mem-def`. Both decimal and binary base are supported.
|
|
+ Detail unit specification is documented in :ref:`virt-units`. Please note that the value for ``slots`` must be
|
|
+ an integer.
|
|
+
|
|
+ To remove any parameters, pass a None object, for instance: 'soft_limit': ``None``. Please note that ``None``
|
|
+ is mapped to ``null`` in sls file, pass ``null`` in sls file instead.
|
|
+
|
|
+ .. code-block:: yaml
|
|
+
|
|
+ - mem:
|
|
+ hard_limit: null
|
|
+ soft_limit: null
|
|
+
|
|
+ .. versionchanged:: Magnesium
|
|
:param vm_type: force virtual machine type for the new VM. The default value is taken from
|
|
the host capabilities. This could be useful for example to use ``'qemu'`` type instead
|
|
of the ``'kvm'`` one.
|
|
@@ -608,6 +664,14 @@ def running(
|
|
|
|
.. versionadded:: Magnesium
|
|
|
|
+ :param stop_on_reboot:
|
|
+ If set to ``True`` the guest will stop instead of rebooting.
|
|
+ This is specially useful when creating a virtual machine with an installation cdrom or
|
|
+ an autoinstallation needing a special first boot configuration.
|
|
+ Defaults to ``False``
|
|
+
|
|
+ .. versionadded:: Aluminium
|
|
+
|
|
.. rubric:: Example States
|
|
|
|
Make sure an already-defined virtual machine called ``domain_name`` is running:
|
|
@@ -676,6 +740,7 @@ def running(
|
|
boot=boot,
|
|
update=update,
|
|
boot_dev=boot_dev,
|
|
+ stop_on_reboot=stop_on_reboot,
|
|
connection=connection,
|
|
username=username,
|
|
password=password,
|
|
diff --git a/salt/templates/virt/libvirt_domain.jinja b/salt/templates/virt/libvirt_domain.jinja
|
|
index 18728a75b5..fb4c9f40d0 100644
|
|
--- a/salt/templates/virt/libvirt_domain.jinja
|
|
+++ b/salt/templates/virt/libvirt_domain.jinja
|
|
@@ -2,9 +2,32 @@
|
|
<domain type='{{ hypervisor }}'>
|
|
<name>{{ name }}</name>
|
|
<vcpu>{{ cpu }}</vcpu>
|
|
- <memory unit='KiB'>{{ mem }}</memory>
|
|
- <currentMemory unit='KiB'>{{ mem }}</currentMemory>
|
|
- <os {{boot.os_attrib}}>
|
|
+ {%- if mem.max %}
|
|
+ <maxMemory {{ mem.slots }} unit='KiB'> {{ mem.max }}</maxMemory>
|
|
+ {%- endif %}
|
|
+ {%- if mem.boot %}
|
|
+ <memory unit='KiB'>{{ mem.boot }}</memory>
|
|
+ {%- endif %}
|
|
+ {%- if mem.current %}
|
|
+ <currentMemory unit='KiB'>{{ mem.current }}</currentMemory>
|
|
+ {%- endif %}
|
|
+ {%- if mem %}
|
|
+ <memtune>
|
|
+ {%- if 'hard_limit' in mem and mem.hard_limit %}
|
|
+ <hard_limit unit="KiB">{{ mem.hard_limit }}</hard_limit>
|
|
+ {%- endif %}
|
|
+ {%- if 'soft_limit' in mem and mem.soft_limit %}
|
|
+ <soft_limit unit="KiB">{{ mem.soft_limit }}</soft_limit>
|
|
+ {%- endif %}
|
|
+ {%- if 'swap_hard_limit' in mem and mem.swap_hard_limit %}
|
|
+ <swap_hard_limit unit="KiB">{{ mem.swap_hard_limit }}</swap_hard_limit>
|
|
+ {%- endif %}
|
|
+ {%- if 'min_guarantee' in mem and mem.min_guarantee %}
|
|
+ <min_guarantee unit="KiB">{{ mem.min_guarantee }}</min_guarantee>
|
|
+ {%- endif %}
|
|
+ </memtune>
|
|
+ {%- endif %}
|
|
+ <os {{ boot.os_attrib }}>
|
|
<type arch='{{ arch }}'>{{ os_type }}</type>
|
|
{% if boot %}
|
|
{% if 'kernel' in boot %}
|
|
@@ -27,6 +50,7 @@
|
|
<boot dev='{{ dev }}' />
|
|
{% endfor %}
|
|
</os>
|
|
+ <on_reboot>{{ on_reboot }}</on_reboot>
|
|
<devices>
|
|
{% for disk in disks %}
|
|
<disk type='{{ disk.type }}' device='{{ disk.device }}'>
|
|
diff --git a/salt/utils/xmlutil.py b/salt/utils/xmlutil.py
|
|
index 111ca155d4..d25f5c8da5 100644
|
|
--- a/salt/utils/xmlutil.py
|
|
+++ b/salt/utils/xmlutil.py
|
|
@@ -299,7 +299,7 @@ def change_xml(doc, data, mapping):
|
|
if convert_fn:
|
|
new_value = convert_fn(new_value)
|
|
|
|
- if current_value != new_value:
|
|
+ if str(current_value) != str(new_value):
|
|
set_fn(node, new_value)
|
|
need_update = True
|
|
else:
|
|
diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py
|
|
index e214e406e2..fba821ea53 100644
|
|
--- a/tests/unit/modules/test_virt.py
|
|
+++ b/tests/unit/modules/test_virt.py
|
|
@@ -21,7 +21,6 @@ from salt.ext import six
|
|
|
|
# pylint: disable=import-error
|
|
from salt.ext.six.moves import range # pylint: disable=redefined-builtin
|
|
-from tests.support.helpers import dedent
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.mock import MagicMock, patch
|
|
from tests.support.unit import TestCase
|
|
@@ -1856,6 +1855,25 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
virt.update("my_vm"),
|
|
)
|
|
|
|
+ # mem + cpu case
|
|
+ define_mock.reset_mock()
|
|
+ domain_mock.setMemoryFlags.return_value = 0
|
|
+ domain_mock.setVcpusFlags.return_value = 0
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ "mem": True,
|
|
+ "cpu": True,
|
|
+ },
|
|
+ virt.update("my_vm", mem=2048, cpu=2),
|
|
+ )
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual("2", setxml.find("vcpu").text)
|
|
+ self.assertEqual("2147483648", setxml.find("memory").text)
|
|
+ self.assertEqual(2048 * 1024, domain_mock.setMemoryFlags.call_args[0][0])
|
|
+
|
|
# Same parameters passed than in default virt.defined state case
|
|
self.assertEqual(
|
|
{
|
|
@@ -2001,6 +2019,50 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
with self.assertRaises(SaltInvocationError):
|
|
virt.update("my_vm", boot={"efi": "Not a boolean value"})
|
|
|
|
+ # Update memtune parameter case
|
|
+ memtune = {
|
|
+ "soft_limit": "0.5g",
|
|
+ "hard_limit": "1024",
|
|
+ "swap_hard_limit": "2048m",
|
|
+ "min_guarantee": "1 g",
|
|
+ }
|
|
+
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("my_vm", mem=memtune),
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("soft_limit").text, str(int(0.5 * 1024 ** 3))
|
|
+ )
|
|
+ self.assertEqual(setxml.find("memtune").find("soft_limit").get("unit"), "bytes")
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("hard_limit").text, str(1024 * 1024 ** 2)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("swap_hard_limit").text, str(2048 * 1024 ** 2)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("min_guarantee").text, str(1 * 1024 ** 3)
|
|
+ )
|
|
+
|
|
+ invalid_unit = {"soft_limit": "2HB"}
|
|
+
|
|
+ with self.assertRaises(SaltInvocationError):
|
|
+ virt.update("my_vm", mem=invalid_unit)
|
|
+
|
|
+ invalid_number = {
|
|
+ "soft_limit": "3.4.MB",
|
|
+ }
|
|
+
|
|
+ with self.assertRaises(SaltInvocationError):
|
|
+ virt.update("my_vm", mem=invalid_number)
|
|
+
|
|
# Update memory case
|
|
setmem_mock = MagicMock(return_value=0)
|
|
domain_mock.setMemoryFlags = setmem_mock
|
|
@@ -2015,10 +2077,43 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
virt.update("my_vm", mem=2048),
|
|
)
|
|
setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
- self.assertEqual(setxml.find("memory").text, "2048")
|
|
- self.assertEqual(setxml.find("memory").get("unit"), "MiB")
|
|
+ self.assertEqual(setxml.find("memory").text, str(2048 * 1024 ** 2))
|
|
+ self.assertEqual(setxml.find("memory").get("unit"), "bytes")
|
|
self.assertEqual(setmem_mock.call_args[0][0], 2048 * 1024)
|
|
|
|
+ mem_dict = {"boot": "0.5g", "current": "2g", "max": "1g", "slots": 12}
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "mem": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("my_vm", mem=mem_dict),
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(setxml.find("memory").get("unit"), "bytes")
|
|
+ self.assertEqual(setxml.find("memory").text, str(int(0.5 * 1024 ** 3)))
|
|
+ self.assertEqual(setxml.find("maxMemory").text, str(1 * 1024 ** 3))
|
|
+ self.assertEqual(setxml.find("currentMemory").text, str(2 * 1024 ** 3))
|
|
+
|
|
+ max_slot_reverse = {
|
|
+ "slots": "10",
|
|
+ "max": "3096m",
|
|
+ }
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("my_vm", mem=max_slot_reverse),
|
|
+ )
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(setxml.find("maxMemory").text, str(3096 * 1024 ** 2))
|
|
+ self.assertEqual(setxml.find("maxMemory").attrib.get("slots"), "10")
|
|
+
|
|
# Update disks case
|
|
devattach_mock = MagicMock(return_value=0)
|
|
devdetach_mock = MagicMock(return_value=0)
|
|
@@ -2533,7 +2628,6 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
"""
|
|
Test virt.update() with existing boot parameters.
|
|
"""
|
|
- root_dir = os.path.join(salt.syspaths.ROOT_DIR, "srv", "salt-images")
|
|
xml_boot = """
|
|
<domain type='kvm' id='8'>
|
|
<name>vm_with_boot_param</name>
|
|
@@ -2591,9 +2685,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
</video>
|
|
</devices>
|
|
</domain>
|
|
- """.format(
|
|
- root_dir, os.sep
|
|
- )
|
|
+ """
|
|
domain_mock_boot = self.set_mock_vm("vm_with_boot_param", xml_boot)
|
|
domain_mock_boot.OSType = MagicMock(return_value="hvm")
|
|
define_mock_boot = MagicMock(return_value=True)
|
|
@@ -2694,6 +2786,218 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
self.assertEqual(setxml.find("os").find("loader"), None)
|
|
self.assertEqual(setxml.find("os").find("nvram"), None)
|
|
|
|
+ def test_update_memtune_params(self):
|
|
+ """
|
|
+ Test virt.update() with memory tuning parameters.
|
|
+ """
|
|
+ xml_with_memtune_params = """
|
|
+ <domain type='kvm' id='8'>
|
|
+ <name>vm_with_boot_param</name>
|
|
+ <memory unit='KiB'>1048576</memory>
|
|
+ <currentMemory unit='KiB'>1048576</currentMemory>
|
|
+ <maxMemory slots="12" unit="bytes">1048576</maxMemory>
|
|
+ <vcpu placement='auto'>1</vcpu>
|
|
+ <memtune>
|
|
+ <hard_limit unit="KiB">1048576</hard_limit>
|
|
+ <soft_limit unit="KiB">2097152</soft_limit>
|
|
+ <swap_hard_limit unit="KiB">2621440</swap_hard_limit>
|
|
+ <min_guarantee unit='KiB'>671088</min_guarantee>
|
|
+ </memtune>
|
|
+ <os>
|
|
+ <type arch='x86_64' machine='pc-i440fx-2.6'>hvm</type>
|
|
+ </os>
|
|
+ </domain>
|
|
+ """
|
|
+ domain_mock = self.set_mock_vm("vm_with_memtune_param", xml_with_memtune_params)
|
|
+ domain_mock.OSType = MagicMock(return_value="hvm")
|
|
+ define_mock = MagicMock(return_value=True)
|
|
+ self.mock_conn.defineXML = define_mock
|
|
+
|
|
+ memtune_new_val = {
|
|
+ "boot": "0.7g",
|
|
+ "current": "2.5g",
|
|
+ "max": "3096m",
|
|
+ "slots": "10",
|
|
+ "soft_limit": "2048m",
|
|
+ "hard_limit": "1024",
|
|
+ "swap_hard_limit": "2.5g",
|
|
+ "min_guarantee": "1 g",
|
|
+ }
|
|
+
|
|
+ domain_mock.setMemoryFlags.return_value = 0
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ "mem": True,
|
|
+ },
|
|
+ virt.update("vm_with_memtune_param", mem=memtune_new_val),
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024 ** 2)
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("soft_limit").text, str(2048 * 1024)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("hard_limit").text, str(1024 * 1024)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("swap_hard_limit").text,
|
|
+ str(int(2.5 * 1024 ** 2)),
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("swap_hard_limit").get("unit"), "KiB",
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("min_guarantee").text, str(1 * 1024 ** 3)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("min_guarantee").attrib.get("unit"), "bytes"
|
|
+ )
|
|
+ self.assertEqual(setxml.find("maxMemory").text, str(3096 * 1024 ** 2))
|
|
+ self.assertEqual(setxml.find("maxMemory").attrib.get("slots"), "10")
|
|
+ self.assertEqual(setxml.find("currentMemory").text, str(int(2.5 * 1024 ** 3)))
|
|
+ self.assertEqual(setxml.find("memory").text, str(int(0.7 * 1024 ** 3)))
|
|
+
|
|
+ max_slot_reverse = {
|
|
+ "slots": "10",
|
|
+ "max": "3096m",
|
|
+ }
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("vm_with_memtune_param", mem=max_slot_reverse),
|
|
+ )
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(setxml.find("maxMemory").text, str(3096 * 1024 ** 2))
|
|
+ self.assertEqual(setxml.find("maxMemory").get("unit"), "bytes")
|
|
+ self.assertEqual(setxml.find("maxMemory").attrib.get("slots"), "10")
|
|
+
|
|
+ max_swap_none = {
|
|
+ "boot": "0.7g",
|
|
+ "current": "2.5g",
|
|
+ "max": None,
|
|
+ "slots": "10",
|
|
+ "soft_limit": "2048m",
|
|
+ "hard_limit": "1024",
|
|
+ "swap_hard_limit": None,
|
|
+ "min_guarantee": "1 g",
|
|
+ }
|
|
+
|
|
+ domain_mock.setMemoryFlags.reset_mock()
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ "mem": True,
|
|
+ },
|
|
+ virt.update("vm_with_memtune_param", mem=max_swap_none),
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024 ** 2)
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("soft_limit").text, str(2048 * 1024)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("hard_limit").text, str(1024 * 1024)
|
|
+ )
|
|
+ self.assertEqual(setxml.find("memtune").find("swap_hard_limit"), None)
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("min_guarantee").text, str(1 * 1024 ** 3)
|
|
+ )
|
|
+ self.assertEqual(
|
|
+ setxml.find("memtune").find("min_guarantee").attrib.get("unit"), "bytes"
|
|
+ )
|
|
+ self.assertEqual(setxml.find("maxMemory").text, None)
|
|
+ self.assertEqual(setxml.find("currentMemory").text, str(int(2.5 * 1024 ** 3)))
|
|
+ self.assertEqual(setxml.find("memory").text, str(int(0.7 * 1024 ** 3)))
|
|
+
|
|
+ memtune_none = {
|
|
+ "soft_limit": None,
|
|
+ "hard_limit": None,
|
|
+ "swap_hard_limit": None,
|
|
+ "min_guarantee": None,
|
|
+ }
|
|
+
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("vm_with_memtune_param", mem=memtune_none),
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(setxml.find("memtune").find("soft_limit"), None)
|
|
+ self.assertEqual(setxml.find("memtune").find("hard_limit"), None)
|
|
+ self.assertEqual(setxml.find("memtune").find("swap_hard_limit"), None)
|
|
+ self.assertEqual(setxml.find("memtune").find("min_guarantee"), None)
|
|
+
|
|
+ max_none = {
|
|
+ "max": None,
|
|
+ }
|
|
+
|
|
+ self.assertEqual(
|
|
+ {
|
|
+ "definition": True,
|
|
+ "disk": {"attached": [], "detached": [], "updated": []},
|
|
+ "interface": {"attached": [], "detached": []},
|
|
+ },
|
|
+ virt.update("vm_with_memtune_param", mem=max_none),
|
|
+ )
|
|
+
|
|
+ setxml = ET.fromstring(define_mock.call_args[0][0])
|
|
+ self.assertEqual(setxml.find("maxMemory"), None)
|
|
+ self.assertEqual(setxml.find("currentMemory").text, str(int(1 * 1024 ** 2)))
|
|
+ self.assertEqual(setxml.find("memory").text, str(int(1 * 1024 ** 2)))
|
|
+
|
|
+ def test_handle_unit(self):
|
|
+ """
|
|
+ Test regex function for handling units
|
|
+ """
|
|
+ valid_case = [
|
|
+ ("2", 2097152),
|
|
+ ("42", 44040192),
|
|
+ ("5b", 5),
|
|
+ ("2.3Kib", 2355),
|
|
+ ("5.8Kb", 5800),
|
|
+ ("16MiB", 16777216),
|
|
+ ("20 GB", 20000000000),
|
|
+ ("16KB", 16000),
|
|
+ (".5k", 512),
|
|
+ ("2.k", 2048),
|
|
+ ]
|
|
+
|
|
+ for key, val in valid_case:
|
|
+ self.assertEqual(virt._handle_unit(key), val)
|
|
+
|
|
+ invalid_case = [
|
|
+ ("9ib", "invalid units"),
|
|
+ ("8byte", "invalid units"),
|
|
+ ("512bytes", "invalid units"),
|
|
+ ("4 Kbytes", "invalid units"),
|
|
+ ("3.4.MB", "invalid number"),
|
|
+ ("", "invalid number"),
|
|
+ ("bytes", "invalid number"),
|
|
+ ("2HB", "invalid units"),
|
|
+ ]
|
|
+
|
|
+ for key, val in invalid_case:
|
|
+ with self.assertRaises(SaltInvocationError):
|
|
+ virt._handle_unit(key)
|
|
+
|
|
def test_mixed_dict_and_list_as_profile_objects(self):
|
|
"""
|
|
Test virt._nic_profile with mixed dictionaries and lists as input.
|
|
diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py
|
|
index 8fe892f607..1923ae5c0f 100644
|
|
--- a/tests/unit/states/test_virt.py
|
|
+++ b/tests/unit/states/test_virt.py
|
|
@@ -8,7 +8,6 @@ import tempfile
|
|
import salt.states.virt as virt
|
|
import salt.utils.files
|
|
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
|
-from salt.ext import six
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.mock import MagicMock, mock_open, patch
|
|
from tests.support.runtests import RUNTIME_VARS
|
|
@@ -346,6 +345,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
install=False,
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
+ stop_on_reboot=True,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -371,6 +371,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
start=False,
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
+ stop_on_reboot=True,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -484,6 +485,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
password=None,
|
|
boot=None,
|
|
test=False,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
|
|
# Failed definition update case
|
|
@@ -554,6 +556,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
install=False,
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
+ stop_on_reboot=False,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -596,6 +599,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
boot=None,
|
|
test=True,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
|
|
# No changes case
|
|
@@ -631,6 +635,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
boot=None,
|
|
test=True,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
|
|
def test_running(self):
|
|
@@ -708,6 +713,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
pub_key=None,
|
|
priv_key=None,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
connection=None,
|
|
username=None,
|
|
password=None,
|
|
@@ -770,6 +776,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
boot_dev="network hd",
|
|
+ stop_on_reboot=True,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -795,6 +802,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
boot_dev="network hd",
|
|
+ stop_on_reboot=True,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -940,6 +948,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
boot=None,
|
|
test=False,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
|
|
# Failed definition update case
|
|
@@ -1013,6 +1022,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
install=False,
|
|
pub_key="/path/to/key.pub",
|
|
priv_key="/path/to/key",
|
|
+ stop_on_reboot=True,
|
|
connection="someconnection",
|
|
username="libvirtuser",
|
|
password="supersecret",
|
|
@@ -1059,6 +1069,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
boot=None,
|
|
test=True,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
start_mock.assert_not_called()
|
|
|
|
@@ -1096,6 +1107,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|
boot=None,
|
|
test=True,
|
|
boot_dev=None,
|
|
+ stop_on_reboot=False,
|
|
)
|
|
|
|
def test_stopped(self):
|
|
--
|
|
2.29.2
|
|
|
|
|