Improve ovirt_vms, ovirt_hosts and ovirt_storage_domains (#35782)

* ovirt_vms: Add graphics consoles

* ovirt_hosts: Fix kdump integration check

* ovirt_storage_domains: Support multiple targets for block storages

* ovirt_vms: add cloud_init_persist parameter

* ovirt_vms: Change IO threads to int

* ovirt_vms: Fix update check

* ovirt_vms: Remove choices of OS, to not enforce it
This commit is contained in:
Ondra Machacek 2018-02-07 17:48:00 +01:00 committed by ansibot
parent 51c4412de2
commit 7d4a2de66a
3 changed files with 222 additions and 138 deletions

View file

@ -268,9 +268,6 @@ class HostsModule(BaseModule):
ssh=otypes.Ssh(
authentication_method=otypes.SshAuthenticationMethod.PUBLICKEY,
) if self.param('public_key') else None,
kdump_status=otypes.KdumpStatus(
self.param('kdump_integration')
) if self.param('kdump_integration') else None,
spm=otypes.Spm(
priority=self.param('spm_priority'),
) if self.param('spm_priority') else None,
@ -283,14 +280,15 @@ class HostsModule(BaseModule):
) if self.param('kernel_params') else None,
power_management=otypes.PowerManagement(
enabled=self.param('power_management_enabled'),
) if self.param('power_management_enabled') is not None else None,
kdump_detection=self.param('kdump_integration') == 'enabled',
) if self.param('power_management_enabled') is not None or self.param('kdump_integration') else None,
)
def update_check(self, entity):
kernel_params = self.param('kernel_params')
return (
equal(self.param('comment'), entity.comment) and
equal(self.param('kdump_integration'), entity.kdump_status) and
equal(self.param('kdump_integration'), 'enabled' if entity.power_management.kdump_detection else 'disabled') and
equal(self.param('spm_priority'), entity.spm.priority) and
equal(self.param('power_management_enabled'), entity.power_management.enabled) and
equal(self.param('override_display'), getattr(entity.display, 'address', None)) and

View file

@ -93,7 +93,10 @@ options:
- "C(username) - A CHAP user name for logging into a target."
- "C(password) - A CHAP password for logging into a target."
- "C(override_luns) - If I(True) ISCSI storage domain luns will be overridden before adding."
- C(target_lun_map) - List of dictionary containing targets and LUNs."
- "Note that these parameters are not idempotent."
- "Parameter C(target_lun_map) is supported since Ansible 2.5."
posixfs:
description:
- "Dictionary with values for PosixFS storage type:"
@ -196,6 +199,21 @@ EXAMPLES = '''
critical_space_action_blocker: 5
warning_low_space: 10
# Since Ansible 2.5 you can specify multiple targets for storage domain,
# Add data iSCSI storage domain with multiple targets:
- ovirt_storage_domains:
name: data_iscsi
host: myhost
data_center: mydatacenter
iscsi:
target_lun_map:
- target: iqn.2016-08-09.domain-01:nickname
lun_id: 1IET_000d0001
- target: iqn.2016-08-09.domain-02:nickname
lun_id: 1IET_000d0002
address: 10.34.63.204
discard_after_delete: True
# Add data glusterfs storage domain
- ovirt_storage_domains:
name: glusterfs_1
@ -294,18 +312,19 @@ class StorageDomainModule(BaseModule):
def _get_storage_type(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp', 'localfs']:
if self._module.params.get(sd_type) is not None:
if self.param(sd_type) is not None:
return sd_type
def _get_storage(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp', 'localfs']:
if self._module.params.get(sd_type) is not None:
return self._module.params.get(sd_type)
if self.param(sd_type) is not None:
return self.param(sd_type)
def _login(self, storage_type, storage):
if storage_type == 'iscsi':
hosts_service = self._connection.system_service().hosts_service()
host_id = get_id_by_name(hosts_service, self._module.params['host'])
host_id = get_id_by_name(hosts_service, self.param('host'))
if storage.get('target'):
hosts_service.host_service(host_id).iscsi_login(
iscsi=otypes.IscsiDetails(
username=storage.get('username'),
@ -314,6 +333,23 @@ class StorageDomainModule(BaseModule):
target=storage.get('target'),
),
)
elif storage.get('target_lun_map'):
for target in [m['target'] for m in storage.get('target_lun_map')]:
hosts_service.host_service(host_id).iscsi_login(
iscsi=otypes.IscsiDetails(
username=storage.get('username'),
password=storage.get('password'),
address=storage.get('address'),
target=target,
),
)
def __target_lun_map(self, storage):
if storage.get('target'):
lun_ids = storage.get('lun_id') if isinstance(storage.get('lun_id'), list) else [(storage.get('lun_id'))]
return [(lun_id, storage.get('target')) for lun_id in lun_ids]
elif storage.get('target_lun_map'):
return [(target_map.get('lun_id'), target_map.get('target')) for target_map in storage.get('target_lun_map')]
def build_entity(self):
storage_type = self._get_storage_type()
@ -321,29 +357,18 @@ class StorageDomainModule(BaseModule):
self._login(storage_type, storage)
return otypes.StorageDomain(
name=self._module.params['name'],
description=self._module.params['description'],
comment=self._module.params['comment'],
wipe_after_delete=self._module.params['wipe_after_delete'],
backup=self._module.params['backup'],
critical_space_action_blocker=self._module.params['critical_space_action_blocker'],
warning_low_space_indicator=self._module.params['warning_low_space'],
import_=(
True
if self._module.params['state'] == 'imported' else None
),
id=(
self._module.params['id']
if self._module.params['state'] == 'imported' else None
),
type=otypes.StorageDomainType(
self._module.params['domain_function']
),
host=otypes.Host(
name=self._module.params['host'],
),
discard_after_delete=self._module.params['discard_after_delete']
if storage_type in ['iscsi', 'fcp'] else False,
name=self.param('name'),
description=self.param('description'),
comment=self.param('comment'),
wipe_after_delete=self.param('wipe_after_delete'),
backup=self.param('backup'),
critical_space_action_blocker=self.param('critical_space_action_blocker'),
warning_low_space_indicator=self.param('warning_low_space'),
import_=True if self.param('state') == 'imported' else None,
id=self.param('id') if self.param('state') == 'imported' else None,
type=otypes.StorageDomainType(self.param('domain_function')),
host=otypes.Host(name=self.param('host')),
discard_after_delete=self.param('discard_after_delete'),
storage=otypes.HostStorage(
type=otypes.StorageType(storage_type),
logical_units=[
@ -351,14 +376,10 @@ class StorageDomainModule(BaseModule):
id=lun_id,
address=storage.get('address'),
port=int(storage.get('port', 3260)),
target=storage.get('target'),
target=target,
username=storage.get('username'),
password=storage.get('password'),
) for lun_id in (
storage.get('lun_id')
if isinstance(storage.get('lun_id'), list)
else [storage.get('lun_id')]
)
) for lun_id, target in self.__target_lun_map(storage)
] if storage_type in ['iscsi', 'fcp'] else None,
override_luns=storage.get('override_luns'),
mount_options=storage.get('mount_options'),
@ -397,7 +418,7 @@ class StorageDomainModule(BaseModule):
raise Exception(
"Can't bring storage to state `%s`, because it seems that"
"it is not attached to any datacenter"
% self._module.params['state']
% self.param('state')
)
else:
if dc.status == dcstatus.UP:
@ -423,7 +444,7 @@ class StorageDomainModule(BaseModule):
return dc_service.storage_domains_service()
def _attached_sd_service(self, storage_domain):
dc_name = self._module.params['data_center']
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
@ -443,8 +464,8 @@ class StorageDomainModule(BaseModule):
wait(
service=attached_sd_service,
condition=lambda sd: sd.status == sdstate.MAINTENANCE,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
wait=self.param('wait'),
timeout=self.param('timeout'),
)
def _unattach(self, storage_domain):
@ -460,15 +481,15 @@ class StorageDomainModule(BaseModule):
wait(
service=attached_sd_service,
condition=lambda sd: sd is None,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
wait=self.param('wait'),
timeout=self.param('timeout'),
)
def pre_remove(self, storage_domain):
# In case the user chose to destroy the storage domain there is no need to
# move it to maintenance or detach it, it should simply be removed from the DB.
# Also if storage domain in already unattached skip this step.
if storage_domain.status == sdstate.UNATTACHED or self._module.params['destroy']:
if storage_domain.status == sdstate.UNATTACHED or self.param('destroy'):
return
# Before removing storage domain we need to put it into maintenance state:
self._maintenance(storage_domain)
@ -478,7 +499,7 @@ class StorageDomainModule(BaseModule):
def post_create_check(self, sd_id):
storage_domain = self._service.service(sd_id).get()
dc_name = self._module.params['data_center']
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
@ -497,12 +518,12 @@ class StorageDomainModule(BaseModule):
wait(
service=attached_sd_service,
condition=lambda sd: sd.status == sdstate.ACTIVE,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
wait=self.param('wait'),
timeout=self.param('timeout'),
)
def unattached_pre_action(self, storage_domain):
dc_name = self._module.params['data_center']
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
@ -511,8 +532,13 @@ class StorageDomainModule(BaseModule):
def update_check(self, entity):
return (
equal(self._module.params['comment'], entity.comment) and
equal(self._module.params['description'], entity.description)
equal(self.param('comment'), entity.comment) and
equal(self.param('description'), entity.description) and
equal(self.param('backup'), entity.backup) and
equal(self.param('critical_space_action_blocker'), entity.critical_space_action_blocker) and
equal(self.param('discard_after_delete'), entity.discard_after_delete) and
equal(self.param('wipe_after_delete'), entity.wipe_after_delete) and
equal(self.param('warning_low_space_indicator'), entity.warning_low_space_indicator)
)
@ -578,9 +604,9 @@ def main():
backup=dict(type='bool', default=None),
critical_space_action_blocker=dict(type='int', default=None),
warning_low_space=dict(type='int', default=None),
destroy=dict(type='bool', default=False),
format=dict(type='bool', default=False),
discard_after_delete=dict(type='bool', default=True)
destroy=dict(type='bool', default=None),
format=dict(type='bool', default=None),
discard_after_delete=dict(type='bool', default=None)
)
module = AnsibleModule(
argument_spec=argument_spec,

View file

@ -371,6 +371,12 @@ options:
- C(nic_name) - Set name to network interface of Virtual Machine.
- C(nic_on_boot) - If I(True) network interface will be set to start on boot.
version_added: "2.3"
cloud_init_persist:
description:
- "If I(true) the C(cloud_init) or C(sysprep) parameters will be saved for the virtual machine
and won't be virtual machine won't be started as run-once."
version_added: "2.5"
aliases: [ 'sysprep_persist' ]
kernel_path:
description:
- Path to a kernel image used to boot the virtual machine.
@ -496,9 +502,9 @@ options:
description:
- "If I(true), use smart card authentication."
version_added: "2.5"
io_threads_enabled:
io_threads:
description:
- "If I(true), use IO threads."
- "Number of IO threads used by virtual machine. I(0) means IO threading disabled."
version_added: "2.5"
ballooning_enabled:
description:
@ -527,6 +533,13 @@ options:
- "C(model) - Model of the watchdog device. For example: I(i6300esb), I(diag288) or I(null)."
- "C(action) - Watchdog action to be performed when watchdog is triggered. For example: I(none), I(reset), I(poweroff), I(pause) or I(dump)."
version_added: "2.5"
graphical_console:
description:
- "Assign graphical console to the virtual machine."
- "Graphical console is a dictionary which can have following values:"
- "C(headless_mode) - If I(true) disable the graphics console for this virtual machine."
- "C(protocol) - Graphical protocol, one of I(VNC), I(SPICE), or both."
version_added: "2.5"
notes:
- If VM is in I(UNASSIGNED) or I(UNKNOWN) state before any operation, the module will fail.
If VM is in I(IMAGE_LOCKED) state before any operation, we try to wait for VM to be I(DOWN).
@ -838,6 +851,10 @@ from ansible.module_utils.ovirt import (
class VmsModule(BaseModule):
def __init__(self, *args, **kwargs):
super(VmsModule, self).__init__(*args, **kwargs)
self._initialization = None
def __get_template_with_version(self):
"""
oVirt/RHV in version 4.1 doesn't support search by template+version_number,
@ -1017,8 +1034,8 @@ class VmsModule(BaseModule):
smartcard_enabled=self.param('smartcard_enabled')
) if self.param('smartcard_enabled') is not None else None,
io=otypes.Io(
threads=int(self.param('io_threads_enabled')),
) if self.param('io_threads_enabled') is not None else None,
threads=self.param('io_threads'),
) if self.param('io_threads') is not None else None,
rng_device=otypes.RngDevice(
source=otypes.RngSource(self.param('rng_device')),
) if self.param('rng_device') else None,
@ -1027,8 +1044,9 @@ class VmsModule(BaseModule):
name=cp.get('name'),
regexp=cp.get('regexp'),
value=str(cp.get('value')),
) for cp in self.param('custom_properties')
] if self.param('custom_properties') is not None else None
) for cp in self.param('custom_properties') if cp
] if self.param('custom_properties') is not None else None,
initialization=self.get_initialization() if self.param('cloud_init_persist') else None,
)
def update_check(self, entity):
@ -1046,14 +1064,16 @@ class VmsModule(BaseModule):
current = []
if entity.custom_properties:
current = [(cp.name, cp.regexp, str(cp.value)) for cp in entity.custom_properties]
passed = [(cp.get('name'), cp.get('regexp'), str(cp.get('value'))) for cp in self.param('custom_properties')]
passed = [(cp.get('name'), cp.get('regexp'), str(cp.get('value'))) for cp in self.param('custom_properties') if cp]
return sorted(current) == sorted(passed)
return True
cpu_mode = getattr(entity.cpu, 'mode')
vm_display = entity.display
return (
check_cpu_pinning() and
check_custom_properties() and
not self.param('cloud_init_persist') and
equal(self.param('cluster'), get_link_name(self._connection, entity.cluster)) and equal(convert_to_bytes(self.param('memory')), entity.memory) and
equal(convert_to_bytes(self.param('memory_guaranteed')), entity.memory_policy.guaranteed) and
equal(convert_to_bytes(self.param('memory_max')), entity.memory_policy.max) and
@ -1065,8 +1085,8 @@ class VmsModule(BaseModule):
equal(self.param('operating_system'), str(entity.os.type)) and
equal(self.param('boot_menu'), entity.bios.boot_menu.enabled) and
equal(self.param('soundcard_enabled'), entity.soundcard_enabled) and
equal(self.param('smartcard_enabled'), entity.display.smartcard_enabled) and
equal(self.param('io_threads_enabled'), bool(entity.io.threads)) and
equal(self.param('smartcard_enabled'), getattr(vm_display, 'smartcard_enabled', False)) and
equal(self.param('io_threads'), entity.io.threads) and
equal(self.param('ballooning_enabled'), entity.memory_policy.ballooning) and
equal(self.param('serial_console'), entity.console.enabled) and
equal(self.param('usb_support'), entity.usb.enabled) and
@ -1088,7 +1108,7 @@ class VmsModule(BaseModule):
equal(self.param('serial_policy_value'), getattr(entity.serial_number, 'value', None)) and
equal(self.param('placement_policy'), str(entity.placement_policy.affinity)) and
equal(self.param('rng_device'), str(entity.rng_device.source) if entity.rng_device else None) and
self.param('host') in [self._connection.follow_link(host).name for host in entity.placement_policy.hosts]
self.param('host') in [self._connection.follow_link(host).name for host in entity.placement_policy.hosts or []]
)
def pre_create(self, entity):
@ -1098,13 +1118,15 @@ class VmsModule(BaseModule):
self._module.params['template'] = 'Blank'
def post_update(self, entity):
self.post_present(entity)
self.post_present(entity.id)
def post_present(self, entity):
def post_present(self, entity_id):
# After creation of the VM, attach disks and NICs:
entity = self._service.service(entity_id).get()
self.changed = self.__attach_disks(entity)
self.changed = self.__attach_nics(entity)
self.changed = self.__attach_watchdog(entity)
self.changed = self.__attach_graphical_console(entity)
def pre_remove(self, entity):
# Forcibly stop the VM, if it's not in DOWN state:
@ -1250,6 +1272,51 @@ class VmsModule(BaseModule):
)
return True
def __attach_graphical_console(self, entity):
graphical_console = self.param('graphical_console')
if not graphical_console:
return
vm_service = self._service.service(entity.id)
gcs_service = vm_service.graphics_consoles_service()
graphical_consoles = gcs_service.list()
# Remove all graphical consoles if there are any:
if bool(graphical_console.get('headless_mode')):
if not self._module.check_mode:
for gc in graphical_consoles:
gcs_service.console_service(gc.id).remove()
return len(graphical_consoles) > 0
# If there are not gc add any gc to be added:
protocol = graphical_console.get('protocol')
if isinstance(protocol, str):
protocol = [protocol]
current_protocols = [str(gc.protocol) for gc in graphical_consoles]
if not current_protocols:
if not self._module.check_mode:
for p in protocol:
gcs_service.add(
otypes.GraphicsConsole(
protocol=otypes.GraphicsType(p),
)
)
return True
# Update consoles:
if sorted(protocol) != sorted(current_protocols):
if not self._module.check_mode:
for gc in graphical_consoles:
gcs_service.console_service(gc.id).remove()
for p in protocol:
gcs_service.add(
otypes.GraphicsConsole(
protocol=otypes.GraphicsType(p),
)
)
return True
def __attach_disks(self, entity):
if not self.param('disks'):
return
@ -1370,6 +1437,52 @@ class VmsModule(BaseModule):
)
self.changed = True
def get_initialization(self):
if self._initialization is not None:
return self._initialization
sysprep = self.param('sysprep')
cloud_init = self.param('cloud_init')
cloud_init_nics = self.param('cloud_init_nics') or []
if cloud_init is not None:
cloud_init_nics.append(cloud_init)
if cloud_init or cloud_init_nics:
self._initialization = otypes.Initialization(
nic_configurations=[
otypes.NicConfiguration(
boot_protocol=otypes.BootProtocol(
nic.pop('nic_boot_protocol').lower()
) if nic.get('nic_boot_protocol') else None,
name=nic.pop('nic_name', None),
on_boot=nic.pop('nic_on_boot', None),
ip=otypes.Ip(
address=nic.pop('nic_ip_address', None),
netmask=nic.pop('nic_netmask', None),
gateway=nic.pop('nic_gateway', None),
) if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None
) else None,
)
for nic in cloud_init_nics
if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None or
nic.get('nic_boot_protocol') is not None or
nic.get('nic_on_boot') is not None
)
] if cloud_init_nics else None,
**cloud_init
)
elif sysprep:
self._initialization = otypes.Initialization(
**sysprep
)
return self._initialization
def _get_role_mappings(module):
roleMappings = list()
@ -1569,45 +1682,6 @@ def import_vm(module, connection):
return True
def _get_initialization(sysprep, cloud_init, cloud_init_nics):
initialization = None
if cloud_init or cloud_init_nics:
initialization = otypes.Initialization(
nic_configurations=[
otypes.NicConfiguration(
boot_protocol=otypes.BootProtocol(
nic.pop('nic_boot_protocol').lower()
) if nic.get('nic_boot_protocol') else None,
name=nic.pop('nic_name', None),
on_boot=nic.pop('nic_on_boot', None),
ip=otypes.Ip(
address=nic.pop('nic_ip_address', None),
netmask=nic.pop('nic_netmask', None),
gateway=nic.pop('nic_gateway', None),
) if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None
) else None,
)
for nic in cloud_init_nics
if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None or
nic.get('nic_boot_protocol') is not None or
nic.get('nic_on_boot') is not None
)
] if cloud_init_nics else None,
**cloud_init
)
elif sysprep:
initialization = otypes.Initialization(
**sysprep
)
return initialization
def control_state(vm, vms_service, module):
if vm is None:
return
@ -1671,19 +1745,7 @@ def main():
cpu_shares=dict(type='int'),
cpu_threads=dict(type='int'),
type=dict(type='str', choices=['server', 'desktop', 'high_performance']),
operating_system=dict(type='str',
choices=[
'rhel_6_ppc64', 'other', 'freebsd', 'windows_2003x64', 'windows_10',
'rhel_6x64', 'rhel_4x64', 'windows_2008x64', 'windows_2008R2x64',
'debian_7', 'windows_2012x64', 'ubuntu_14_04', 'ubuntu_12_04',
'ubuntu_13_10', 'windows_8x64', 'other_linux_ppc64', 'windows_2003',
'other_linux', 'windows_10x64', 'windows_2008', 'rhel_3', 'rhel_5',
'rhel_4', 'other_ppc64', 'sles_11', 'rhel_6', 'windows_xp', 'rhel_7x64',
'freebsdx64', 'rhel_7_ppc64', 'windows_7', 'rhel_5x64',
'ubuntu_14_04_ppc64', 'sles_11_ppc64', 'windows_8',
'windows_2012R2x64', 'windows_2008r2x64', 'ubuntu_13_04',
'ubuntu_12_10', 'windows_7x64',
]),
operating_system=dict(type='str'),
cd_iso=dict(type='str'),
boot_devices=dict(type='list'),
vnic_profile_mappings=dict(default=[], type='list'),
@ -1708,6 +1770,7 @@ def main():
nics=dict(type='list', default=[]),
cloud_init=dict(type='dict'),
cloud_init_nics=dict(type='list', default=[]),
cloud_init_persist=dict(type='bool', default=False, aliases=['sysprep_persist']),
sysprep=dict(type='dict'),
host=dict(type='str'),
clone=dict(type='bool', default=False),
@ -1729,11 +1792,12 @@ def main():
cpu_pinning=dict(type='list'),
soundcard_enabled=dict(type='bool', default=None),
smartcard_enabled=dict(type='bool', default=None),
io_threads_enabled=dict(type='bool', default=None),
io_threads=dict(type='int', default=None),
ballooning_enabled=dict(type='bool', default=None),
rng_device=dict(type='str'),
custom_properties=dict(type='list'),
watchdog=dict(type='dict'),
graphical_console=dict(type='dict'),
)
module = AnsibleModule(
argument_spec=argument_spec,
@ -1760,12 +1824,6 @@ def main():
if module.params['xen'] or module.params['kvm'] or module.params['vmware']:
vms_module.changed = import_vm(module, connection)
sysprep = module.params['sysprep']
cloud_init = module.params['cloud_init']
cloud_init_nics = module.params['cloud_init_nics'] or []
if cloud_init is not None:
cloud_init_nics.append(cloud_init)
# In case VM don't exist, wait for VM DOWN state,
# otherwise don't wait for any state, just update VM:
ret = vms_module.create(
@ -1774,11 +1832,11 @@ def main():
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
vms_module.post_present(vm)
vms_module.post_present(ret['id'])
# Run the VM if it was just created, else don't run it:
if state == 'running':
initialization = _get_initialization(sysprep, cloud_init, cloud_init_nics)
initialization = vms_module.get_initialization()
ret = vms_module.action(
action='start',
post_action=vms_module._post_start_action,
@ -1794,8 +1852,8 @@ def main():
),
wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
# Start action kwargs:
use_cloud_init=cloud_init is not None or len(cloud_init_nics) > 0,
use_sysprep=sysprep is not None,
use_cloud_init=not module.params.get('cloud_init_persist') and module.params.get('cloud_init') is not None,
use_sysprep=not module.params.get('cloud_init_persist') and module.params.get('sysprep') is not None,
vm=otypes.Vm(
placement_policy=otypes.VmPlacementPolicy(
hosts=[otypes.Host(name=module.params['host'])]
@ -1815,7 +1873,7 @@ def main():
module.params.get('initrd_path') or
module.params.get('kernel_path') or
module.params.get('host') or
initialization
initialization is not None and not module.params.get('cloud_init_persist')
) else None,
)
@ -1839,6 +1897,7 @@ def main():
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
vms_module.post_present(ret['id'])
if module.params['force']:
ret = vms_module.action(
action='stop',
@ -1860,6 +1919,7 @@ def main():
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
vms_module.post_present(ret['id'])
ret = vms_module.action(
action='suspend',
pre_action=vms_module._pre_suspend_action,