def domain_has_changed(vir_dom, domain, active=False): flags = libvirt.VIR_DOMAIN_XML_SECURE flags |= libvirt.VIR_DOMAIN_XML_INACTIVE if not active else 0 current = util.from_xml(vir_dom.XMLDesc(flags)) eq, path, cause = util.compare(domain, current, 'domain') return not eq, path, cause
def run_module(): module_args = dict( state=dict(type='str', choices=[ STATE_DEFINED, STATE_CREATED, STATE_DESTROYED, STATE_UNDEFINED, STATE_STOPPED ], default=STATE_CREATED), name=dict(type='str'), domain=dict(type='dict'), xml=dict(type='str'), update=dict(type='bool', default=False), persistent=dict(type='bool', default=True), destroy_graceful=dict(type='bool', default=True), undefine_destroy=dict(type='bool', default=True), undefine_managed_save=dict(type='bool', default=False), undefine_snapshots_metadata=dict(type='bool', default=False), undefine_keep_nvram=dict(type='bool', default=False), undefine_nvram=dict(type='bool', default=False), shutdown_acpi_power_btn=dict(type='bool', default=False), shutdown_guest_agent=dict(type='bool', default=False), shutdown_initctl=dict(type='bool', default=False), shutdown_signal=dict(type='bool', default=False), shutdown_paravirt=dict(type='bool', default=False), # undefine_remove_all_storage=dict(type='bool', default=False), # TODO # undefine_storage=dict(type='list'), # TODO # undefine_wipe_storage=dict(type='bool', default=False), # TODO ) module_args.update(util.common_args) result = dict(changed=False, ) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[ ['domain', 'xml', 'name'], ['undefine_keep_nvram', 'undefine_nvram'], ], required_if=[ ['state', STATE_CREATED, ['domain', 'xml'], True], ['state', STATE_DEFINED, ['domain', 'xml'], True], ['state', STATE_DESTROYED, ['name']], ], ) domain = module.params['domain'] if module.params['xml'] is not None: domain = util.from_xml(module.params['xml']) state = module.params['state'] name = module.params['name'] or domain['name'] if not name.strip(): module.fail_json(msg='missing domain name', **result) update = module.params['update'] persistent = module.params['persistent'] if state == STATE_DEFINED and not persistent: module.fail_json( msg='persistent cannot be false when state is defined') destroy_graceful = module.params['destroy_graceful'] undefine_destroy = module.params['undefine_destroy'] undefine_managed_save = module.params['undefine_managed_save'] undefine_snapshots_metadata = module.params['undefine_snapshots_metadata'] undefine_keep_nvram = module.params['undefine_keep_nvram'] undefine_nvram = module.params['undefine_nvram'] shutdown_acpi_power_btn = module.params['shutdown_acpi_power_btn'] shutdown_guest_agent = module.params['shutdown_guest_agent'] shutdown_initctl = module.params['shutdown_initctl'] shutdown_signal = module.params['shutdown_signal'] shutdown_paravirt = module.params['shutdown_paravirt'] conn = util.get_conn(module.params) # type: libvirt.virConnect if conn is None: module.fail_json(msg='cannot open connection to libvirt', **result) try: vir_dom = conn.lookupByName(name) # type: libvirt.virDomain if domain: domain['uuid'] = vir_dom.UUIDString() except libvirt.libvirtError: vir_dom = None if state == STATE_DEFINED: if vir_dom is None: result['changed'] = True vir_dom = define_domain(conn, domain) result.update(util.describe_domain(vir_dom)) elif update: changed, path, cause = domain_has_changed(vir_dom, domain) if changed: result['changed'] = True result['changed_path'] = path result['changed_cause'] = cause vir_dom = define_domain(conn, domain) changed, path, cause = domain_has_changed(vir_dom, domain) if changed: module.warn( 'the provided domain definition was modified by the virtualization platform, ' 'check the current definition to avoid unnecessary updates' ) result['domain'] = domain result['changed_path'] = path result['changed_cause'] = cause result.update(util.describe_domain(vir_dom)) elif state == STATE_CREATED: if vir_dom is None: result['changed'] = True if persistent: vir_dom = define_domain(conn, domain) vir_dom.create() else: vir_dom = create_domain(conn, domain) result.update(util.describe_domain(vir_dom)) elif update: if vir_dom.isActive(): # TODO: detect changes changed, path, cause = domain_has_changed(vir_dom, domain, active=True) if changed: module.warn( 'some configurations cannot be applied to running domain' ) module.warn('{}: {}'.format(path, cause)) if persistent: result['changed'] = True vir_dom = define_domain(conn, domain) if not vir_dom.isActive(): vir_dom.create() result.update(util.describe_domain(vir_dom)) elif vir_dom.isPersistent(): result['changed'] = True undefine_domain(vir_dom, undefine_managed_save, undefine_snapshots_metadata, undefine_keep_nvram, undefine_nvram) elif state == STATE_UNDEFINED: if vir_dom is not None: destroy = vir_dom.isActive() and undefine_destroy if vir_dom.isPersistent(): result['changed'] = True undefine_domain(vir_dom, undefine_managed_save, undefine_snapshots_metadata, undefine_keep_nvram, undefine_nvram) if destroy: result['changed'] = True destroy_domain(vir_dom, destroy_graceful) elif state == STATE_DESTROYED: if vir_dom is not None: result['changed'] = True destroy_domain(vir_dom, destroy_graceful) elif state == STATE_STOPPED: if vir_dom is None: module.warn('domain does not exists so cannot shutdown') else: result['changed'] = True domain_shutdown(vir_dom, shutdown_acpi_power_btn, shutdown_guest_agent, shutdown_initctl, shutdown_paravirt, shutdown_signal) module.exit_json(**result)
def run_module(): module_args = dict( state=dict(type='str', choices=[STATE_DEFINED, STATE_STARTED, STATE_UNDEFINED, STATE_DESTROYED], default=STATE_STARTED), name=dict(type='str'), network=dict(type='dict'), xml=dict(type='str'), autostart=dict(type='bool', default=True), persistent=dict(type='bool', default=True), undefine_destroy=dict(type='bool', default=True), ) module_args.update(util.common_args) result = dict( changed=False, ) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[ ['domain', 'xml', 'name'], ], required_if=[ ['state', STATE_STARTED, ['network', 'xml'], True], ['state', STATE_DEFINED, ['network', 'xml'], True], ['state', STATE_UNDEFINED, ['name']], ['state', STATE_DESTROYED, ['name']], ], ) network = module.params['network'] if module.params['xml'] is not None: network = util.from_xml(module.params['xml']) state = module.params['state'] name = module.params['name'] or network['name'] if not name.strip(): module.fail_json(msg='missing network name', **result) autostart = module.params['autostart'] persistent = module.params['persistent'] if state == STATE_DEFINED and not persistent: module.fail_json(msg='persistent cannot be false when state is defined') undefine_destroy = module.params['undefine_destroy'] conn = util.get_conn(module.params) # type: libvirt.virConnect if conn is None: module.fail_json(msg='cannot open connection to libvirt', **result) try: vir_net = conn.networkLookupByName(name) # type: libvirt.virNetwork if network: network['uuid'] = vir_net.UUIDString() except libvirt.libvirtError as e: vir_net = None if state == STATE_DEFINED: if vir_net is None: result['changed'] = True vir_net = define_network(conn, network, autostart) result.update(util.describe_network(vir_net)) else: changed, path, cause = network_has_changed(vir_net, network) if changed: result['changed'] = True result['changed_path'] = path result['changed_cause'] = cause vir_net = define_network(conn, network, autostart) changed, path, cause = network_has_changed(vir_net, network) if changed: module.warn('the provided network definition was modified by the virtualization platform, ' 'check the current definition to avoid unnecessary updates') result['network'] = network result['changed_path'] = path result['changed_cause'] = cause result.update(util.describe_network(vir_net)) elif state == STATE_STARTED: if vir_net is None: result['changed'] = True if persistent: vir_net = define_network(conn, network, autostart) vir_net.create() else: vir_net = create_network(conn, network) result.update(util.describe_network(vir_net)) else: if vir_net.isActive(): # TODO: detect changes changed, path, cause = network_has_changed(vir_net, network, active=True) if changed: module.warn('some configurations cannot be applied to running network') module.warn('{}: {}'.format(path, cause)) if persistent: result['changed'] = True vir_net = define_network(conn, network, autostart) if not vir_net.isActive(): vir_net.create() result.update(util.describe_network(vir_net)) elif vir_net.isPersistent(): result['changed'] = True undefine_network(vir_net) elif state == STATE_UNDEFINED: if vir_net is not None: destroy = vir_net.isActive() and undefine_destroy if vir_net.isPersistent(): result['changed'] = True undefine_network(vir_net) if destroy: result['changed'] = True destroy_network(vir_net) elif state == STATE_DESTROYED: if vir_net is not None: result['changed'] = True destroy_network(vir_net) module.exit_json(**result)
def network_has_changed(vir_net, network, active=False): # type: (libvirt.virNetwork, dict, bool) -> tuple flags = libvirt.VIR_NETWORK_XML_INACTIVE if not active else 0 current = util.from_xml(vir_net.XMLDesc(flags)) eq, path, cause = util.compare(network, current, 'network') return not eq, path, cause
def run_module(): module_args = dict( state=dict(type='str', choices=[STATE_PRESENT, STATE_ABSENT], default=STATE_PRESENT), domain=dict(type='str', required=True), alias=dict(type='str'), type=dict(type='str', choices=['emulator', 'disk', 'filesystem', 'controller', 'lease', 'hostdev', 'source', 'redirdev', 'smartcard', 'interface', 'input', 'hub', 'graphics', 'video', 'parallel', 'serial', 'console', 'channel', 'sound', 'watchdog', 'memballoon', 'rng', 'tpm', 'nvram', 'panic', 'shmem', 'memory', 'iommu', 'vsock']), device=dict(type='dict'), xml=dict(type='str'), update=dict(type='bool', default=False), ) module_args.update(util.common_args) result = dict( changed=False, ) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[ ['device', 'xml'], ['alias', 'type'], ], required_if=[ ['state', STATE_PRESENT, ['domain', 'xml'], True], ['state', STATE_ABSENT, ['alias', 'domain', 'xml'], True], ], ) state = module.params['state'] domain = module.params['domain'] device_type = module.params['type'] device = module.params['device'] if module.params['xml'] is not None: device = util.from_xml(module.params['xml']) alias = module.params['alias'] or device.get('alias', {}).get('_name') if alias and not alias.startswith('ua-'): module.fail_json(msg='alias must have "ua-" prefix', **result) update = module.params['update'] conn = util.get_conn(module.params) # type: libvirt.virConnect if conn is None: module.fail_json(msg='cannot open connection to libvirt', **result) try: vir_dom = conn.lookupByName(domain) # type: libvirt.virDomain except libvirt.libvirtError: module.fail_json(msg='domain not found', **result) # TODO: Check if device already exists. The rules are complex. # search disk by <target dev='name'/> then by <source file='name'/> if state == STATE_PRESENT: xml = encode_device(device_type, device) if alias: if not alias_exists(vir_dom, device_type, alias): vir_dom.attachDeviceFlags(xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT) result['changed'] = True else: vir_dom.attachDeviceFlags(xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT) result['changed'] = True elif state == STATE_ABSENT: if alias: if alias_exists(vir_dom, device_type, alias): vir_dom.detachDeviceAlias(alias, libvirt.VIR_DOMAIN_AFFECT_CURRENT) result['changed'] = True else: xml = encode_device(device_type, device) vir_dom.detachDeviceFlags(xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT) result['changed'] = True # TODO: Check if has changed module.exit_json(**result)
def run_module(): module_args = dict( state=dict(type='str', choices=['absent', 'present'], default='present'), name=dict(type='str'), pool=dict(type='str', required=True), volume=dict(type='dict'), xml=dict(type='str'), upload=dict(type='path'), resize=dict(type='int'), ) module_args.update(util.common_args) result = dict( changed=False, ) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[ ['volume', 'xml'] ], required_if=[ ['state', 'present', ['volume', 'xml'], True], ['state', 'absent', ['name']] ] ) state = module.params['state'] pool = module.params['pool'] upload = module.params['upload'] resize = module.params['resize'] volume = module.params['volume'] if module.params['xml'] is not None: volume = util.from_xml(module.params['xml']) name = module.params['name'] or volume['name'] if not name.strip(): module.fail_json(msg='Missing volume name', **result) conn = util.get_conn(module.params) # type: libvirt.virConnect if conn is None: module.fail_json(msg='Cannot open connection to libvirt', **result) vir_pool = None try: vir_pool = conn.storagePoolLookupByName(pool) except libvirt.libvirtError: pass vir_vol = None if vir_pool is not None: try: vir_vol = vir_pool.storageVolLookupByName(name) except libvirt.libvirtError: pass if state == 'absent': if vir_vol is not None: vir_vol.delete() result['name'] = vir_vol.name() result['changed'] = True elif state == 'present': if vir_vol is None: xml = encode_volume(volume) vir_vol = vir_pool.createXML(xml) result['changed'] = True result.update(util.describe_volume(vir_vol)) if upload is not None: size = os.path.getsize(upload) if not module.check_mode: stream = conn.newStream() vir_vol.upload(stream, 0, size) with open(upload, 'rb') as f: stream.sendAll(lambda _, data, file_: file_.read(data), f) stream.finish() result['uploaded'] = upload result['uploaded_bytes'] = size if resize is not None: vir_vol.resize(resize) result['resized'] = resize else: # TODO result.update(util.describe_volume(vir_vol)) module.exit_json(**result)