From 95358418c9490e2ec08c3599bf932a5e0aa4a646 Mon Sep 17 00:00:00 2001 From: Tony Garcia Date: Tue, 17 Oct 2023 17:34:44 -0500 Subject: [PATCH] Remove custom virt module Use community.libvirt instead of custom module --- plugins/modules/virt.py | 625 ------------------ .../installer/tasks/59_cleanup_bootstrap.yml | 10 +- 2 files changed, 5 insertions(+), 630 deletions(-) delete mode 100644 plugins/modules/virt.py diff --git a/plugins/modules/virt.py b/plugins/modules/virt.py deleted file mode 100644 index da861dfaf..000000000 --- a/plugins/modules/virt.py +++ /dev/null @@ -1,625 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2007, 2012 Red Hat, Inc -# Michael DeHaan -# Seth Vidal -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - - -DOCUMENTATION = """ ---- -module: virt -short_description: Manages virtual machines supported by libvirt -description: - - Manages virtual machines supported by I(libvirt). -options: - name: - description: - - name of the guest VM being managed. Note that VM must be previously - defined with xml. - - This option is required unless I(command) is C(list_vms) or C(info). - type: str - aliases: - - guest - state: - description: - - Note that there may be some lag for state requests like C(shutdown) - since these refer only to VM states. After starting a guest, it may not - be immediately accessible. - state and command are mutually exclusive except when command=list_vms. In - this case all VMs in specified state will be listed. - choices: [ destroyed, paused, running, shutdown ] - type: str - command: - description: - - In addition to state management, various non-idempotent commands are available. - choices: [ create, define, destroy, freemem, get_xml, info, list_vms, nodeinfo, pause, shutdown, start, status, stop, undefine, unpause, virttype ] - type: str - autostart: - description: - - start VM at host startup. - type: bool - uri: - description: - - libvirt connection uri. - default: qemu:///system - type: str - xml: - description: - - XML document used with the define command. - - Must be raw XML content using C(lookup). XML cannot be reference to a file. - type: str -requirements: - - python >= 2.6 - - libvirt-python -author: - - Ansible Core Team - - Michael DeHaan - - Seth Vidal (@skvidal) -""" - -EXAMPLES = """ -# a playbook task line: -- community.libvirt.virt: - name: alpha - state: running - -# /usr/bin/ansible invocations -# ansible host -m virt -a "name=alpha command=status" -# ansible host -m virt -a "name=alpha command=get_xml" -# ansible host -m virt -a "name=alpha command=create uri=lxc:///" - -# defining and launching an LXC guest -- name: define vm - community.libvirt.virt: - command: define - xml: "{{ lookup('template', 'container-template.xml.j2') }}" - uri: 'lxc:///' -- name: start vm - community.libvirt.virt: - name: foo - state: running - uri: 'lxc:///' - -# setting autostart on a qemu VM (default uri) -- name: set autostart for a VM - community.libvirt.virt: - name: foo - autostart: yes - -# Defining a VM and making is autostart with host. VM will be off after this task -- name: define vm from xml and set autostart - community.libvirt.virt: - command: define - xml: "{{ lookup('template', 'vm_template.xml.j2') }}" - autostart: yes - -# Listing VMs -- name: list all VMs - community.libvirt.virt: - command: list_vms - register: all_vms - -- name: list only running VMs - community.libvirt.virt: - command: list_vms - state: running - register: running_vms -""" - -RETURN = """ -# for list_vms command -list_vms: - description: The list of vms defined on the remote system - type: list - returned: success - sample: [ - "build.example.org", - "dev.example.org" - ] -# for status command -status: - description: The status of the VM, among running, crashed, paused and shutdown - type: str - sample: "success" - returned: success -""" - -import traceback - -try: - import libvirt - from libvirt import libvirtError -except ImportError: - HAS_VIRT = False -else: - HAS_VIRT = True - -import re - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - - -VIRT_FAILED = 1 -VIRT_SUCCESS = 0 -VIRT_UNAVAILABLE = 2 - -ALL_COMMANDS = [] -VM_COMMANDS = [ - "create", - "define", - "destroy", - "get_xml", - "pause", - "shutdown", - "status", - "start", - "stop", - "undefine", - "unpause", -] -HOST_COMMANDS = ["freemem", "info", "list_vms", "nodeinfo", "virttype"] -ALL_COMMANDS.extend(VM_COMMANDS) -ALL_COMMANDS.extend(HOST_COMMANDS) - -VIRT_STATE_NAME_MAP = { - 0: "running", - 1: "running", - 2: "running", - 3: "paused", - 4: "shutdown", - 5: "shutdown", - 6: "crashed", -} - - -class VMNotFound(Exception): - pass - - -class LibvirtConnection(object): - def __init__(self, uri, module): - - self.module = module - - cmd = "uname -r" - rc, stdout, stderr = self.module.run_command(cmd) - - if "xen" in stdout: - conn = libvirt.open(None) - elif "esx" in uri: - auth = [ - [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT], - [], - None, - ] - conn = libvirt.openAuth(uri, auth) - else: - conn = libvirt.open(uri) - - if not conn: - raise Exception("hypervisor connection failure") - - self.conn = conn - - def find_vm(self, vmid): - """ - Extra bonus feature: vmid = -1 returns a list of everything - """ - conn = self.conn - - vms = [] - - # this block of code borrowed from virt-manager: - # get working domain's name - ids = conn.listDomainsID() - for id in ids: - vm = conn.lookupByID(id) - vms.append(vm) - # get defined domain - names = conn.listDefinedDomains() - for name in names: - vm = conn.lookupByName(name) - vms.append(vm) - - if vmid == -1: - return vms - - for vm in vms: - if vm.name() == vmid: - return vm - - raise VMNotFound("virtual machine %s not found" % vmid) - - def shutdown(self, vmid): - return self.find_vm(vmid).shutdown() - - def pause(self, vmid): - return self.suspend(vmid) - - def unpause(self, vmid): - return self.resume(vmid) - - def suspend(self, vmid): - return self.find_vm(vmid).suspend() - - def resume(self, vmid): - return self.find_vm(vmid).resume() - - def create(self, vmid): - return self.find_vm(vmid).create() - - def destroy(self, vmid): - return self.find_vm(vmid).destroy() - - def undefine(self, vmid): - return self.find_vm(vmid).undefine() - - def get_status2(self, vm): - state = vm.info()[0] - return VIRT_STATE_NAME_MAP.get(state, "unknown") - - def get_status(self, vmid): - state = self.find_vm(vmid).info()[0] - return VIRT_STATE_NAME_MAP.get(state, "unknown") - - def nodeinfo(self): - return self.conn.getInfo() - - def get_type(self): - return self.conn.getType() - - def get_xml(self, vmid): - vm = self.conn.lookupByName(vmid) - return vm.XMLDesc(0) - - def get_maxVcpus(self, vmid): - vm = self.conn.lookupByName(vmid) - return vm.maxVcpus() - - def get_maxMemory(self, vmid): - vm = self.conn.lookupByName(vmid) - return vm.maxMemory() - - def getFreeMemory(self): - return self.conn.getFreeMemory() - - def get_autostart(self, vmid): - vm = self.conn.lookupByName(vmid) - return vm.autostart() - - def set_autostart(self, vmid, val): - vm = self.conn.lookupByName(vmid) - return vm.setAutostart(val) - - def define_from_xml(self, xml): - return self.conn.defineXML(xml) - - -class Virt(object): - def __init__(self, uri, module): - self.module = module - self.uri = uri - - def __get_conn(self): - self.conn = LibvirtConnection(self.uri, self.module) - return self.conn - - def get_vm(self, vmid): - self.__get_conn() - return self.conn.find_vm(vmid) - - def state(self): - vms = self.list_vms() - state = [] - for vm in vms: - state_blurb = self.conn.get_status(vm) - state.append("%s %s" % (vm, state_blurb)) - return state - - def info(self): - vms = self.list_vms() - info = dict() - for vm in vms: - data = self.conn.find_vm(vm).info() - # libvirt returns maxMem, memory, and cpuTime as long()'s, which - # xmlrpclib tries to convert to regular int's during serialization. - # This throws exceptions, so convert them to strings here and - # assume the other end of the xmlrpc connection can figure things - # out or doesn't care. - info[vm] = dict( - state=VIRT_STATE_NAME_MAP.get(data[0], "unknown"), - maxMem=str(data[1]), - memory=str(data[2]), - nrVirtCpu=data[3], - cpuTime=str(data[4]), - autostart=self.conn.get_autostart(vm), - ) - - return info - - def nodeinfo(self): - self.__get_conn() - data = self.conn.nodeinfo() - info = dict( - cpumodel=str(data[0]), - phymemory=str(data[1]), - cpus=str(data[2]), - cpumhz=str(data[3]), - numanodes=str(data[4]), - sockets=str(data[5]), - cpucores=str(data[6]), - cputhreads=str(data[7]), - ) - return info - - def list_vms(self, state=None): - self.conn = self.__get_conn() - vms = self.conn.find_vm(-1) - results = [] - for x in vms: - try: - if state: - vmstate = self.conn.get_status2(x) - if vmstate == state: - results.append(x.name()) - else: - results.append(x.name()) - except Exception: - pass - return results - - def virttype(self): - return self.__get_conn().get_type() - - def autostart(self, vmid, as_flag): - self.conn = self.__get_conn() - # Change autostart flag only if needed - if self.conn.get_autostart(vmid) != as_flag: - self.conn.set_autostart(vmid, as_flag) - return True - - return False - - def freemem(self): - self.conn = self.__get_conn() - return self.conn.getFreeMemory() - - def shutdown(self, vmid): - """ Make the machine with the given vmid stop running. Whatever that takes. """ - self.__get_conn() - self.conn.shutdown(vmid) - return 0 - - def pause(self, vmid): - """ Pause the machine with the given vmid. """ - - self.__get_conn() - return self.conn.suspend(vmid) - - def unpause(self, vmid): - """ Unpause the machine with the given vmid. """ - - self.__get_conn() - return self.conn.resume(vmid) - - def create(self, vmid): - """ Start the machine via the given vmid """ - - self.__get_conn() - return self.conn.create(vmid) - - def start(self, vmid): - """ Start the machine via the given id/name """ - - self.__get_conn() - return self.conn.create(vmid) - - def destroy(self, vmid): - """ Pull the virtual power from the virtual domain, giving it virtually no time to virtually shut down. """ - self.__get_conn() - return self.conn.destroy(vmid) - - def undefine(self, vmid): - """ Stop a domain, and then wipe it from the face of the earth. (delete disk/config file) """ - - self.__get_conn() - return self.conn.undefine(vmid) - - def status(self, vmid): - """ - Return a state suitable for server consumption. Aka, codes.py values, not XM output. - """ - self.__get_conn() - return self.conn.get_status(vmid) - - def get_xml(self, vmid): - """ - Receive a Vm id as input - Return an xml describing vm config returned by a libvirt call - """ - - self.__get_conn() - return self.conn.get_xml(vmid) - - def get_maxVcpus(self, vmid): - """ - Gets the max number of VCPUs on a guest - """ - - self.__get_conn() - return self.conn.get_maxVcpus(vmid) - - def get_max_memory(self, vmid): - """ - Gets the max memory on a guest - """ - - self.__get_conn() - return self.conn.get_MaxMemory(vmid) - - def define(self, xml): - """ - Define a guest with the given xml - """ - self.__get_conn() - return self.conn.define_from_xml(xml) - - -def core(module): - - state = module.params.get("state", None) - autostart = module.params.get("autostart", None) - guest = module.params.get("name", None) - command = module.params.get("command", None) - uri = module.params.get("uri", None) - xml = module.params.get("xml", None) - - v = Virt(uri, module) - res = dict() - - if state and command == "list_vms": - res = v.list_vms(state=state) - if not isinstance(res, dict): - res = {command: res} - return VIRT_SUCCESS, res - - if autostart is not None and command != "define": - if not guest: - module.fail_json(msg="autostart requires 1 argument: name") - try: - v.get_vm(guest) - except VMNotFound: - module.fail_json(msg="domain %s not found" % guest) - res["changed"] = v.autostart(guest, autostart) - if not command and not state: - return VIRT_SUCCESS, res - - if state: - if not guest: - module.fail_json(msg="state change requires a guest specified") - - if state == "running": - if v.status(guest) == "paused": - res["changed"] = True - res["msg"] = v.unpause(guest) - elif v.status(guest) != "running": - res["changed"] = True - res["msg"] = v.start(guest) - elif state == "shutdown": - if v.status(guest) != "shutdown": - res["changed"] = True - res["msg"] = v.shutdown(guest) - elif state == "destroyed": - if v.status(guest) != "shutdown": - res["changed"] = True - res["msg"] = v.destroy(guest) - elif state == "paused": - if v.status(guest) == "running": - res["changed"] = True - res["msg"] = v.pause(guest) - else: - module.fail_json(msg="unexpected state") - - return VIRT_SUCCESS, res - - if command: - if command in VM_COMMANDS: - if command == "define": - if not xml: - module.fail_json(msg="define requires xml argument") - if guest: - # there might be a mismatch between quest 'name' in the module and in the xml - module.warn("'xml' is given - ignoring 'name'") - found_name = re.search("(.*)", xml).groups() - if found_name: - domain_name = found_name[0] - else: - module.fail_json(msg="Could not find domain 'name' in xml") - - # From libvirt docs (https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainDefineXML): - # -- A previous definition for this domain would be overridden if it already exists. - # - # In real world testing with libvirt versions 1.2.17-13, 2.0.0-10 and 3.9.0-14 - # on qemu and lxc domains results in: - # operation failed: domain '' already exists with - # - # In case a domain would be indeed overwritten, we should protect idempotency: - try: - existing_domain = v.get_vm(domain_name) - except VMNotFound: - existing_domain = None - try: - domain = v.define(xml) - if existing_domain: - # if we are here, then libvirt redefined existing domain as the doc promised - if existing_domain.XMLDesc() != domain.XMLDesc(): - res = {"changed": True, "change_reason": "config changed"} - else: - res = {"changed": True, "created": domain.name()} - except libvirtError as e: - if e.get_error_code() != 9: # 9 means 'domain already exists' error - module.fail_json(msg="libvirtError: %s" % e.message) - if autostart is not None and v.autostart(domain_name, autostart): - res = {"changed": True, "change_reason": "autostart"} - - elif not guest: - module.fail_json(msg="%s requires 1 argument: guest" % command) - else: - res = getattr(v, command)(guest) - if not isinstance(res, dict): - res = {command: res} - - return VIRT_SUCCESS, res - - elif hasattr(v, command): - res = getattr(v, command)() - if not isinstance(res, dict): - res = {command: res} - return VIRT_SUCCESS, res - - else: - module.fail_json(msg="Command %s not recognized" % command) - - module.fail_json(msg="expected state or command parameter to be specified") - - -def main(): - module = AnsibleModule( - argument_spec=dict( - name=dict(type="str", aliases=["guest"]), - state=dict( - type="str", choices=["destroyed", "paused", "running", "shutdown"] - ), - autostart=dict(type="bool"), - command=dict(type="str", choices=ALL_COMMANDS), - uri=dict(type="str", default="qemu:///system"), - xml=dict(type="str"), - ), - ) - - if not HAS_VIRT: - module.fail_json( - msg="The `libvirt` module is not importable. Check the requirements." - ) - - rc = VIRT_SUCCESS - try: - rc, result = core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=traceback.format_exc()) - - if rc != 0: # something went wrong emit the msg - module.fail_json(rc=rc, msg=result) - else: - module.exit_json(**result) - - -if __name__ == "__main__": - main() diff --git a/roles/installer/tasks/59_cleanup_bootstrap.yml b/roles/installer/tasks/59_cleanup_bootstrap.yml index 3e4912d51..ee6c4e4c1 100644 --- a/roles/installer/tasks/59_cleanup_bootstrap.yml +++ b/roles/installer/tasks/59_cleanup_bootstrap.yml @@ -1,13 +1,13 @@ --- - name: Get list of all VMs - redhatci.ocp.virt: + community.libvirt.virt: command: list_vms register: all_vms become: true tags: cleanup - name: Get list of all running VMs - redhatci.ocp.virt: + community.libvirt.virt: command: list_vms state: running register: running_vms @@ -15,7 +15,7 @@ tags: cleanup - name: Get list of all paused VMs - redhatci.ocp.virt: + community.libvirt.virt: command: list_vms state: paused register: paused_vms @@ -23,7 +23,7 @@ tags: cleanup - name: Destroy old bootstrap VMs, if any - redhatci.ocp.virt: + community.libvirt.virt: name: "{{ item }}" command: destroy with_items: @@ -34,7 +34,7 @@ tags: cleanup - name: Undefine old bootstrap VMs, if any - redhatci.ocp.virt: + community.libvirt.virt: name: "{{ item }}" command: undefine with_items: "{{ all_vms.list_vms }}"