mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 16:45:27 +00:00
Merge pull request #48421 from cbosdo/virt-running
Virt states improvements
This commit is contained in:
commit
2f2a0ee320
@ -694,16 +694,32 @@ def _gen_net_xml(name,
|
||||
|
||||
def _gen_pool_xml(name,
|
||||
ptype,
|
||||
target,
|
||||
source=None):
|
||||
target=None,
|
||||
permissions=None,
|
||||
source_devices=None,
|
||||
source_dir=None,
|
||||
source_adapter=None,
|
||||
source_hosts=None,
|
||||
source_auth=None,
|
||||
source_name=None,
|
||||
source_format=None):
|
||||
'''
|
||||
Generate the XML string to define a libvirt storage pool
|
||||
'''
|
||||
hosts = [host.split(':') for host in source_hosts or []]
|
||||
context = {
|
||||
'name': name,
|
||||
'ptype': ptype,
|
||||
'target': target,
|
||||
'source': source,
|
||||
'target': {'path': target, 'permissions': permissions},
|
||||
'source': {
|
||||
'devices': source_devices or [],
|
||||
'dir': source_dir,
|
||||
'adapter': source_adapter,
|
||||
'hosts': [{'name': host[0], 'port': host[1] if len(host) > 1 else None} for host in hosts],
|
||||
'auth': source_auth,
|
||||
'name': source_name,
|
||||
'format': source_format
|
||||
}
|
||||
}
|
||||
fn_ = 'libvirt_pool.jinja'
|
||||
try:
|
||||
@ -3909,7 +3925,7 @@ def cpu_baseline(full=False, migratable=False, out='libvirt', **kwargs):
|
||||
return cpu.toxml()
|
||||
|
||||
|
||||
def net_define(name, bridge, forward, **kwargs):
|
||||
def network_define(name, bridge, forward, **kwargs):
|
||||
'''
|
||||
Create libvirt network.
|
||||
|
||||
@ -3928,7 +3944,7 @@ def net_define(name, bridge, forward, **kwargs):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' virt.net_define network main bridge openvswitch
|
||||
salt '*' virt.network_define network main bridge openvswitch
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
'''
|
||||
@ -4146,85 +4162,166 @@ def network_set_autostart(name, state='on', **kwargs):
|
||||
conn.close()
|
||||
|
||||
|
||||
def pool_define_build(name, **kwargs):
|
||||
def pool_define(name,
|
||||
ptype,
|
||||
target=None,
|
||||
permissions=None,
|
||||
source_devices=None,
|
||||
source_dir=None,
|
||||
source_adapter=None,
|
||||
source_hosts=None,
|
||||
source_auth=None,
|
||||
source_name=None,
|
||||
source_format=None,
|
||||
transient=False,
|
||||
start=True, # pylint: disable=redefined-outer-name
|
||||
**kwargs):
|
||||
'''
|
||||
Create libvirt pool.
|
||||
|
||||
:param name: Pool name
|
||||
:param ptype: Pool type
|
||||
:param target: Pool path target
|
||||
:param source: Pool dev source
|
||||
:param autostart: Pool autostart (default True)
|
||||
:param ptype:
|
||||
Pool type. See `libvirt documentation <https://libvirt.org/storage.html>`_ for the
|
||||
possible values.
|
||||
:param target: Pool full path target
|
||||
:param permissions:
|
||||
Permissions to set on the target folder. This is mostly used for filesystem-based
|
||||
pool types. See :ref:`pool-define-permissions` for more details on this structure.
|
||||
:param source_devices:
|
||||
List of source devices for pools backed by physical devices. (Default: ``None``)
|
||||
|
||||
Each item in the list is a dictionary with ``path`` and optionally ``part_separator``
|
||||
keys. The path is the qualified name for iSCSI devices.
|
||||
|
||||
Report to `this libvirt page <https://libvirt.org/formatstorage.html#StoragePool>`_
|
||||
for more informations on the use of ``part_separator``
|
||||
:param source_dir:
|
||||
Path to the source directory for pools of type ``dir``, ``netfs`` or ``gluster``.
|
||||
(Default: ``None``)
|
||||
:param source_adapter:
|
||||
SCSI source definition. The value is a dictionary with ``type``, ``name``, ``parent``,
|
||||
``managed``, ``parent_wwnn``, ``parent_wwpn``, ``parent_fabric_wwn``, ``wwnn``, ``wwpn``
|
||||
and ``parent_address`` keys.
|
||||
|
||||
The ``parent_address`` value is a dictionary with ``unique_id`` and ``address`` keys.
|
||||
The address represents a PCI address and is itself a dictionary with ``domain``, ``bus``,
|
||||
``slot`` and ``function`` properties.
|
||||
Report to `this libvirt page <https://libvirt.org/formatstorage.html#StoragePool>`_
|
||||
for the meaning and possible values of these properties.
|
||||
:param source_hosts:
|
||||
List of source for pools backed by storage from remote servers. Each item is the hostname
|
||||
optionally followed by the port separated by a colon. (Default: ``None``)
|
||||
:param source_auth:
|
||||
Source authentication details. (Default: ``None``)
|
||||
|
||||
The value is a dictionary with ``type``, ``username`` and ``secret`` keys. The type
|
||||
can be one of ``ceph`` for Ceph RBD or ``chap`` for iSCSI sources.
|
||||
|
||||
The ``secret`` value links to a libvirt secret object. It is a dictionary with
|
||||
``type`` and ``value`` keys. The type value can be either ``uuid`` or ``usage``.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
source_auth={
|
||||
'type': 'ceph',
|
||||
'username': 'admin',
|
||||
'secret': {
|
||||
'type': 'uuid',
|
||||
'uuid': '2ec115d7-3a88-3ceb-bc12-0ac909a6fd87'
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
source_auth={
|
||||
'type': 'chap',
|
||||
'username': 'myname',
|
||||
'secret': {
|
||||
'type': 'usage',
|
||||
'uuid': 'mycluster_myname'
|
||||
}
|
||||
}
|
||||
|
||||
:param source_name:
|
||||
Identifier of name-based sources.
|
||||
:param source_format:
|
||||
String representing the source format. The possible values are depending on the
|
||||
source type. See `libvirt documentation <https://libvirt.org/storage.html>`_ for
|
||||
the possible values.
|
||||
:param start: Pool start (default True)
|
||||
:param transient:
|
||||
When ``True``, the pool will be automatically undefined after being stopped.
|
||||
Note that a transient pool will force ``start`` to ``True``. (Default: ``False``)
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
:param username: username to connect with, overriding defaults
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
CLI Example:
|
||||
.. _pool-define-permissions:
|
||||
|
||||
.. rubric:: Permissions definition
|
||||
|
||||
The permissions are described by a dictionary containing the following keys:
|
||||
|
||||
mode
|
||||
The octal representation of the permissions. (Default: `0711`)
|
||||
|
||||
owner
|
||||
the numeric user ID of the owner. (Default: from the parent folder)
|
||||
|
||||
group
|
||||
the numeric ID of the group. (Default: from the parent folder)
|
||||
|
||||
label
|
||||
the SELinux label. (Default: `None`)
|
||||
|
||||
|
||||
.. rubric:: CLI Example:
|
||||
|
||||
Local folder pool:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' virt.pool_define base logical base
|
||||
salt '*' virt.pool_define somepool dir target=/srv/mypool \
|
||||
permissions="{'mode': '0744' 'ower': 107, 'group': 107 }"
|
||||
|
||||
CIFS backed pool:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' virt.pool_define myshare netfs source_format=cifs \
|
||||
source_dir=samba_share source_hosts="['example.com']" target=/mnt/cifs
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
'''
|
||||
exist = False
|
||||
update = False
|
||||
conn = __get_conn(**kwargs)
|
||||
ptype = kwargs.pop('ptype', None)
|
||||
target = kwargs.pop('target', None)
|
||||
source = kwargs.pop('source', None)
|
||||
autostart = kwargs.pop('autostart', True)
|
||||
starting = kwargs.pop('start', True)
|
||||
pool_xml = _gen_pool_xml(
|
||||
name,
|
||||
ptype,
|
||||
target,
|
||||
source,
|
||||
permissions=permissions,
|
||||
source_devices=source_devices,
|
||||
source_dir=source_dir,
|
||||
source_adapter=source_adapter,
|
||||
source_hosts=source_hosts,
|
||||
source_auth=source_auth,
|
||||
source_name=source_name,
|
||||
source_format=source_format
|
||||
)
|
||||
try:
|
||||
conn.storagePoolDefineXML(pool_xml)
|
||||
except libvirtError as err:
|
||||
log.warning(err)
|
||||
if err.get_error_code() == libvirt.VIR_ERR_STORAGE_POOL_BUILT or libvirt.VIR_ERR_OPERATION_FAILED:
|
||||
exist = True
|
||||
if transient:
|
||||
pool = conn.storagePoolCreateXML(pool_xml)
|
||||
else:
|
||||
conn.close()
|
||||
raise err # a real error we should report upwards
|
||||
try:
|
||||
pool = conn.storagePoolLookupByName(name)
|
||||
pool = conn.storagePoolDefineXML(pool_xml)
|
||||
if start:
|
||||
pool.create()
|
||||
except libvirtError as err:
|
||||
log.warning(err)
|
||||
conn.close()
|
||||
raise err # a real error we should report upwards
|
||||
|
||||
if pool is None:
|
||||
finally:
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
if (starting is True or autostart is True) and pool.isActive() != 1:
|
||||
if exist is True:
|
||||
update = True
|
||||
pool.create()
|
||||
else:
|
||||
pool.create(libvirt.VIR_STORAGE_POOL_CREATE_WITH_BUILD)
|
||||
|
||||
if autostart is True and pool.autostart() != 1:
|
||||
if exist is True:
|
||||
update = True
|
||||
pool.setAutostart(int(autostart))
|
||||
elif autostart is False and pool.autostart() == 1:
|
||||
if exist is True:
|
||||
update = True
|
||||
pool.setAutostart(int(autostart))
|
||||
|
||||
conn.close()
|
||||
|
||||
if exist is True:
|
||||
if update is True:
|
||||
return (True, 'Pool exist', 'Pool update')
|
||||
return (True, 'Pool exist')
|
||||
|
||||
# libvirt function will raise a libvirtError in case of failure
|
||||
return True
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ except ImportError:
|
||||
import salt.utils.args
|
||||
import salt.utils.files
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.versions
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import 3rd-party libs
|
||||
@ -144,7 +145,8 @@ def keys(name, basepath='/etc/pki', **kwargs):
|
||||
return ret
|
||||
|
||||
|
||||
def _virt_call(domain, function, section, comment, **kwargs):
|
||||
def _virt_call(domain, function, section, comment,
|
||||
connection=None, username=None, password=None, **kwargs):
|
||||
'''
|
||||
Helper to call the virt functions. Wildcards supported.
|
||||
|
||||
@ -160,7 +162,11 @@ def _virt_call(domain, function, section, comment, **kwargs):
|
||||
ignored_domains = list()
|
||||
for targeted_domain in targeted_domains:
|
||||
try:
|
||||
response = __salt__['virt.{0}'.format(function)](targeted_domain, **kwargs)
|
||||
response = __salt__['virt.{0}'.format(function)](targeted_domain,
|
||||
connection=connection,
|
||||
username=username,
|
||||
password=password,
|
||||
**kwargs)
|
||||
if isinstance(response, dict):
|
||||
response = response['name']
|
||||
changed_domains.append({'domain': targeted_domain, function: response})
|
||||
@ -178,54 +184,183 @@ def _virt_call(domain, function, section, comment, **kwargs):
|
||||
return ret
|
||||
|
||||
|
||||
def stopped(name):
|
||||
def stopped(name, connection=None, username=None, password=None):
|
||||
'''
|
||||
Stops a VM by shutting it down nicely.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
virt.stopped
|
||||
'''
|
||||
|
||||
return _virt_call(name, 'shutdown', 'stopped', "Machine has been shut down")
|
||||
return _virt_call(name, 'shutdown', 'stopped', "Machine has been shut down",
|
||||
connection=connection, username=username, password=password)
|
||||
|
||||
|
||||
def powered_off(name):
|
||||
def powered_off(name, connection=None, username=None, password=None):
|
||||
'''
|
||||
Stops a VM by power off.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
virt.stopped
|
||||
'''
|
||||
|
||||
return _virt_call(name, 'stop', 'unpowered', 'Machine has been powered off')
|
||||
return _virt_call(name, 'stop', 'unpowered', 'Machine has been powered off',
|
||||
connection=connection, username=username, password=password)
|
||||
|
||||
|
||||
def running(name, **kwargs):
|
||||
def running(name,
|
||||
cpu=None,
|
||||
mem=None,
|
||||
image=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):
|
||||
'''
|
||||
Starts an existing guest, or defines and starts a new VM with specified arguments.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
: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 image: disk image to use for the first disk of the new VM
|
||||
|
||||
.. deprecated:: Fluorine
|
||||
: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.
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param disk_profile:
|
||||
Name of the disk profile to use for the new virtual machine
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
: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.
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param nic_profile:
|
||||
Name of the network interfaces profile to use for the new virtual machine
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
: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.
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param graphics:
|
||||
Graphics device to create for the new virtual machine.
|
||||
See :ref:`init-graphics-def` for more details on this dictionary
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param saltenv:
|
||||
Fileserver environment (Default: ``'base'``).
|
||||
See :mod:`cp module for more details <salt.modules.cp>`
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param seed: ``True`` to seed the disk image. Only used when the ``image`` parameter is provided.
|
||||
(Default: ``True``)
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param install: install salt minion if absent (Default: ``True``)
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param pub_key: public key to seed with (Default: ``None``)
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param priv_key: public key to seed with (Default: ``None``)
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param seed_cmd: Salt command to execute to seed the image. (Default: ``'seed.apply'``)
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
|
||||
.. rubric:: Example States
|
||||
|
||||
Make sure an already-defined virtual machine called ``domain_name`` is running:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
virt.running
|
||||
|
||||
Do the same, but define the virtual machine if needed:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
virt.running:
|
||||
- cpu: 2
|
||||
- mem: 2048
|
||||
- eth0_mac: 00:00:6a:53:00:e3
|
||||
- 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
|
||||
|
||||
'''
|
||||
|
||||
@ -235,11 +370,6 @@ def running(name, **kwargs):
|
||||
'comment': '{0} is running'.format(name)
|
||||
}
|
||||
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
cpu = kwargs.pop('cpu', False)
|
||||
mem = kwargs.pop('mem', False)
|
||||
image = kwargs.pop('image', False)
|
||||
|
||||
try:
|
||||
try:
|
||||
__salt__['virt.vm_state'](name)
|
||||
@ -250,8 +380,29 @@ def running(name, **kwargs):
|
||||
else:
|
||||
ret['comment'] = 'Domain {0} exists and is running'.format(name)
|
||||
except CommandExecutionError:
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
__salt__['virt.init'](name, cpu=cpu, mem=mem, image=image, **kwargs)
|
||||
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,
|
||||
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)
|
||||
ret['changes'][name] = 'Domain defined and started'
|
||||
ret['comment'] = 'Domain {0} defined and started'.format(name)
|
||||
except libvirt.libvirtError as err:
|
||||
@ -262,12 +413,22 @@ def running(name, **kwargs):
|
||||
return ret
|
||||
|
||||
|
||||
def snapshot(name, suffix=None):
|
||||
def snapshot(name, suffix=None, connection=None, username=None, password=None):
|
||||
'''
|
||||
Takes a snapshot of a particular VM or by a UNIX-style wildcard.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
@ -279,21 +440,32 @@ def snapshot(name, suffix=None):
|
||||
- suffix: periodic
|
||||
'''
|
||||
|
||||
return _virt_call(name, 'snapshot', 'saved', 'Snapshot has been taken', suffix=suffix)
|
||||
return _virt_call(name, 'snapshot', 'saved', 'Snapshot has been taken', suffix=suffix,
|
||||
connection=connection, username=username, password=password)
|
||||
|
||||
|
||||
# Deprecated states
|
||||
def rebooted(name):
|
||||
def rebooted(name, connection=None, username=None, password=None):
|
||||
'''
|
||||
Reboots VMs
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
:param name:
|
||||
:return:
|
||||
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
'''
|
||||
|
||||
return _virt_call(name, 'reboot', 'rebooted', "Machine has been rebooted")
|
||||
return _virt_call(name, 'reboot', 'rebooted', "Machine has been rebooted",
|
||||
connection=connection, username=username, password=password)
|
||||
|
||||
|
||||
def unpowered(name):
|
||||
@ -396,10 +568,28 @@ def reverted(name, snapshot=None, cleanup=False): # pylint: disable=redefined-o
|
||||
return ret
|
||||
|
||||
|
||||
def network_define(name, bridge, forward, **kwargs):
|
||||
def network_running(name,
|
||||
bridge,
|
||||
forward,
|
||||
vport=None,
|
||||
tag=None,
|
||||
autostart=True,
|
||||
connection=None,
|
||||
username=None,
|
||||
password=None):
|
||||
'''
|
||||
Defines and starts a new network with specified arguments.
|
||||
|
||||
:param connection: libvirt connection URI, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param username: username to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
:param password: password to connect with, overriding defaults
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
domain_name:
|
||||
@ -414,42 +604,75 @@ def network_define(name, bridge, forward, **kwargs):
|
||||
- vport: openvswitch
|
||||
- tag: 180
|
||||
- autostart: True
|
||||
- start: True
|
||||
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'result': True,
|
||||
'comment': ''
|
||||
}
|
||||
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
vport = kwargs.pop('vport', None)
|
||||
tag = kwargs.pop('tag', None)
|
||||
autostart = kwargs.pop('autostart', True)
|
||||
start = kwargs.pop('start', True)
|
||||
|
||||
try:
|
||||
result = __salt__['virt.net_define'](name, bridge, forward, vport, tag=tag, autostart=autostart, start=start)
|
||||
if result:
|
||||
ret['changes'][name] = 'Network {0} has been created'.format(name)
|
||||
ret['result'] = True
|
||||
info = __salt__['virt.network_info'](name, connection=connection, username=username, password=password)
|
||||
if info:
|
||||
if info['active']:
|
||||
ret['comment'] = 'Network {0} exists and is running'.format(name)
|
||||
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:
|
||||
ret['comment'] = 'Network {0} created fail'.format(name)
|
||||
__salt__['virt.network_define'](name,
|
||||
bridge,
|
||||
forward,
|
||||
vport,
|
||||
tag=tag,
|
||||
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:
|
||||
if err.get_error_code() == libvirt.VIR_ERR_NETWORK_EXIST or libvirt.VIR_ERR_OPERATION_FAILED:
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The network already exist'
|
||||
else:
|
||||
ret['comment'] = err.get_error_message()
|
||||
ret['result'] = False
|
||||
ret['comment'] = err.get_error_message()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def pool_define(name, **kwargs):
|
||||
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:: Fluorine
|
||||
|
||||
: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:
|
||||
@ -459,44 +682,73 @@ def pool_define(name, **kwargs):
|
||||
|
||||
pool_name:
|
||||
virt.pool_define:
|
||||
- ptype: logical
|
||||
- target: pool
|
||||
- source: sda1
|
||||
- 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
|
||||
- start: True
|
||||
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'result': True,
|
||||
'comment': ''
|
||||
}
|
||||
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
ptype = kwargs.pop('ptype', None)
|
||||
target = kwargs.pop('target', None)
|
||||
source = kwargs.pop('source', None)
|
||||
autostart = kwargs.pop('autostart', True)
|
||||
start = kwargs.pop('start', True)
|
||||
|
||||
try:
|
||||
result = __salt__['virt.pool_define_build'](name, ptype=ptype, target=target,
|
||||
source=source, autostart=autostart, start=start)
|
||||
if result:
|
||||
if 'Pool exist' in result:
|
||||
if 'Pool update' in result:
|
||||
ret['changes'][name] = 'Pool {0} has been updated'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Pool {0} already exist'.format(name)
|
||||
info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password)
|
||||
if info:
|
||||
if info['state'] == 'running':
|
||||
ret['comment'] = 'Pool {0} exists and is running'.format(name)
|
||||
else:
|
||||
ret['changes'][name] = 'Pool {0} has been created'.format(name)
|
||||
ret['result'] = True
|
||||
__salt__['virt.pool_start'](name, connection=connection, username=username, password=password)
|
||||
ret['changes'][name] = 'Pool started'
|
||||
ret['comment'] = 'Pool {0} started'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Pool {0} created fail'.format(name)
|
||||
__salt__['virt.pool_define'](name,
|
||||
ptype=ptype,
|
||||
target=target,
|
||||
permissions=permissions,
|
||||
source_devices=(source or {}).get('devices', None),
|
||||
source_dir=(source or {}).get('dir', None),
|
||||
source_adapter=(source or {}).get('adapter', None),
|
||||
source_hosts=(source or {}).get('hosts', None),
|
||||
source_auth=(source or {}).get('auth', None),
|
||||
source_name=(source or {}).get('name', None),
|
||||
source_format=(source or {}).get('format', None),
|
||||
transient=transient,
|
||||
start=True,
|
||||
connection=connection,
|
||||
username=username,
|
||||
password=password)
|
||||
if autostart:
|
||||
__salt__['virt.pool_set_autostart'](name,
|
||||
state='on' if autostart else 'off',
|
||||
connection=connection,
|
||||
username=username,
|
||||
password=password)
|
||||
|
||||
__salt__['virt.pool_build'](name,
|
||||
connection=connection,
|
||||
username=username,
|
||||
password=password)
|
||||
|
||||
__salt__['virt.pool_start'](name,
|
||||
connection=connection,
|
||||
username=username,
|
||||
password=password)
|
||||
ret['changes'][name] = 'Pool defined and started'
|
||||
ret['comment'] = 'Pool {0} defined and started'.format(name)
|
||||
except libvirt.libvirtError as err:
|
||||
if err.get_error_code() == libvirt.VIR_ERR_STORAGE_POOL_BUILT or libvirt.VIR_ERR_OPERATION_FAILED:
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'The pool already exist'
|
||||
ret['comment'] = err.get_error_message()
|
||||
ret['result'] = False
|
||||
|
||||
return ret
|
||||
|
@ -1,9 +1,64 @@
|
||||
<pool type='{{ ptype }}'>
|
||||
<name>{{ name }}</name>
|
||||
{% if target.path or target.permissions %}
|
||||
<target>
|
||||
<path>/dev/{{ target }}</path>
|
||||
</target>{% if source != None %}
|
||||
{% if target.path %}
|
||||
<path>{{ target.path }}</path>
|
||||
{% endif %}
|
||||
{% if target.permissions %}
|
||||
<permissions>
|
||||
{% for key in ['mode', 'owner', 'group', 'label'] %}
|
||||
{% if key in target.permissions %}
|
||||
<{{ key }}>{{ target.permissions[key] }}</{{ key }}>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</permissions>
|
||||
{% endif %}
|
||||
</target>
|
||||
{% endif %}
|
||||
{% if source %}
|
||||
<source>
|
||||
<device path='/dev/{{ source }}'/>
|
||||
</source>{% endif %}
|
||||
</pool>
|
||||
{% if ptype in ['fs', 'logical', 'disk', 'iscsi', 'zfs', 'vstorage'] %}
|
||||
{% for device in source.devices %}
|
||||
<device path='{{ device.path }}'
|
||||
{% if 'part_separator' in device %}part_separator='{{ device.part_separator }}'{% endif %}/>
|
||||
{% endfor %}
|
||||
{% elif ptype in ['dir', 'netfs', 'gluster'] %}
|
||||
<dir path='{{ source.dir }}'/>
|
||||
{% elif ptype == 'scsi' %}
|
||||
<adapter type='{{ source.adapter.type }}'
|
||||
{% for key in ['name', 'parent', 'managed', 'parent_wwnn', 'parent_wwpn', 'parent_fabric_wwn', 'wwnn', 'wwpn'] %}
|
||||
{% if key in source.adapter %}{{ key }}='{{ source.adapter[key] }}'{% endif %}
|
||||
{% endfor %}>
|
||||
{% if 'parent_address' in source.adapter %}
|
||||
<parentaddr
|
||||
{% if 'unique_id' in source.adapter.parent_address %}
|
||||
unique_id='{{ source.adapter.parent_address.unique_id }}'
|
||||
{% endif %}>
|
||||
<address
|
||||
{% for key in source.adapter.parent_address.address %}
|
||||
{{ key }}='{{ source.adapter.parent_address.address[key] }}'
|
||||
{% endfor %}/>
|
||||
</parentaddr>
|
||||
{% endif %}
|
||||
</adapter>
|
||||
{% endif %}
|
||||
{% if ptype in ['netfs', 'iscsi', 'rbd', 'sheepdog', 'gluster'] and source.hosts %}
|
||||
{% for host in source.hosts %}
|
||||
<host name='{{ host.name }}' {% if host.port %}port='{{ host.port }}'{% endif %}/>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if ptype in ['iscsi', 'rbd'] and source.auth %}
|
||||
<auth type='{{source.auth.type}}' username='{{ source.auth.username }}'>
|
||||
<secret type='{{ source.auth.secret.type }}' {{ source.auth.secret.type }}='{{source.auth.secret.value}}'/>
|
||||
</auth>
|
||||
{% endif %}
|
||||
{% if ptype in ['logical', 'rbd', 'sheepdog', 'gluster'] and source.name %}
|
||||
<name>{{ source.name }}</name>
|
||||
{% endif %}
|
||||
{% if ptype in ['fs', 'netfs', 'logical', 'disk'] and source.format %}
|
||||
<format type='{{ source.format }}'/>
|
||||
{% endif %}
|
||||
</source>
|
||||
{% endif %}
|
||||
</pool>
|
||||
|
@ -1581,7 +1581,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'''
|
||||
Test virt._gen_pool_xml()
|
||||
'''
|
||||
xml_data = virt._gen_pool_xml('pool', 'logical', 'base')
|
||||
xml_data = virt._gen_pool_xml('pool', 'logical', '/dev/base')
|
||||
root = ET.fromstring(xml_data)
|
||||
self.assertEqual(root.find('name').text, 'pool')
|
||||
self.assertEqual(root.attrib['type'], 'logical')
|
||||
@ -1591,13 +1591,120 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'''
|
||||
Test virt._gen_pool_xml() with a source device
|
||||
'''
|
||||
xml_data = virt._gen_pool_xml('pool', 'logical', 'base', 'sda')
|
||||
xml_data = virt._gen_pool_xml('pool', 'logical', '/dev/base', source_devices=[{'path': '/dev/sda'}])
|
||||
root = ET.fromstring(xml_data)
|
||||
self.assertEqual(root.find('name').text, 'pool')
|
||||
self.assertEqual(root.attrib['type'], 'logical')
|
||||
self.assertEqual(root.find('target/path').text, '/dev/base')
|
||||
self.assertEqual(root.find('source/device').attrib['path'], '/dev/sda')
|
||||
|
||||
def test_pool_with_scsi(self):
|
||||
'''
|
||||
Test virt._gen_pool_xml() with a SCSI source
|
||||
'''
|
||||
xml_data = virt._gen_pool_xml('pool',
|
||||
'scsi',
|
||||
'/dev/disk/by-path',
|
||||
source_devices=[{'path': '/dev/sda'}],
|
||||
source_adapter={
|
||||
'type': 'scsi_host',
|
||||
'parent_address': {
|
||||
'unique_id': 5,
|
||||
'address': {
|
||||
'domain': '0x0000',
|
||||
'bus': '0x00',
|
||||
'slot': '0x1f',
|
||||
'function': '0x2'
|
||||
}
|
||||
}
|
||||
},
|
||||
source_name='srcname')
|
||||
root = ET.fromstring(xml_data)
|
||||
self.assertEqual(root.find('name').text, 'pool')
|
||||
self.assertEqual(root.attrib['type'], 'scsi')
|
||||
self.assertEqual(root.find('target/path').text, '/dev/disk/by-path')
|
||||
self.assertEqual(root.find('source/device'), None)
|
||||
self.assertEqual(root.find('source/name'), None)
|
||||
self.assertEqual(root.find('source/adapter').attrib['type'], 'scsi_host')
|
||||
self.assertEqual(root.find('source/adapter/parentaddr').attrib['unique_id'], '5')
|
||||
self.assertEqual(root.find('source/adapter/parentaddr/address').attrib['domain'], '0x0000')
|
||||
self.assertEqual(root.find('source/adapter/parentaddr/address').attrib['bus'], '0x00')
|
||||
self.assertEqual(root.find('source/adapter/parentaddr/address').attrib['slot'], '0x1f')
|
||||
self.assertEqual(root.find('source/adapter/parentaddr/address').attrib['function'], '0x2')
|
||||
|
||||
def test_pool_with_rbd(self):
|
||||
'''
|
||||
Test virt._gen_pool_xml() with an RBD source
|
||||
'''
|
||||
xml_data = virt._gen_pool_xml('pool',
|
||||
'rbd',
|
||||
source_devices=[{'path': '/dev/sda'}],
|
||||
source_hosts=['1.2.3.4', 'my.ceph.monitor:69'],
|
||||
source_auth={
|
||||
'type': 'ceph',
|
||||
'username': 'admin',
|
||||
'secret': {
|
||||
'type': 'uuid',
|
||||
'value': 'someuuid'
|
||||
}
|
||||
},
|
||||
source_name='srcname',
|
||||
source_adapter={'type': 'scsi_host', 'name': 'host0'},
|
||||
source_dir='/some/dir',
|
||||
source_format='fmt')
|
||||
root = ET.fromstring(xml_data)
|
||||
self.assertEqual(root.find('name').text, 'pool')
|
||||
self.assertEqual(root.attrib['type'], 'rbd')
|
||||
self.assertEqual(root.find('target'), None)
|
||||
self.assertEqual(root.find('source/device'), None)
|
||||
self.assertEqual(root.find('source/name').text, 'srcname')
|
||||
self.assertEqual(root.find('source/adapter'), None)
|
||||
self.assertEqual(root.find('source/dir'), None)
|
||||
self.assertEqual(root.find('source/format'), None)
|
||||
self.assertEqual(root.findall('source/host')[0].attrib['name'], '1.2.3.4')
|
||||
self.assertTrue('port' not in root.findall('source/host')[0].attrib)
|
||||
self.assertEqual(root.findall('source/host')[1].attrib['name'], 'my.ceph.monitor')
|
||||
self.assertEqual(root.findall('source/host')[1].attrib['port'], '69')
|
||||
self.assertEqual(root.find('source/auth').attrib['type'], 'ceph')
|
||||
self.assertEqual(root.find('source/auth').attrib['username'], 'admin')
|
||||
self.assertEqual(root.find('source/auth/secret').attrib['type'], 'uuid')
|
||||
self.assertEqual(root.find('source/auth/secret').attrib['uuid'], 'someuuid')
|
||||
|
||||
def test_pool_with_netfs(self):
|
||||
'''
|
||||
Test virt._gen_pool_xml() with a netfs source
|
||||
'''
|
||||
xml_data = virt._gen_pool_xml('pool',
|
||||
'netfs',
|
||||
target='/path/to/target',
|
||||
permissions={
|
||||
'mode': '0770',
|
||||
'owner': 1000,
|
||||
'group': 100,
|
||||
'label': 'seclabel'
|
||||
},
|
||||
source_devices=[{'path': '/dev/sda'}],
|
||||
source_hosts=['nfs.host'],
|
||||
source_name='srcname',
|
||||
source_adapter={'type': 'scsi_host', 'name': 'host0'},
|
||||
source_dir='/some/dir',
|
||||
source_format='nfs')
|
||||
root = ET.fromstring(xml_data)
|
||||
self.assertEqual(root.find('name').text, 'pool')
|
||||
self.assertEqual(root.attrib['type'], 'netfs')
|
||||
self.assertEqual(root.find('target/path').text, '/path/to/target')
|
||||
self.assertEqual(root.find('target/permissions/mode').text, '0770')
|
||||
self.assertEqual(root.find('target/permissions/owner').text, '1000')
|
||||
self.assertEqual(root.find('target/permissions/group').text, '100')
|
||||
self.assertEqual(root.find('target/permissions/label').text, 'seclabel')
|
||||
self.assertEqual(root.find('source/device'), None)
|
||||
self.assertEqual(root.find('source/name'), None)
|
||||
self.assertEqual(root.find('source/adapter'), None)
|
||||
self.assertEqual(root.find('source/dir').attrib['path'], '/some/dir')
|
||||
self.assertEqual(root.find('source/format').attrib['type'], 'nfs')
|
||||
self.assertEqual(root.find('source/host').attrib['name'], 'nfs.host')
|
||||
self.assertEqual(root.find('source/auth'), None)
|
||||
|
||||
def test_list_pools(self):
|
||||
'''
|
||||
Test virt.list_pools()
|
||||
|
@ -23,6 +23,10 @@ from tests.support.mock import (
|
||||
# Import Salt Libs
|
||||
import salt.states.virt as virt
|
||||
import salt.utils.files
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class LibvirtMock(MagicMock): # pylint: disable=too-many-ancestors
|
||||
@ -35,6 +39,12 @@ class LibvirtMock(MagicMock): # pylint: disable=too-many-ancestors
|
||||
libvirt error mockup
|
||||
'''
|
||||
|
||||
def get_error_message(self):
|
||||
'''
|
||||
Fake function return error message
|
||||
'''
|
||||
return six.text_type(self)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
@ -230,9 +240,421 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'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',
|
||||
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.__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,
|
||||
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,
|
||||
image=None,
|
||||
disk='prod',
|
||||
disks=disks,
|
||||
nic='prod',
|
||||
interfaces=ifaces,
|
||||
graphics=graphics,
|
||||
hypervisor='qemu',
|
||||
seed=False,
|
||||
install=False,
|
||||
pub_key='/path/to/key.pub',
|
||||
priv_key='/path/to/key',
|
||||
connection='someconnection',
|
||||
username='libvirtuser',
|
||||
password='supersecret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='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)
|
||||
|
||||
def test_stopped(self):
|
||||
'''
|
||||
stopped state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
shutdown_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': shutdown_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'stopped': [{'domain': 'myvm', 'shutdown': True}]
|
||||
},
|
||||
'comment': 'Machine has been shut down'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
shutdown_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': shutdown_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.stopped('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
shutdown_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
|
||||
def test_powered_off(self):
|
||||
'''
|
||||
powered_off state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
stop_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': stop_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'unpowered': [{'domain': 'myvm', 'stop': True}]
|
||||
},
|
||||
'comment': 'Machine has been powered off'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
stop_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': stop_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.powered_off('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
stop_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
|
||||
def test_snapshot(self):
|
||||
'''
|
||||
snapshot state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
snapshot_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': snapshot_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'saved': [{'domain': 'myvm', 'snapshot': True}]
|
||||
},
|
||||
'comment': 'Snapshot has been taken'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
snapshot_mock.assert_called_with('myvm', suffix=None, connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': snapshot_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.snapshot('myvm',
|
||||
suffix='snap',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
snapshot_mock.assert_called_with('myvm',
|
||||
suffix='snap',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
|
||||
def test_rebooted(self):
|
||||
'''
|
||||
rebooted state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
reboot_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': reboot_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'rebooted': [{'domain': 'myvm', 'reboot': True}]
|
||||
},
|
||||
'comment': 'Machine has been rebooted'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), ret)
|
||||
reboot_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': reboot_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.rebooted('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
reboot_mock.assert_called_with('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), 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,
|
||||
autostart=False,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
define_mock.assert_called_with('mynet',
|
||||
'br2',
|
||||
'bridge',
|
||||
'openvswitch',
|
||||
tag=180,
|
||||
autostart=False,
|
||||
start=True,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.network_info': MagicMock(return_value={'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={'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',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
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={}),
|
||||
'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)
|
||||
|
||||
def test_pool_running(self):
|
||||
'''
|
||||
pool_running state test cases.
|
||||
'''
|
||||
ret = {'name': 'mypool', 'changes': {}, 'result': True, 'comment': ''}
|
||||
mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start']}
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={}),
|
||||
'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 and started'},
|
||||
'comment': 'Pool mypool defined and started'})
|
||||
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)
|
||||
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,
|
||||
transient=True,
|
||||
start=True,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
mocks['autostart'].assert_called_with('mypool',
|
||||
state='on',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
mocks['build'].assert_called_with('mypool',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={'state': 'running'}),
|
||||
}):
|
||||
ret.update({'changes': {}, 'comment': 'Pool mypool exists and is running'})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
|
||||
for mock in mocks:
|
||||
mocks[mock].reset_mock()
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={'state': 'stopped'}),
|
||||
'virt.pool_build': mocks['build'],
|
||||
'virt.pool_start': mocks['start']
|
||||
}):
|
||||
ret.update({'changes': {'mypool': 'Pool started'}, 'comment': 'Pool mypool started'})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None)
|
||||
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_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
|
Loading…
Reference in New Issue
Block a user