SHA256
1
0
forked from pool/salt
salt/opensuse-3000-virt-defined-states-222.patch

2378 lines
128 KiB
Diff

From e5d42c6313ba051f22f83cbde3da9410fd7fc3b9 Mon Sep 17 00:00:00 2001
From: Cedric Bosdonnat <cbosdonnat@suse.com>
Date: Fri, 13 Mar 2020 16:38:08 +0100
Subject: [PATCH] openSUSE-3000 virt-defined-states (#222)
* Create virt.pool_defined state out of virt.pool_running
Users may want to use states to ensure a virtual storage pool is defined
and not enforce it to be running. Extract the code that performs the
pool definition / update from virt.pool_running state into a
virt.pool_defined.
Obviously the virt.pool_running state calls the virt.pool_defined one.
In such a case no additionnal test is needed for virt.pool_defined since
this is already tested with virt.pool_running.
* Add virt.update test parameter
In order to allow running dry-runs of virt.update module add a test
parameter. This will later be used by the virt states.
* Extract virt.defined state from virt.running
In order to ensure a virtual guest is defined independently of its
status, extract the corresponding code from the virt.running state.
This commit also handles the __opts__['test'] for the running state.
Since the update call only performs changes if needed, deprecate the
update parameter.
* Extract virt.network_defined from virt.network_running
Just like domains and storage pools, users may want to ensure a network
is defined without influencing it's status. Extract the code from
network_running state defining the network into a network_defined state.
While at it, support __opt__['test'] == True in these states. Updating
the network definition in the pool_defined state will come in a future
PR.
* Fix virt.update to handle None mem and cpu
virt.running state now may call virt.update with None mem and cpu
parameters. This was not handled in _gen_xml(). Also add some more tests
cases matching this for virt.update.
---
salt/modules/virt.py | 16 +-
salt/states/virt.py | 673 +++++++++++++++-----
tests/unit/modules/test_virt.py | 26 +
tests/unit/states/test_virt.py | 1346 ++++++++++++++++++++++++++++++++-------
4 files changed, 1665 insertions(+), 396 deletions(-)
diff --git a/salt/modules/virt.py b/salt/modules/virt.py
index 3889238ecd..f0820e8825 100644
--- a/salt/modules/virt.py
+++ b/salt/modules/virt.py
@@ -1783,6 +1783,7 @@ def update(name,
graphics=None,
live=True,
boot=None,
+ test=False,
**kwargs):
'''
Update the definition of an existing domain.
@@ -1835,6 +1836,10 @@ def update(name,
.. versionadded:: 3000
+ :param test: run in dry-run mode if set to True
+
+ .. versionadded:: sodium
+
:return:
Returns a dictionary indicating the status of what has been done. It is structured in
@@ -1880,8 +1885,8 @@ def update(name,
boot = _handle_remote_boot_params(boot)
new_desc = ElementTree.fromstring(_gen_xml(name,
- cpu,
- mem,
+ cpu or 0,
+ mem or 0,
all_disks,
_get_merged_nics(hypervisor, nic_profile, interfaces),
hypervisor,
@@ -1973,11 +1978,12 @@ def update(name,
if changes['disk']:
for idx, item in enumerate(changes['disk']['sorted']):
source_file = all_disks[idx]['source_file']
- if item in changes['disk']['new'] and source_file and not os.path.isfile(source_file):
+ if item in changes['disk']['new'] and source_file and not os.path.isfile(source_file) and not test:
_qemu_image_create(all_disks[idx])
try:
- conn.defineXML(salt.utils.stringutils.to_str(ElementTree.tostring(desc)))
+ if not test:
+ conn.defineXML(salt.utils.stringutils.to_str(ElementTree.tostring(desc)))
status['definition'] = True
except libvirt.libvirtError as err:
conn.close()
@@ -2010,7 +2016,7 @@ def update(name,
for cmd in commands:
try:
- ret = getattr(domain, cmd['cmd'])(*cmd['args'])
+ ret = getattr(domain, cmd['cmd'])(*cmd['args']) if not test else 0
device_type = cmd['device']
if device_type in ['cpu', 'mem']:
status[device_type] = not bool(ret)
diff --git a/salt/states/virt.py b/salt/states/virt.py
index 55a9ad2616..819776d707 100644
--- a/salt/states/virt.py
+++ b/salt/states/virt.py
@@ -14,6 +14,7 @@ for the generation and signing of certificates for systems running libvirt:
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
+import copy
import fnmatch
import os
@@ -245,6 +246,187 @@ def powered_off(name, connection=None, username=None, password=None):
connection=connection, username=username, password=password)
+def defined(name,
+ cpu=None,
+ mem=None,
+ vm_type=None,
+ disk_profile=None,
+ disks=None,
+ nic_profile=None,
+ interfaces=None,
+ graphics=None,
+ seed=True,
+ install=True,
+ pub_key=None,
+ priv_key=None,
+ connection=None,
+ username=None,
+ password=None,
+ os_type=None,
+ arch=None,
+ boot=None,
+ update=True):
+ '''
+ Starts an existing guest, or defines and starts a new VM with specified arguments.
+
+ .. versionadded:: sodium
+
+ :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 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.
+ :param disk_profile:
+ Name of the disk profile to use for the new virtual machine
+ :param disks:
+ List of disk to create for the new virtual machine.
+ See :ref:`init-disk-def` for more details on the items on this list.
+ :param nic_profile:
+ Name of the network interfaces profile to use for the new virtual machine
+ :param interfaces:
+ List of network interfaces to create for the new virtual machine.
+ See :ref:`init-nic-def` for more details on the items on this list.
+ :param graphics:
+ Graphics device to create for the new virtual machine.
+ See :ref:`init-graphics-def` for more details on this dictionary
+ :param saltenv:
+ Fileserver environment (Default: ``'base'``).
+ See :mod:`cp module for more details <salt.modules.cp>`
+ :param seed: ``True`` to seed the disk image. Only used when the ``image`` parameter is provided.
+ (Default: ``True``)
+ :param install: install salt minion if absent (Default: ``True``)
+ :param pub_key: public key to seed with (Default: ``None``)
+ :param priv_key: public key to seed with (Default: ``None``)
+ :param seed_cmd: Salt command to execute to seed the image. (Default: ``'seed.apply'``)
+ :param connection: libvirt connection URI, overriding defaults
+ :param username: username to connect with, overriding defaults
+ :param password: password to connect with, overriding defaults
+ :param os_type:
+ type of virtualization as found in the ``//os/type`` element of the libvirt definition.
+ The default value is taken from the host capabilities, with a preference for ``hvm``.
+ Only used when creating a new virtual machine.
+ :param arch:
+ architecture of the virtual machine. The default value is taken from the host capabilities,
+ but ``x86_64`` is prefed over ``i686``. Only used when creating a new virtual machine.
+
+ :param boot:
+ Specifies kernel for the virtual machine, as well as boot parameters
+ for the virtual machine. This is an optionl parameter, and all of the
+ keys are optional within the dictionary. If a remote path is provided
+ to kernel or initrd, salt will handle the downloading of the specified
+ remote fild, and will modify the XML accordingly.
+
+ .. code-block:: python
+
+ {
+ 'kernel': '/root/f8-i386-vmlinuz',
+ 'initrd': '/root/f8-i386-initrd',
+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/'
+ }
+
+ :param update: set to ``False`` to prevent updating a defined domain. (Default: ``True``)
+
+ .. deprecated:: sodium
+
+ .. rubric:: Example States
+
+ Make sure a virtual machine called ``domain_name`` is defined:
+
+ .. code-block:: yaml
+
+ domain_name:
+ virt.defined:
+ - cpu: 2
+ - mem: 2048
+ - disk_profile: prod
+ - disks:
+ - name: system
+ size: 8192
+ overlay_image: True
+ pool: default
+ image: /path/to/image.qcow2
+ - name: data
+ size: 16834
+ - nic_profile: prod
+ - interfaces:
+ - name: eth0
+ mac: 01:23:45:67:89:AB
+ - name: eth1
+ type: network
+ source: admin
+ - graphics:
+ type: spice
+ listen:
+ type: address
+ address: 192.168.0.125
+
+ '''
+
+ ret = {'name': name,
+ 'changes': {},
+ 'result': True if not __opts__['test'] else None,
+ 'comment': ''
+ }
+
+ try:
+ if name in __salt__['virt.list_domains'](connection=connection, username=username, password=password):
+ status = {}
+ if update:
+ status = __salt__['virt.update'](name,
+ cpu=cpu,
+ mem=mem,
+ disk_profile=disk_profile,
+ disks=disks,
+ nic_profile=nic_profile,
+ interfaces=interfaces,
+ graphics=graphics,
+ live=True,
+ connection=connection,
+ username=username,
+ password=password,
+ boot=boot,
+ test=__opts__['test'])
+ ret['changes'][name] = status
+ if not status.get('definition'):
+ ret['comment'] = 'Domain {0} unchanged'.format(name)
+ ret['result'] = True
+ elif status.get('errors'):
+ ret['comment'] = 'Domain {0} updated with live update(s) failures'.format(name)
+ else:
+ ret['comment'] = 'Domain {0} updated'.format(name)
+ else:
+ if not __opts__['test']:
+ __salt__['virt.init'](name,
+ cpu=cpu,
+ mem=mem,
+ os_type=os_type,
+ arch=arch,
+ hypervisor=vm_type,
+ disk=disk_profile,
+ disks=disks,
+ nic=nic_profile,
+ interfaces=interfaces,
+ graphics=graphics,
+ seed=seed,
+ install=install,
+ pub_key=pub_key,
+ priv_key=priv_key,
+ connection=connection,
+ username=username,
+ password=password,
+ boot=boot,
+ start=False)
+ ret['changes'][name] = {'definition': True}
+ ret['comment'] = 'Domain {0} defined'.format(name)
+ except libvirt.libvirtError as err:
+ # Something bad happened when defining / updating the VM, report it
+ ret['comment'] = six.text_type(err)
+ ret['result'] = False
+
+ return ret
+
+
def running(name,
cpu=None,
mem=None,
@@ -326,9 +508,10 @@ def running(name,
:param seed_cmd: Salt command to execute to seed the image. (Default: ``'seed.apply'``)
.. versionadded:: 2019.2.0
- :param update: set to ``True`` to update a defined module. (Default: ``False``)
+ :param update: set to ``True`` to update a defined domain. (Default: ``False``)
.. versionadded:: 2019.2.0
+ .. deprecated:: sodium
:param connection: libvirt connection URI, overriding defaults
.. versionadded:: 2019.2.0
@@ -424,93 +607,74 @@ def running(name,
address: 192.168.0.125
'''
-
- ret = {'name': name,
- 'changes': {},
- 'result': True,
- 'comment': '{0} is running'.format(name)
- }
-
- try:
+ merged_disks = disks
+ if image:
+ default_disks = [{'system': {}}]
+ disknames = ['system']
+ if disk_profile:
+ disklist = copy.deepcopy(
+ __salt__['config.get']('virt:disk', {}).get(disk_profile, default_disks))
+ disknames = disklist.keys()
+ disk = {'name': disknames[0], 'image': image}
+ if merged_disks:
+ first_disk = [d for d in merged_disks if d.get('name') == disknames[0]]
+ if first_disk and 'image' not in first_disk[0]:
+ first_disk[0]['image'] = image
+ else:
+ merged_disks.append(disk)
+ else:
+ merged_disks = [disk]
+ salt.utils.versions.warn_until(
+ 'Sodium',
+ '\'image\' parameter has been deprecated. Rather use the \'disks\' parameter '
+ 'to override or define the image. \'image\' will be removed in {version}.'
+ )
+
+ if not update:
+ salt.utils.versions.warn_until('Magnesium',
+ '\'update\' parameter has been deprecated. Future behavior will be the one of update=True'
+ 'It will be removed in {version}.')
+ ret = defined(name,
+ cpu=cpu,
+ mem=mem,
+ vm_type=vm_type,
+ disk_profile=disk_profile,
+ disks=merged_disks,
+ nic_profile=nic_profile,
+ interfaces=interfaces,
+ graphics=graphics,
+ seed=seed,
+ install=install,
+ pub_key=pub_key,
+ priv_key=priv_key,
+ os_type=os_type,
+ arch=arch,
+ boot=boot,
+ update=update,
+ connection=connection,
+ username=username,
+ password=password)
+
+ result = True if not __opts__['test'] else None
+ if ret['result'] is None or ret['result']:
+ changed = ret['changes'][name].get('definition', False)
try:
domain_state = __salt__['virt.vm_state'](name)
if domain_state.get(name) != 'running':
- action_msg = 'started'
- if update:
- status = __salt__['virt.update'](name,
- cpu=cpu,
- mem=mem,
- disk_profile=disk_profile,
- disks=disks,
- nic_profile=nic_profile,
- interfaces=interfaces,
- graphics=graphics,
- live=False,
- connection=connection,
- username=username,
- password=password,
- boot=boot)
- if status['definition']:
- action_msg = 'updated and started'
- __salt__['virt.start'](name)
- ret['changes'][name] = 'Domain {0}'.format(action_msg)
- ret['comment'] = 'Domain {0} {1}'.format(name, action_msg)
- else:
- if update:
- status = __salt__['virt.update'](name,
- cpu=cpu,
- mem=mem,
- disk_profile=disk_profile,
- disks=disks,
- nic_profile=nic_profile,
- interfaces=interfaces,
- graphics=graphics,
- connection=connection,
- username=username,
- password=password,
- boot=boot)
- ret['changes'][name] = status
- if status.get('errors', None):
- ret['comment'] = 'Domain {0} updated, but some live update(s) failed'.format(name)
- elif not status['definition']:
- ret['comment'] = 'Domain {0} exists and is running'.format(name)
- else:
- ret['comment'] = 'Domain {0} updated, restart to fully apply the changes'.format(name)
- else:
- ret['comment'] = 'Domain {0} exists and is running'.format(name)
- except CommandExecutionError:
- if image:
- salt.utils.versions.warn_until(
- 'Sodium',
- '\'image\' parameter has been deprecated. Rather use the \'disks\' parameter '
- 'to override or define the image. \'image\' will be removed in {version}.'
- )
- __salt__['virt.init'](name,
- cpu=cpu,
- mem=mem,
- os_type=os_type,
- arch=arch,
- image=image,
- hypervisor=vm_type,
- disk=disk_profile,
- disks=disks,
- nic=nic_profile,
- interfaces=interfaces,
- graphics=graphics,
- seed=seed,
- install=install,
- pub_key=pub_key,
- priv_key=priv_key,
- connection=connection,
- username=username,
- password=password,
- boot=boot)
- ret['changes'][name] = 'Domain defined and started'
- ret['comment'] = 'Domain {0} defined and started'.format(name)
- except libvirt.libvirtError as err:
- # Something bad happened when starting / updating the VM, report it
- ret['comment'] = six.text_type(err)
- ret['result'] = False
+ if not __opts__['test']:
+ __salt__['virt.start'](name, connection=connection, username=username, password=password)
+ comment = 'Domain {} started'.format(name)
+ if not ret['comment'].endswith('unchanged'):
+ comment = '{} and started'.format(ret['comment'])
+ ret['comment'] = comment
+ ret['changes'][name]['started'] = True
+ elif not changed:
+ ret['comment'] = 'Domain {0} exists and is running'.format(name)
+
+ except libvirt.libvirtError as err:
+ # Something bad happened when starting / updating the VM, report it
+ ret['comment'] = six.text_type(err)
+ ret['result'] = False
return ret
@@ -670,6 +834,106 @@ def reverted(name, snapshot=None, cleanup=False): # pylint: disable=redefined-o
return ret
+def network_defined(name,
+ bridge,
+ forward,
+ vport=None,
+ tag=None,
+ ipv4_config=None,
+ ipv6_config=None,
+ autostart=True,
+ connection=None,
+ username=None,
+ password=None):
+ '''
+ Defines a new network with specified arguments.
+
+ :param bridge: Bridge name
+ :param forward: Forward mode(bridge, router, nat)
+ :param vport: Virtualport type (Default: ``'None'``)
+ :param tag: Vlan tag (Default: ``'None'``)
+ :param ipv4_config:
+ IPv4 network configuration. See the :py:func`virt.network_define
+ <salt.modules.virt.network_define>` function corresponding parameter documentation
+ for more details on this dictionary.
+ (Default: None).
+ :param ipv6_config:
+ IPv6 network configuration. See the :py:func`virt.network_define
+ <salt.modules.virt.network_define>` function corresponding parameter documentation
+ for more details on this dictionary.
+ (Default: None).
+ :param autostart: Network autostart (default ``'True'``)
+ :param connection: libvirt connection URI, overriding defaults
+ :param username: username to connect with, overriding defaults
+ :param password: password to connect with, overriding defaults
+
+ .. versionadded:: sodium
+
+ .. code-block:: yaml
+
+ network_name:
+ virt.network_defined
+
+ .. code-block:: yaml
+
+ network_name:
+ virt.network_defined:
+ - bridge: main
+ - forward: bridge
+ - vport: openvswitch
+ - tag: 180
+ - autostart: True
+
+ .. code-block:: yaml
+
+ network_name:
+ virt.network_defined:
+ - bridge: natted
+ - forward: nat
+ - ipv4_config:
+ cidr: 192.168.42.0/24
+ dhcp_ranges:
+ - start: 192.168.42.10
+ end: 192.168.42.25
+ - start: 192.168.42.100
+ end: 192.168.42.150
+ - autostart: True
+
+ '''
+ ret = {'name': name,
+ 'changes': {},
+ 'result': True if not __opts__['test'] else None,
+ 'comment': ''
+ }
+
+ try:
+ info = __salt__['virt.network_info'](name, connection=connection, username=username, password=password)
+ if info and info[name]:
+ ret['comment'] = 'Network {0} exists'.format(name)
+ ret['result'] = True
+ else:
+ if not __opts__['test']:
+ __salt__['virt.network_define'](name,
+ bridge,
+ forward,
+ vport=vport,
+ tag=tag,
+ ipv4_config=ipv4_config,
+ ipv6_config=ipv6_config,
+ autostart=autostart,
+ start=False,
+ connection=connection,
+ username=username,
+ password=password)
+ ret['changes'][name] = 'Network defined'
+ ret['comment'] = 'Network {0} defined'.format(name)
+ except libvirt.libvirtError as err:
+ ret['result'] = False
+ ret['comment'] = err.get_error_message()
+
+ return ret
+
+
def network_running(name,
bridge,
forward,
@@ -715,13 +979,13 @@ def network_running(name,
.. code-block:: yaml
- domain_name:
- virt.network_define
+ network_name:
+ virt.network_running
.. code-block:: yaml
network_name:
- virt.network_define:
+ virt.network_running:
- bridge: main
- forward: bridge
- vport: openvswitch
@@ -731,7 +995,7 @@ def network_running(name,
.. code-block:: yaml
network_name:
- virt.network_define:
+ virt.network_running:
- bridge: natted
- forward: nat
- ipv4_config:
@@ -744,44 +1008,46 @@ def network_running(name,
- autostart: True
'''
- ret = {'name': name,
- 'changes': {},
- 'result': True,
- 'comment': ''
- }
-
- try:
- info = __salt__['virt.network_info'](name, connection=connection, username=username, password=password)
- if info:
- if info[name]['active']:
- ret['comment'] = 'Network {0} exists and is running'.format(name)
+ ret = network_defined(name,
+ bridge,
+ forward,
+ vport=vport,
+ tag=tag,
+ ipv4_config=ipv4_config,
+ ipv6_config=ipv6_config,
+ autostart=autostart,
+ connection=connection,
+ username=username,
+ password=password)
+
+ defined = name in ret['changes'] and ret['changes'][name].startswith('Network defined')
+
+ result = True if not __opts__['test'] else None
+ if ret['result'] is None or ret['result']:
+ try:
+ info = __salt__['virt.network_info'](name, connection=connection, username=username, password=password)
+ # In the corner case where test=True and the network wasn't defined
+ # we may not get the network in the info dict and that is normal.
+ if info.get(name, {}).get('active', False):
+ ret['comment'] = '{} and is running'.format(ret['comment'])
else:
- __salt__['virt.network_start'](name, connection=connection, username=username, password=password)
- ret['changes'][name] = 'Network started'
- ret['comment'] = 'Network {0} started'.format(name)
- else:
- __salt__['virt.network_define'](name,
- bridge,
- forward,
- vport=vport,
- tag=tag,
- ipv4_config=ipv4_config,
- ipv6_config=ipv6_config,
- autostart=autostart,
- start=True,
- connection=connection,
- username=username,
- password=password)
- ret['changes'][name] = 'Network defined and started'
- ret['comment'] = 'Network {0} defined and started'.format(name)
- except libvirt.libvirtError as err:
- ret['result'] = False
- ret['comment'] = err.get_error_message()
+ if not __opts__['test']:
+ __salt__['virt.network_start'](name, connection=connection, username=username, password=password)
+ change = 'Network started'
+ if name in ret['changes']:
+ change = '{} and started'.format(ret['changes'][name])
+ ret['changes'][name] = change
+ ret['comment'] = '{} and started'.format(ret['comment'])
+ ret['result'] = result
+
+ except libvirt.libvirtError as err:
+ ret['result'] = False
+ ret['comment'] = err.get_error_message()
return ret
-def pool_running(name,
+def pool_defined(name,
ptype=None,
target=None,
permissions=None,
@@ -792,9 +1058,9 @@ def pool_running(name,
username=None,
password=None):
'''
- Defines and starts a new pool with specified arguments.
+ Defines a new pool with specified arguments.
- .. versionadded:: 2019.2.0
+ .. versionadded:: sodium
:param ptype: libvirt pool type
:param target: full path to the target device or folder. (Default: ``None``)
@@ -816,12 +1082,7 @@ def pool_running(name,
.. code-block:: yaml
pool_name:
- virt.pool_define
-
- .. code-block:: yaml
-
- pool_name:
- virt.pool_define:
+ virt.pool_defined:
- ptype: netfs
- target: /mnt/cifs
- permissions:
@@ -884,29 +1145,19 @@ def pool_running(name,
username=username,
password=password)
- action = "started"
- if info[name]['state'] == 'running':
- action = "restarted"
+ action = ''
+ if info[name]['state'] != 'running':
if not __opts__['test']:
- __salt__['virt.pool_stop'](name, connection=connection, username=username, password=password)
-
- if not __opts__['test']:
- __salt__['virt.pool_build'](name, connection=connection, username=username, password=password)
- __salt__['virt.pool_start'](name, connection=connection, username=username, password=password)
+ __salt__['virt.pool_build'](name, connection=connection, username=username, password=password)
+ action = ', built'
- autostart_str = ', autostart flag changed' if needs_autostart else ''
- ret['changes'][name] = 'Pool updated, built{0} and {1}'.format(autostart_str, action)
- ret['comment'] = 'Pool {0} updated, built{1} and {2}'.format(name, autostart_str, action)
+ action = '{}, autostart flag changed'.format(action) if needs_autostart else action
+ ret['changes'][name] = 'Pool updated{0}'.format(action)
+ ret['comment'] = 'Pool {0} updated{1}'.format(name, action)
else:
- if info[name]['state'] == 'running':
- ret['comment'] = 'Pool {0} unchanged and is running'.format(name)
- ret['result'] = True
- else:
- ret['changes'][name] = 'Pool started'
- ret['comment'] = 'Pool {0} started'.format(name)
- if not __opts__['test']:
- __salt__['virt.pool_start'](name, connection=connection, username=username, password=password)
+ ret['comment'] = 'Pool {0} unchanged'.format(name)
+ ret['result'] = True
else:
needs_autostart = autostart
if not __opts__['test']:
@@ -932,17 +1183,12 @@ def pool_running(name,
connection=connection,
username=username,
password=password)
-
- __salt__['virt.pool_start'](name,
- connection=connection,
- username=username,
- password=password)
if needs_autostart:
- ret['changes'][name] = 'Pool defined, started and marked for autostart'
- ret['comment'] = 'Pool {0} defined, started and marked for autostart'.format(name)
+ ret['changes'][name] = 'Pool defined, marked for autostart'
+ ret['comment'] = 'Pool {0} defined, marked for autostart'.format(name)
else:
- ret['changes'][name] = 'Pool defined and started'
- ret['comment'] = 'Pool {0} defined and started'.format(name)
+ ret['changes'][name] = 'Pool defined'
+ ret['comment'] = 'Pool {0} defined'.format(name)
if needs_autostart:
if not __opts__['test']:
@@ -958,6 +1204,117 @@ def pool_running(name,
return ret
+def pool_running(name,
+ ptype=None,
+ target=None,
+ permissions=None,
+ source=None,
+ transient=False,
+ autostart=True,
+ connection=None,
+ username=None,
+ password=None):
+ '''
+ Defines and starts a new pool with specified arguments.
+
+ .. versionadded:: 2019.2.0
+
+ :param ptype: libvirt pool type
+ :param target: full path to the target device or folder. (Default: ``None``)
+ :param permissions:
+ target permissions. See :ref:`pool-define-permissions` for more details on this structure.
+ :param source:
+ dictionary containing keys matching the ``source_*`` parameters in function
+ :func:`salt.modules.virt.pool_define`.
+ :param transient:
+ when set to ``True``, the pool will be automatically undefined after being stopped. (Default: ``False``)
+ :param autostart:
+ Whether to start the pool when booting the host. (Default: ``True``)
+ :param start:
+ When ``True``, define and start the pool, otherwise the pool will be left stopped.
+ :param connection: libvirt connection URI, overriding defaults
+ :param username: username to connect with, overriding defaults
+ :param password: password to connect with, overriding defaults
+
+ .. code-block:: yaml
+
+ pool_name:
+ virt.pool_running
+
+ .. code-block:: yaml
+
+ pool_name:
+ virt.pool_running:
+ - ptype: netfs
+ - target: /mnt/cifs
+ - permissions:
+ - mode: 0770
+ - owner: 1000
+ - group: 100
+ - source:
+ dir: samba_share
+ hosts:
+ - one.example.com
+ - two.example.com
+ format: cifs
+ - autostart: True
+
+ '''
+ ret = pool_defined(name,
+ ptype=ptype,
+ target=target,
+ permissions=permissions,
+ source=source,
+ transient=transient,
+ autostart=autostart,
+ connection=connection,
+ username=username,
+ password=password)
+ defined = name in ret['changes'] and ret['changes'][name].startswith('Pool defined')
+ updated = name in ret['changes'] and ret['changes'][name].startswith('Pool updated')
+
+ result = True if not __opts__['test'] else None
+ if ret['result'] is None or ret['result']:
+ try:
+ info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password)
+ action = 'started'
+ # In the corner case where test=True and the pool wasn't defined
+ # we may get not get our pool in the info dict and that is normal.
+ is_running = info.get(name, {}).get('state', 'stopped') == 'running'
+ if is_running:
+ if updated:
+ action = 'built, restarted'
+ if not __opts__['test']:
+ __salt__['virt.pool_stop'](name, connection=connection, username=username, password=password)
+ if not __opts__['test']:
+ __salt__['virt.pool_build'](name, connection=connection, username=username, password=password)
+ else:
+ action = 'already running'
+ result = True
+
+ if not is_running or updated or defined:
+ if not __opts__['test']:
+ __salt__['virt.pool_start'](name, connection=connection, username=username, password=password)
+
+ comment = 'Pool {0}'.format(name)
+ change = 'Pool'
+ if name in ret['changes']:
+ comment = '{0},'.format(ret['comment'])
+ change = '{0},'.format(ret['changes'][name])
+
+ if action != 'already running':
+ ret['changes'][name] = '{0} {1}'.format(change, action)
+
+ ret['comment'] = '{0} {1}'.format(comment, action)
+ ret['result'] = result
+
+ except libvirt.libvirtError as err:
+ ret['comment'] = err.get_error_message()
+ ret['result'] = False
+
+ return ret
+
+
def pool_deleted(name,
purge=False,
connection=None,
diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py
index d762dcc479..8690154662 100644
--- a/tests/unit/modules/test_virt.py
+++ b/tests/unit/modules/test_virt.py
@@ -1272,6 +1272,32 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
define_mock = MagicMock(return_value=True)
self.mock_conn.defineXML = define_mock
+ # No parameter passed case
+ self.assertEqual({
+ 'definition': False,
+ 'disk': {'attached': [], 'detached': []},
+ 'interface': {'attached': [], 'detached': []}
+ }, virt.update('my vm'))
+
+ # Same parameters passed than in default virt.defined state case
+ self.assertEqual({
+ 'definition': False,
+ 'disk': {'attached': [], 'detached': []},
+ 'interface': {'attached': [], 'detached': []}
+ }, virt.update('my vm',
+ cpu=None,
+ mem=None,
+ disk_profile=None,
+ disks=None,
+ nic_profile=None,
+ interfaces=None,
+ graphics=None,
+ live=True,
+ connection=None,
+ username=None,
+ password=None,
+ boot=None))
+
# Update vcpus case
setvcpus_mock = MagicMock(return_value=0)
domain_mock.setVcpusFlags = setvcpus_mock
diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py
index c50c04b8ab..6727704494 100644
--- a/tests/unit/states/test_virt.py
+++ b/tests/unit/states/test_virt.py
@@ -217,6 +217,243 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
organization='SaltStack',
expiration_days=700), ret)
+ def test_defined(self):
+ '''
+ defined state test cases.
+ '''
+ ret = {'name': 'myvm',
+ 'changes': {},
+ 'result': True,
+ 'comment': 'myvm is running'}
+ with patch.dict(virt.__opts__, {'test': False}):
+ # no change test
+ init_mock = MagicMock(return_value=True)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': MagicMock(return_value={'definition': False}),
+ }):
+ ret.update({'changes': {'myvm': {'definition': False}},
+ 'comment': 'Domain myvm unchanged'})
+ self.assertDictEqual(virt.defined('myvm'), ret)
+
+ # Test defining a guest with connection details
+ init_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=[]),
+ 'virt.init': init_mock,
+ 'virt.update': MagicMock(side_effect=CommandExecutionError('not found')),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True}},
+ 'comment': 'Domain myvm defined'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/image.qcow2'
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ ifaces = [{
+ 'name': 'eth0',
+ 'mac': '01:23:45:67:89:AB'
+ },
+ {
+ 'name': 'eth1',
+ 'type': 'network',
+ 'source': 'admin'
+ }]
+ graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
+ self.assertDictEqual(virt.defined('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ vm_type='qemu',
+ disk_profile='prod',
+ disks=disks,
+ nic_profile='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ seed=False,
+ install=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret'), ret)
+ init_mock.assert_called_with('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ disk='prod',
+ disks=disks,
+ nic='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ hypervisor='qemu',
+ seed=False,
+ boot=None,
+ install=False,
+ start=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret')
+
+ # Working update case when running
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True})
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.defined('myvm', cpu=2), ret)
+
+ # Working update case when running with boot params
+ boot = {
+ 'kernel': '/root/f8-i386-vmlinuz',
+ 'initrd': '/root/f8-i386-initrd',
+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/'
+ }
+
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True})
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.defined('myvm', boot=boot), ret)
+
+ # Working update case when stopped
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': MagicMock(return_value={'definition': True})
+ }):
+ ret.update({'changes': {'myvm': {'definition': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.defined('myvm', cpu=2), ret)
+
+ # Failed live update case
+ update_mock = MagicMock(return_value={'definition': True, 'cpu': False, 'errors': ['some error']})
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': update_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 'errors': ['some error']}},
+ 'result': True,
+ 'comment': 'Domain myvm updated with live update(s) failures'})
+ self.assertDictEqual(virt.defined('myvm', cpu=2), ret)
+ update_mock.assert_called_with('myvm', cpu=2, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=False)
+
+ # Failed definition update case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')])
+ }):
+ ret.update({'changes': {},
+ 'result': False,
+ 'comment': 'error message'})
+ self.assertDictEqual(virt.defined('myvm', cpu=2), ret)
+
+ # Test dry-run mode
+ with patch.dict(virt.__opts__, {'test': True}):
+ # Guest defined case
+ init_mock = MagicMock(return_value=True)
+ update_mock = MagicMock(side_effect=CommandExecutionError('not found'))
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=[]),
+ 'virt.init': init_mock,
+ 'virt.update': update_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': True}},
+ 'result': None,
+ 'comment': 'Domain myvm defined'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/image.qcow2'
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ ifaces = [{
+ 'name': 'eth0',
+ 'mac': '01:23:45:67:89:AB'
+ },
+ {
+ 'name': 'eth1',
+ 'type': 'network',
+ 'source': 'admin'
+ }]
+ graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
+ self.assertDictEqual(virt.defined('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ vm_type='qemu',
+ disk_profile='prod',
+ disks=disks,
+ nic_profile='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ seed=False,
+ install=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret'), ret)
+ init_mock.assert_not_called()
+ update_mock.assert_not_called()
+
+ # Guest update case
+ update_mock = MagicMock(return_value={'definition': True})
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': update_mock
+ }):
+ ret.update({'changes': {'myvm': {'definition': True}},
+ 'result': None,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.defined('myvm', cpu=2), ret)
+ update_mock.assert_called_with('myvm', cpu=2, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=True)
+
+ # No changes case
+ update_mock = MagicMock(return_value={'definition': False})
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ 'virt.update': update_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': False}},
+ 'result': True,
+ 'comment': 'Domain myvm unchanged'})
+ self.assertDictEqual(virt.defined('myvm'), ret)
+ update_mock.assert_called_with('myvm', cpu=None, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=True)
+
def test_running(self):
'''
running state test cases.
@@ -225,163 +462,369 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
'changes': {},
'result': True,
'comment': 'myvm is running'}
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
- 'virt.start': MagicMock(return_value=0),
- }):
- ret.update({'changes': {'myvm': 'Domain started'},
- 'comment': 'Domain myvm started'})
- self.assertDictEqual(virt.running('myvm'), ret)
-
- init_mock = MagicMock(return_value=True)
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(side_effect=CommandExecutionError('not found')),
- 'virt.init': init_mock,
- 'virt.start': MagicMock(return_value=0)
- }):
- ret.update({'changes': {'myvm': 'Domain defined and started'},
- 'comment': 'Domain myvm defined and started'})
- self.assertDictEqual(virt.running('myvm',
- cpu=2,
- mem=2048,
- image='/path/to/img.qcow2'), ret)
- init_mock.assert_called_with('myvm', cpu=2, mem=2048, image='/path/to/img.qcow2',
- os_type=None, arch=None, boot=None,
- disk=None, disks=None, nic=None, interfaces=None,
- graphics=None, hypervisor=None,
- seed=True, install=True, pub_key=None, priv_key=None,
- connection=None, username=None, password=None)
+ with patch.dict(virt.__opts__, {'test': False}):
+ # Test starting an existing guest without changing it
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.start': MagicMock(return_value=0),
+ 'virt.update': MagicMock(return_value={'definition': False}),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {'started': True}},
+ 'comment': 'Domain myvm started'})
+ self.assertDictEqual(virt.running('myvm'), ret)
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(side_effect=CommandExecutionError('not found')),
- 'virt.init': init_mock,
- 'virt.start': MagicMock(return_value=0)
- }):
- ret.update({'changes': {'myvm': 'Domain defined and started'},
- 'comment': 'Domain myvm defined and started'})
- disks = [{
- 'name': 'system',
- 'size': 8192,
- 'overlay_image': True,
- 'pool': 'default',
- 'image': '/path/to/image.qcow2'
- },
- {
- 'name': 'data',
- 'size': 16834
- }]
- ifaces = [{
- 'name': 'eth0',
- 'mac': '01:23:45:67:89:AB'
- },
- {
- 'name': 'eth1',
- 'type': 'network',
- 'source': 'admin'
- }]
- graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
- self.assertDictEqual(virt.running('myvm',
- cpu=2,
- mem=2048,
- os_type='linux',
- arch='i686',
- vm_type='qemu',
- disk_profile='prod',
- disks=disks,
- nic_profile='prod',
- interfaces=ifaces,
- graphics=graphics,
- seed=False,
- install=False,
- pub_key='/path/to/key.pub',
- priv_key='/path/to/key',
+ # Test defining and starting a guest the old way
+ init_mock = MagicMock(return_value=True)
+ start_mock = MagicMock(return_value=0)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.init': init_mock,
+ 'virt.start': start_mock,
+ 'virt.list_domains': MagicMock(return_value=[]),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'comment': 'Domain myvm defined and started'})
+ self.assertDictEqual(virt.running('myvm',
+ cpu=2,
+ mem=2048,
+ image='/path/to/img.qcow2'), ret)
+ init_mock.assert_called_with('myvm', cpu=2, mem=2048,
+ os_type=None, arch=None, boot=None,
+ disk=None, disks=[{'name': 'system', 'image': '/path/to/img.qcow2'}], nic=None, interfaces=None,
+ graphics=None, hypervisor=None, start=False,
+ seed=True, install=True, pub_key=None, priv_key=None,
+ connection=None, username=None, password=None,)
+ start_mock.assert_called_with('myvm', connection=None, username=None, password=None)
+
+ # Test image parameter with disks with defined image
+ init_mock = MagicMock(return_value=True)
+ start_mock = MagicMock(return_value=0)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.init': init_mock,
+ 'virt.start': start_mock,
+ 'virt.list_domains': MagicMock(return_value=[]),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'comment': 'Domain myvm defined and started'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/image.qcow2'
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ self.assertDictEqual(virt.running('myvm',
+ cpu=2,
+ mem=2048,
+ disks=disks,
+ image='/path/to/img.qcow2'), ret)
+ init_mock.assert_called_with('myvm', cpu=2, mem=2048,
+ os_type=None, arch=None, boot=None,
+ disk=None, disks=disks, nic=None, interfaces=None,
+ graphics=None, hypervisor=None, start=False,
+ seed=True, install=True, pub_key=None, priv_key=None,
+ connection=None, username=None, password=None,)
+ start_mock.assert_called_with('myvm', connection=None, username=None, password=None)
+
+ # Test image parameter with disks without defined image
+ init_mock = MagicMock(return_value=True)
+ start_mock = MagicMock(return_value=0)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.init': init_mock,
+ 'virt.start': start_mock,
+ 'virt.list_domains': MagicMock(return_value=[]),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'comment': 'Domain myvm defined and started'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ self.assertDictEqual(virt.running('myvm',
+ cpu=2,
+ mem=2048,
+ disks=disks,
+ image='/path/to/img.qcow2'), ret)
+ init_mock.assert_called_with('myvm', cpu=2, mem=2048,
+ os_type=None, arch=None, boot=None,
+ disk=None,
+ disks=[{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/img.qcow2',
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }],
+ nic=None, interfaces=None,
+ graphics=None, hypervisor=None, start=False,
+ seed=True, install=True, pub_key=None, priv_key=None,
+ connection=None, username=None, password=None,)
+ start_mock.assert_called_with('myvm', connection=None, username=None, password=None)
+
+ # Test defining and starting a guest the new way with connection details
+ init_mock.reset_mock()
+ start_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.init': init_mock,
+ 'virt.start': start_mock,
+ 'virt.list_domains': MagicMock(return_value=[]),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'comment': 'Domain myvm defined and started'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/image.qcow2'
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ ifaces = [{
+ 'name': 'eth0',
+ 'mac': '01:23:45:67:89:AB'
+ },
+ {
+ 'name': 'eth1',
+ 'type': 'network',
+ 'source': 'admin'
+ }]
+ graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
+ self.assertDictEqual(virt.running('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ vm_type='qemu',
+ disk_profile='prod',
+ disks=disks,
+ nic_profile='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ seed=False,
+ install=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret'), ret)
+ init_mock.assert_called_with('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ disk='prod',
+ disks=disks,
+ nic='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ hypervisor='qemu',
+ seed=False,
+ boot=None,
+ install=False,
+ start=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret')
+ start_mock.assert_called_with('myvm',
connection='someconnection',
username='libvirtuser',
- password='supersecret'), ret)
- init_mock.assert_called_with('myvm',
- cpu=2,
- mem=2048,
- os_type='linux',
- arch='i686',
- image=None,
- disk='prod',
- disks=disks,
- nic='prod',
- interfaces=ifaces,
- graphics=graphics,
- hypervisor='qemu',
- seed=False,
- boot=None,
- install=False,
- pub_key='/path/to/key.pub',
- priv_key='/path/to/key',
- connection='someconnection',
- username='libvirtuser',
- password='supersecret')
+ password='supersecret')
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
- 'virt.start': MagicMock(side_effect=[self.mock_libvirt.libvirtError('libvirt error msg')])
- }):
- ret.update({'changes': {}, 'result': False, 'comment': 'libvirt error msg'})
- self.assertDictEqual(virt.running('myvm'), ret)
+ # Test with existing guest, but start raising an error
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.update': MagicMock(return_value={'definition': False}),
+ 'virt.start': MagicMock(side_effect=[self.mock_libvirt.libvirtError('libvirt error msg')]),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {}}, 'result': False, 'comment': 'libvirt error msg'})
+ self.assertDictEqual(virt.running('myvm'), ret)
- # Working update case when running
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
- 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True})
- }):
- ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
- 'result': True,
- 'comment': 'Domain myvm updated, restart to fully apply the changes'})
- self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
-
- # Working update case when running with boot params
- boot = {
- 'kernel': '/root/f8-i386-vmlinuz',
- 'initrd': '/root/f8-i386-initrd',
- 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/'
- }
+ # Working update case when running
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
+ 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True}),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.running('myvm', cpu=2, update=True), ret)
+
+ # Working update case when running with boot params
+ boot = {
+ 'kernel': '/root/f8-i386-vmlinuz',
+ 'initrd': '/root/f8-i386-initrd',
+ 'cmdline': 'console=ttyS0 ks=http://example.com/f8-i386/os/'
+ }
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
- 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True})
- }):
- ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
- 'result': True,
- 'comment': 'Domain myvm updated, restart to fully apply the changes'})
- self.assertDictEqual(virt.running('myvm', update=True, boot=boot), ret)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
+ 'virt.update': MagicMock(return_value={'definition': True, 'cpu': True}),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated'})
+ self.assertDictEqual(virt.running('myvm', boot=boot, update=True), ret)
- # Working update case when stopped
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
- 'virt.start': MagicMock(return_value=0),
- 'virt.update': MagicMock(return_value={'definition': True})
- }):
- ret.update({'changes': {'myvm': 'Domain updated and started'},
- 'result': True,
- 'comment': 'Domain myvm updated and started'})
- self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+ # Working update case when stopped
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.start': MagicMock(return_value=0),
+ 'virt.update': MagicMock(return_value={'definition': True}),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'result': True,
+ 'comment': 'Domain myvm updated and started'})
+ self.assertDictEqual(virt.running('myvm', cpu=2, update=True), ret)
- # Failed live update case
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
- 'virt.update': MagicMock(return_value={'definition': True, 'cpu': False, 'errors': ['some error']})
- }):
- ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 'errors': ['some error']}},
- 'result': True,
- 'comment': 'Domain myvm updated, but some live update(s) failed'})
- self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+ # Failed live update case
+ update_mock = MagicMock(return_value={'definition': True, 'cpu': False, 'errors': ['some error']})
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
+ 'virt.update': update_mock,
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 'errors': ['some error']}},
+ 'result': True,
+ 'comment': 'Domain myvm updated with live update(s) failures'})
+ self.assertDictEqual(virt.running('myvm', cpu=2, update=True), ret)
+ update_mock.assert_called_with('myvm', cpu=2, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=False)
+
+ # Failed definition update case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
+ 'virt.update': MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')]),
+ 'virt.list_domains': MagicMock(return_value=['myvm']),
+ }):
+ ret.update({'changes': {},
+ 'result': False,
+ 'comment': 'error message'})
+ self.assertDictEqual(virt.running('myvm', cpu=2, update=True), ret)
- # Failed definition update case
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
- 'virt.update': MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')])
- }):
- ret.update({'changes': {},
- 'result': False,
- 'comment': 'error message'})
- self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
+ # Test dry-run mode
+ with patch.dict(virt.__opts__, {'test': True}):
+ # Guest defined case
+ init_mock = MagicMock(return_value=True)
+ start_mock = MagicMock(return_value=0)
+ list_mock = MagicMock(return_value=[])
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.init': init_mock,
+ 'virt.start': start_mock,
+ 'virt.list_domains': list_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'result': None,
+ 'comment': 'Domain myvm defined and started'})
+ disks = [{
+ 'name': 'system',
+ 'size': 8192,
+ 'overlay_image': True,
+ 'pool': 'default',
+ 'image': '/path/to/image.qcow2'
+ },
+ {
+ 'name': 'data',
+ 'size': 16834
+ }]
+ ifaces = [{
+ 'name': 'eth0',
+ 'mac': '01:23:45:67:89:AB'
+ },
+ {
+ 'name': 'eth1',
+ 'type': 'network',
+ 'source': 'admin'
+ }]
+ graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
+ self.assertDictEqual(virt.running('myvm',
+ cpu=2,
+ mem=2048,
+ os_type='linux',
+ arch='i686',
+ vm_type='qemu',
+ disk_profile='prod',
+ disks=disks,
+ nic_profile='prod',
+ interfaces=ifaces,
+ graphics=graphics,
+ seed=False,
+ install=False,
+ pub_key='/path/to/key.pub',
+ priv_key='/path/to/key',
+ connection='someconnection',
+ username='libvirtuser',
+ password='supersecret'), ret)
+ init_mock.assert_not_called()
+ start_mock.assert_not_called()
+
+ # Guest update case
+ update_mock = MagicMock(return_value={'definition': True})
+ start_mock = MagicMock(return_value=0)
+ list_mock = MagicMock(return_value=['myvm'])
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'stopped'}),
+ 'virt.start': start_mock,
+ 'virt.update': update_mock,
+ 'virt.list_domains': list_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': True, 'started': True}},
+ 'result': None,
+ 'comment': 'Domain myvm updated and started'})
+ self.assertDictEqual(virt.running('myvm', cpu=2, update=True), ret)
+ update_mock.assert_called_with('myvm', cpu=2, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=True)
+ start_mock.assert_not_called()
+
+ # No changes case
+ update_mock = MagicMock(return_value={'definition': False})
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.vm_state': MagicMock(return_value={'myvm': 'running'}),
+ 'virt.update': update_mock,
+ 'virt.list_domains': list_mock,
+ }):
+ ret.update({'changes': {'myvm': {'definition': False}},
+ 'result': True,
+ 'comment': 'Domain myvm exists and is running'})
+ self.assertDictEqual(virt.running('myvm', update=True), ret)
+ update_mock.assert_called_with('myvm', cpu=None, mem=None,
+ disk_profile=None, disks=None, nic_profile=None, interfaces=None,
+ graphics=None, live=True,
+ connection=None, username=None, password=None,
+ boot=None, test=True)
def test_stopped(self):
'''
@@ -599,92 +1042,506 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
self.assertDictEqual(virt.rebooted('myvm'), ret)
+ def test_network_defined(self):
+ '''
+ network_defined state test cases.
+ '''
+ ret = {'name': 'mynet', 'changes': {}, 'result': True, 'comment': ''}
+ with patch.dict(virt.__opts__, {'test': False}):
+ define_mock = MagicMock(return_value=True)
+ # Non-existing network case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(side_effect=[{}, {'mynet': {'active': False}}]),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network defined'},
+ 'comment': 'Network mynet defined'})
+ self.assertDictEqual(virt.network_defined('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ autostart=False,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ define_mock.assert_called_with('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ autostart=False,
+ start=False,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ connection='myconnection',
+ username='user',
+ password='secret')
+
+ # Case where there is nothing to be done
+ define_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {}, 'comment': 'Network mynet exists'})
+ self.assertDictEqual(virt.network_defined('mynet', 'br2', 'bridge'), ret)
+
+ # Error case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={}),
+ 'virt.network_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+ }):
+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
+ self.assertDictEqual(virt.network_defined('mynet', 'br2', 'bridge'), ret)
+
+ # Test cases with __opt__['test'] set to True
+ with patch.dict(virt.__opts__, {'test': True}):
+ ret.update({'result': None})
+
+ # Non-existing network case
+ define_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={}),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network defined'},
+ 'comment': 'Network mynet defined'})
+ self.assertDictEqual(virt.network_defined('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ autostart=False,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ define_mock.assert_not_called()
+
+ # Case where there is nothing to be done
+ define_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {}, 'comment': 'Network mynet exists', 'result': True})
+ self.assertDictEqual(virt.network_defined('mynet', 'br2', 'bridge'), ret)
+
+ # Error case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+ }):
+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
+ self.assertDictEqual(virt.network_defined('mynet', 'br2', 'bridge'), ret)
+
def test_network_running(self):
'''
network_running state test cases.
'''
ret = {'name': 'mynet', 'changes': {}, 'result': True, 'comment': ''}
- define_mock = MagicMock(return_value=True)
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.network_info': MagicMock(return_value={}),
- 'virt.network_define': define_mock
- }):
- ret.update({'changes': {'mynet': 'Network defined and started'},
- 'comment': 'Network mynet defined and started'})
- self.assertDictEqual(virt.network_running('mynet',
- 'br2',
- 'bridge',
- vport='openvswitch',
- tag=180,
- ipv4_config={
- 'cidr': '192.168.2.0/24',
- 'dhcp_ranges': [
- {'start': '192.168.2.10', 'end': '192.168.2.25'},
- {'start': '192.168.2.110', 'end': '192.168.2.125'},
- ]
- },
- ipv6_config={
- 'cidr': '2001:db8:ca2:2::1/64',
- 'dhcp_ranges': [
- {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
- ]
- },
- autostart=False,
- connection='myconnection',
- username='user',
- password='secret'), ret)
- define_mock.assert_called_with('mynet',
- 'br2',
- 'bridge',
- vport='openvswitch',
- tag=180,
- autostart=False,
- start=True,
- ipv4_config={
- 'cidr': '192.168.2.0/24',
- 'dhcp_ranges': [
- {'start': '192.168.2.10', 'end': '192.168.2.25'},
- {'start': '192.168.2.110', 'end': '192.168.2.125'},
- ]
- },
- ipv6_config={
- 'cidr': '2001:db8:ca2:2::1/64',
- 'dhcp_ranges': [
- {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
- ]
- },
- connection='myconnection',
- username='user',
- password='secret')
+ with patch.dict(virt.__opts__, {'test': False}):
+ define_mock = MagicMock(return_value=True)
+ start_mock = MagicMock(return_value=True)
+ # Non-existing network case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(side_effect=[{}, {'mynet': {'active': False}}]),
+ 'virt.network_define': define_mock,
+ 'virt.network_start': start_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network defined and started'},
+ 'comment': 'Network mynet defined and started'})
+ self.assertDictEqual(virt.network_running('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ autostart=False,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ define_mock.assert_called_with('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ autostart=False,
+ start=False,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ connection='myconnection',
+ username='user',
+ password='secret')
+ start_mock.assert_called_with('mynet',
+ connection='myconnection',
+ username='user',
+ password='secret')
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}),
- 'virt.network_define': define_mock,
- }):
- ret.update({'changes': {}, 'comment': 'Network mynet exists and is running'})
- self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
+ # Case where there is nothing to be done
+ define_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {}, 'comment': 'Network mynet exists and is running'})
+ self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
- start_mock = MagicMock(return_value=True)
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.network_info': MagicMock(return_value={'mynet': {'active': False}}),
- 'virt.network_start': start_mock,
- 'virt.network_define': define_mock,
- }):
- ret.update({'changes': {'mynet': 'Network started'}, 'comment': 'Network mynet started'})
- self.assertDictEqual(virt.network_running('mynet',
- 'br2',
- 'bridge',
+ # Network existing and stopped case
+ start_mock = MagicMock(return_value=True)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': False}}),
+ 'virt.network_start': start_mock,
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network started'}, 'comment': 'Network mynet exists and started'})
+ self.assertDictEqual(virt.network_running('mynet',
+ 'br2',
+ 'bridge',
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ start_mock.assert_called_with('mynet', connection='myconnection', username='user', password='secret')
+
+ # Error case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={}),
+ 'virt.network_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+ }):
+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
+ self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
+
+ # Test cases with __opt__['test'] set to True
+ with patch.dict(virt.__opts__, {'test': True}):
+ ret.update({'result': None})
+
+ # Non-existing network case
+ define_mock.reset_mock()
+ start_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={}),
+ 'virt.network_define': define_mock,
+ 'virt.network_start': start_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network defined and started'},
+ 'comment': 'Network mynet defined and started'})
+ self.assertDictEqual(virt.network_running('mynet',
+ 'br2',
+ 'bridge',
+ vport='openvswitch',
+ tag=180,
+ ipv4_config={
+ 'cidr': '192.168.2.0/24',
+ 'dhcp_ranges': [
+ {'start': '192.168.2.10', 'end': '192.168.2.25'},
+ {'start': '192.168.2.110', 'end': '192.168.2.125'},
+ ]
+ },
+ ipv6_config={
+ 'cidr': '2001:db8:ca2:2::1/64',
+ 'dhcp_ranges': [
+ {'start': '2001:db8:ca2:1::10', 'end': '2001:db8:ca2::1f'},
+ ]
+ },
+ autostart=False,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ define_mock.assert_not_called()
+ start_mock.assert_not_called()
+
+ # Case where there is nothing to be done
+ define_mock.reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': True}}),
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {}, 'comment': 'Network mynet exists and is running'})
+ self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
+
+ # Network existing and stopped case
+ start_mock = MagicMock(return_value=True)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(return_value={'mynet': {'active': False}}),
+ 'virt.network_start': start_mock,
+ 'virt.network_define': define_mock,
+ }):
+ ret.update({'changes': {'mynet': 'Network started'}, 'comment': 'Network mynet exists and started'})
+ self.assertDictEqual(virt.network_running('mynet',
+ 'br2',
+ 'bridge',
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ start_mock.assert_not_called()
+
+ # Error case
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.network_info': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+ }):
+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
+ self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
+
+ def test_pool_defined(self):
+ '''
+ pool_defined state test cases.
+ '''
+ ret = {'name': 'mypool', 'changes': {}, 'result': True, 'comment': ''}
+ mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build']}
+ with patch.dict(virt.__opts__, {'test': False}):
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(side_effect=[{}, {'mypool': {'state': 'stopped', 'autostart': True}}]),
+ 'virt.pool_define': mocks['define'],
+ 'virt.pool_build': mocks['build'],
+ 'virt.pool_set_autostart': mocks['autostart']
+ }):
+ ret.update({'changes': {'mypool': 'Pool defined, marked for autostart'},
+ 'comment': 'Pool mypool defined, marked for autostart'})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source={'devices': [{'path': '/dev/sda'}]},
+ transient=True,
+ autostart=True,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+ mocks['define'].assert_called_with('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source_devices=[{'path': '/dev/sda'}],
+ source_dir=None,
+ source_adapter=None,
+ source_hosts=None,
+ source_auth=None,
+ source_name=None,
+ source_format=None,
+ source_initiator=None,
+ transient=True,
+ start=False,
+ connection='myconnection',
+ username='user',
+ password='secret')
+ mocks['autostart'].assert_called_with('mypool',
+ state='on',
connection='myconnection',
username='user',
- password='secret'), ret)
- start_mock.assert_called_with('mynet', connection='myconnection', username='user', password='secret')
+ password='secret')
+ mocks['build'].assert_called_with('mypool',
+ connection='myconnection',
+ username='user',
+ password='secret')
- with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.network_info': MagicMock(return_value={}),
- 'virt.network_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
- }):
- ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
- self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
+ mocks['update'] = MagicMock(return_value=False)
+ for mock in mocks:
+ mocks[mock].reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped', 'autostart': True}}),
+ 'virt.pool_update': mocks['update'],
+ 'virt.pool_build': mocks['build'],
+ }):
+ ret.update({'changes': {}, 'comment': 'Pool mypool unchanged'})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ source={'devices': [{'path': '/dev/sda'}]}), ret)
+ mocks['build'].assert_not_called()
+
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={}),
+ 'virt.pool_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
+ }):
+ ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ source={'devices': [{'path': '/dev/sda'}]}), ret)
+
+ # Test case with update and autostart change on stopped pool
+ for mock in mocks:
+ mocks[mock].reset_mock()
+ mocks['update'] = MagicMock(return_value=True)
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'stopped', 'autostart': True}}),
+ 'virt.pool_update': mocks['update'],
+ 'virt.pool_set_autostart': mocks['autostart'],
+ 'virt.pool_build': mocks['build'],
+ }):
+ ret.update({'changes': {'mypool': 'Pool updated, built, autostart flag changed'},
+ 'comment': 'Pool mypool updated, built, autostart flag changed',
+ 'result': True})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ autostart=False,
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source={'devices': [{'path': '/dev/sda'}]}), ret)
+ mocks['build'].assert_called_with('mypool', connection=None, username=None, password=None)
+ mocks['autostart'].assert_called_with('mypool', state='off',
+ connection=None, username=None, password=None)
+ mocks['update'].assert_called_with('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source_devices=[{'path': '/dev/sda'}],
+ source_dir=None,
+ source_adapter=None,
+ source_hosts=None,
+ source_auth=None,
+ source_name=None,
+ source_format=None,
+ source_initiator=None,
+ connection=None,
+ username=None,
+ password=None)
+
+ # test case with update and no autostart change on running pool
+ for mock in mocks:
+ mocks[mock].reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': False}}),
+ 'virt.pool_update': mocks['update'],
+ 'virt.pool_build': mocks['build'],
+ }):
+ ret.update({'changes': {'mypool': 'Pool updated'},
+ 'comment': 'Pool mypool updated',
+ 'result': True})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ autostart=False,
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source={'devices': [{'path': '/dev/sda'}]}), ret)
+ mocks['update'].assert_called_with('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source_devices=[{'path': '/dev/sda'}],
+ source_dir=None,
+ source_adapter=None,
+ source_hosts=None,
+ source_auth=None,
+ source_name=None,
+ source_format=None,
+ source_initiator=None,
+ connection=None,
+ username=None,
+ password=None)
+
+ with patch.dict(virt.__opts__, {'test': True}):
+ # test case with test=True and no change
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}),
+ 'virt.pool_update': MagicMock(return_value=False),
+ }):
+ ret.update({'changes': {}, 'comment': 'Pool mypool unchanged',
+ 'result': True})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ source={'devices': [{'path': '/dev/sda'}]}), ret)
+
+ # test case with test=True and pool to be defined
+ for mock in mocks:
+ mocks[mock].reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={}),
+ }):
+ ret.update({'changes': {'mypool': 'Pool defined, marked for autostart'},
+ 'comment': 'Pool mypool defined, marked for autostart',
+ 'result': None})
+ self.assertDictEqual(virt.pool_defined('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source={'devices': [{'path': '/dev/sda'}]},
+ transient=True,
+ autostart=True,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
def test_pool_running(self):
'''
@@ -694,14 +1551,14 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start', 'stop']}
with patch.dict(virt.__opts__, {'test': False}):
with patch.dict(virt.__salt__, { # pylint: disable=no-member
- 'virt.pool_info': MagicMock(return_value={}),
+ 'virt.pool_info': MagicMock(side_effect=[{}, {'mypool': {'state': 'stopped', 'autostart': True}}]),
'virt.pool_define': mocks['define'],
'virt.pool_build': mocks['build'],
'virt.pool_start': mocks['start'],
'virt.pool_set_autostart': mocks['autostart']
}):
- ret.update({'changes': {'mypool': 'Pool defined, started and marked for autostart'},
- 'comment': 'Pool mypool defined, started and marked for autostart'})
+ ret.update({'changes': {'mypool': 'Pool defined, marked for autostart, started'},
+ 'comment': 'Pool mypool defined, marked for autostart, started'})
self.assertDictEqual(virt.pool_running('mypool',
ptype='logical',
target='/dev/base',
@@ -754,7 +1611,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}),
'virt.pool_update': MagicMock(return_value=False),
}):
- ret.update({'changes': {}, 'comment': 'Pool mypool unchanged and is running'})
+ ret.update({'changes': {}, 'comment': 'Pool mypool already running'})
self.assertDictEqual(virt.pool_running('mypool',
ptype='logical',
target='/dev/base',
@@ -797,8 +1654,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
'virt.pool_build': mocks['build'],
'virt.pool_start': mocks['start']
}):
- ret.update({'changes': {'mypool': 'Pool updated, built, autostart flag changed and started'},
- 'comment': 'Pool mypool updated, built, autostart flag changed and started',
+ ret.update({'changes': {'mypool': 'Pool updated, built, autostart flag changed, started'},
+ 'comment': 'Pool mypool updated, built, autostart flag changed, started',
'result': True})
self.assertDictEqual(virt.pool_running('mypool',
ptype='logical',
@@ -842,8 +1699,8 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
'virt.pool_start': mocks['start'],
'virt.pool_stop': mocks['stop']
}):
- ret.update({'changes': {'mypool': 'Pool updated, built and restarted'},
- 'comment': 'Pool mypool updated, built and restarted',
+ ret.update({'changes': {'mypool': 'Pool updated, built, restarted'},
+ 'comment': 'Pool mypool updated, built, restarted',
'result': True})
self.assertDictEqual(virt.pool_running('mypool',
ptype='logical',
@@ -882,7 +1739,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
'virt.pool_info': MagicMock(return_value={'mypool': {'state': 'running', 'autostart': True}}),
'virt.pool_update': MagicMock(return_value=False),
}):
- ret.update({'changes': {}, 'comment': 'Pool mypool unchanged and is running',
+ ret.update({'changes': {}, 'comment': 'Pool mypool already running',
'result': True})
self.assertDictEqual(virt.pool_running('mypool',
ptype='logical',
@@ -905,6 +1762,29 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
target='/dev/base',
source={'devices': [{'path': '/dev/sda'}]}), ret)
+ # test case with test=True and pool to be defined
+ for mock in mocks:
+ mocks[mock].reset_mock()
+ with patch.dict(virt.__salt__, { # pylint: disable=no-member
+ 'virt.pool_info': MagicMock(return_value={}),
+ }):
+ ret.update({'changes': {'mypool': 'Pool defined, marked for autostart, started'},
+ 'comment': 'Pool mypool defined, marked for autostart, started',
+ 'result': None})
+ self.assertDictEqual(virt.pool_running('mypool',
+ ptype='logical',
+ target='/dev/base',
+ permissions={'mode': '0770',
+ 'owner': 1000,
+ 'group': 100,
+ 'label': 'seclabel'},
+ source={'devices': [{'path': '/dev/sda'}]},
+ transient=True,
+ autostart=True,
+ connection='myconnection',
+ username='user',
+ password='secret'), ret)
+
def test_pool_deleted(self):
'''
Test the pool_deleted state
--
2.16.4