diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py b/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py index 8de22478cf1..bb2dfcb4054 100644 --- a/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py +++ b/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py @@ -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 diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py b/lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py index e92bea69b9f..96612ac45cb 100644 --- a/lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py +++ b/lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py @@ -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,26 +312,44 @@ 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']) - hosts_service.host_service(host_id).iscsi_login( - iscsi=otypes.IscsiDetails( - username=storage.get('username'), - password=storage.get('password'), - address=storage.get('address'), - target=storage.get('target'), - ), - ) + 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'), + password=storage.get('password'), + address=storage.get('address'), + 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, diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py index f6a06bb9659..69ae5573354 100644 --- a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py +++ b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py @@ -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,