PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/xapi_virt.py |
""" This module (mostly) uses the XenAPI to manage Xen virtual machines. Big fat warning: the XenAPI used in this file is the one bundled with Xen Source, NOT XenServer nor Xen Cloud Platform. As a matter of fact it *will* fail under those platforms. From what I've read, little work is needed to adapt this code to XS/XCP, mostly playing with XenAPI version, but as XCP is not taking precedence on Xen Source on many platforms, please keep compatibility in mind. Useful documentation: . http://downloads.xen.org/Wiki/XenAPI/xenapi-1.0.6.pdf . http://docs.vmd.citrix.com/XenServer/6.0.0/1.0/en_gb/api/ . https://github.com/xapi-project/xen-api/tree/master/scripts/examples/python . http://xenbits.xen.org/gitweb/?p=xen.git;a=tree;f=tools/python/xen/xm;hb=HEAD """ import contextlib import importlib import os import sys import salt.modules.cmdmod import salt.utils.files import salt.utils.path import salt.utils.stringutils from salt.exceptions import CommandExecutionError # Define the module's virtual name __virtualname__ = "virt" # This module has only been tested on Debian GNU/Linux and NetBSD, it # probably needs more path appending for other distributions. # The path to append is the path to python Xen libraries, where resides # XenAPI. def _check_xenapi(): if __grains__["os"] == "Debian": debian_xen_version = "/usr/lib/xen-common/bin/xen-version" if os.path.isfile(debian_xen_version): # __salt__ is not available in __virtual__ xenversion = salt.modules.cmdmod._run_quiet(debian_xen_version) xapipath = f"/usr/lib/xen-{xenversion}/lib/python" if os.path.isdir(xapipath): sys.path.append(xapipath) try: return importlib.import_module("xen.xm.XenAPI") except (ImportError, AttributeError): return False def __virtual__(): if _check_xenapi() is not False: return __virtualname__ return (False, "Module xapi: xenapi check failed") @contextlib.contextmanager def _get_xapi_session(): """ Get a session to XenAPI. By default, use the local UNIX socket. """ _xenapi = _check_xenapi() xapi_uri = __salt__["config.option"]("xapi.uri") xapi_login = __salt__["config.option"]("xapi.login") xapi_password = __salt__["config.option"]("xapi.password") if not xapi_uri: # xend local UNIX socket xapi_uri = "httpu:///var/run/xend/xen-api.sock" if not xapi_login: xapi_login = "" if not xapi_password: xapi_password = "" try: session = _xenapi.Session(xapi_uri) session.xenapi.login_with_password(xapi_login, xapi_password) yield session.xenapi except Exception: # pylint: disable=broad-except raise CommandExecutionError("Failed to connect to XenAPI socket.") finally: session.xenapi.session.logout() # Used rectypes (Record types): # # host # host_cpu # VM # VIF # VBD def _get_xtool(): """ Internal, returns xl or xm command line path """ for xtool in ["xl", "xm"]: path = salt.utils.path.which(xtool) if path is not None: return path def _get_all(xapi, rectype): """ Internal, returns all members of rectype """ return getattr(xapi, rectype).get_all() def _get_label_uuid(xapi, rectype, label): """ Internal, returns label's uuid """ try: return getattr(xapi, rectype).get_by_name_label(label)[0] except Exception: # pylint: disable=broad-except return False def _get_record(xapi, rectype, uuid): """ Internal, returns a full record for uuid """ return getattr(xapi, rectype).get_record(uuid) def _get_record_by_label(xapi, rectype, label): """ Internal, returns a full record for uuid """ uuid = _get_label_uuid(xapi, rectype, label) if uuid is False: return False return getattr(xapi, rectype).get_record(uuid) def _get_metrics_record(xapi, rectype, record): """ Internal, returns metrics record for a rectype """ metrics_id = record["metrics"] return getattr(xapi, f"{rectype}_metrics").get_record(metrics_id) def _get_val(record, keys): """ Internal, get value from record """ data = record for key in keys: if key in data: data = data[key] else: return None return data def list_domains(): """ Return a list of virtual machine names on the minion CLI Example: .. code-block:: bash salt '*' virt.list_domains """ with _get_xapi_session() as xapi: hosts = xapi.VM.get_all() ret = [] for _host in hosts: if xapi.VM.get_record(_host)["is_control_domain"] is False: ret.append(xapi.VM.get_name_label(_host)) return ret def vm_info(vm_=None): """ Return detailed information about the vms. If you pass a VM name in as an argument then it will return info for just the named VM, otherwise it will return all VMs. CLI Example: .. code-block:: bash salt '*' virt.vm_info """ with _get_xapi_session() as xapi: def _info(vm_): vm_rec = _get_record_by_label(xapi, "VM", vm_) if vm_rec is False: return False vm_metrics_rec = _get_metrics_record(xapi, "VM", vm_rec) return { "cpu": vm_metrics_rec["VCPUs_number"], "maxCPU": _get_val(vm_rec, ["VCPUs_max"]), "cputime": vm_metrics_rec["VCPUs_utilisation"], "disks": get_disks(vm_), "nics": get_nics(vm_), "maxMem": int(_get_val(vm_rec, ["memory_dynamic_max"])), "mem": int(vm_metrics_rec["memory_actual"]), "state": _get_val(vm_rec, ["power_state"]), } info = {} if vm_: ret = _info(vm_) if ret is not None: info[vm_] = ret else: for vm_ in list_domains(): ret = _info(vm_) if ret is not None: info[vm_] = _info(vm_) return info def vm_state(vm_=None): """ Return list of all the vms and their state. If you pass a VM name in as an argument then it will return info for just the named VM, otherwise it will return all VMs. CLI Example: .. code-block:: bash salt '*' virt.vm_state <vm name> """ with _get_xapi_session() as xapi: info = {} if vm_: info[vm_] = _get_record_by_label(xapi, "VM", vm_)["power_state"] return info for vm_ in list_domains(): info[vm_] = _get_record_by_label(xapi, "VM", vm_)["power_state"] return info def node_info(): """ Return a dict with information about this node CLI Example: .. code-block:: bash salt '*' virt.node_info """ with _get_xapi_session() as xapi: # get node uuid host_rec = _get_record(xapi, "host", _get_all(xapi, "host")[0]) # get first CPU (likely to be a core) uuid host_cpu_rec = _get_record(xapi, "host_cpu", host_rec["host_CPUs"][0]) # get related metrics host_metrics_rec = _get_metrics_record(xapi, "host", host_rec) # adapted / cleaned up from Xen's xm def getCpuMhz(): cpu_speeds = [ int(host_cpu_rec["speed"]) for host_cpu_it in host_cpu_rec if "speed" in host_cpu_it ] if cpu_speeds: return sum(cpu_speeds) / len(cpu_speeds) else: return 0 def getCpuFeatures(): if host_cpu_rec: return host_cpu_rec["features"] def getFreeCpuCount(): cnt = 0 for host_cpu_it in host_cpu_rec: if not host_cpu_rec["cpu_pool"]: cnt += 1 return cnt info = { "cpucores": _get_val(host_rec, ["cpu_configuration", "nr_cpus"]), "cpufeatures": getCpuFeatures(), "cpumhz": getCpuMhz(), "cpuarch": _get_val(host_rec, ["software_version", "machine"]), "cputhreads": _get_val(host_rec, ["cpu_configuration", "threads_per_core"]), "phymemory": int(host_metrics_rec["memory_total"]) / 1024 / 1024, "cores_per_sockets": _get_val( host_rec, ["cpu_configuration", "cores_per_socket"] ), "free_cpus": getFreeCpuCount(), "free_memory": int(host_metrics_rec["memory_free"]) / 1024 / 1024, "xen_major": _get_val(host_rec, ["software_version", "xen_major"]), "xen_minor": _get_val(host_rec, ["software_version", "xen_minor"]), "xen_extra": _get_val(host_rec, ["software_version", "xen_extra"]), "xen_caps": " ".join(_get_val(host_rec, ["capabilities"])), "xen_scheduler": _get_val(host_rec, ["sched_policy"]), "xen_pagesize": _get_val(host_rec, ["other_config", "xen_pagesize"]), "platform_params": _get_val(host_rec, ["other_config", "platform_params"]), "xen_commandline": _get_val(host_rec, ["other_config", "xen_commandline"]), "xen_changeset": _get_val(host_rec, ["software_version", "xen_changeset"]), "cc_compiler": _get_val(host_rec, ["software_version", "cc_compiler"]), "cc_compile_by": _get_val(host_rec, ["software_version", "cc_compile_by"]), "cc_compile_domain": _get_val( host_rec, ["software_version", "cc_compile_domain"] ), "cc_compile_date": _get_val( host_rec, ["software_version", "cc_compile_date"] ), "xend_config_format": _get_val( host_rec, ["software_version", "xend_config_format"] ), } return info def get_nics(vm_): """ Return info about the network interfaces of a named vm CLI Example: .. code-block:: bash salt '*' virt.get_nics <vm name> """ with _get_xapi_session() as xapi: nic = {} vm_rec = _get_record_by_label(xapi, "VM", vm_) if vm_rec is False: return False for vif in vm_rec["VIFs"]: vif_rec = _get_record(xapi, "VIF", vif) nic[vif_rec["MAC"]] = { "mac": vif_rec["MAC"], "device": vif_rec["device"], "mtu": vif_rec["MTU"], } return nic def get_macs(vm_): """ Return a list off MAC addresses from the named vm CLI Example: .. code-block:: bash salt '*' virt.get_macs <vm name> """ macs = [] nics = get_nics(vm_) if nics is None: return None for nic in nics: macs.append(nic) return macs def get_disks(vm_): """ Return the disks of a named vm CLI Example: .. code-block:: bash salt '*' virt.get_disks <vm name> """ with _get_xapi_session() as xapi: disk = {} vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False for vbd in xapi.VM.get_VBDs(vm_uuid): dev = xapi.VBD.get_device(vbd) if not dev: continue prop = xapi.VBD.get_runtime_properties(vbd) disk[dev] = { "backend": prop["backend"], "type": prop["device-type"], "protocol": prop["protocol"], } return disk def setmem(vm_, memory): """ Changes the amount of memory allocated to VM. Memory is to be specified in MB CLI Example: .. code-block:: bash salt '*' virt.setmem myvm 768 """ with _get_xapi_session() as xapi: mem_target = int(memory) * 1024 * 1024 vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.set_memory_dynamic_max_live(vm_uuid, mem_target) xapi.VM.set_memory_dynamic_min_live(vm_uuid, mem_target) return True except Exception: # pylint: disable=broad-except return False def setvcpus(vm_, vcpus): """ Changes the amount of vcpus allocated to VM. vcpus is an int representing the number to be assigned CLI Example: .. code-block:: bash salt '*' virt.setvcpus myvm 2 """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.set_VCPUs_number_live(vm_uuid, vcpus) return True except Exception: # pylint: disable=broad-except return False def vcpu_pin(vm_, vcpu, cpus): """ Set which CPUs a VCPU can use. CLI Example: .. code-block:: bash salt 'foo' virt.vcpu_pin domU-id 2 1 salt 'foo' virt.vcpu_pin domU-id 2 2-6 """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False # from xm's main def cpu_make_map(cpulist): cpus = [] for c in cpulist.split(","): if c == "": continue if "-" in c: (x, y) = c.split("-") for i in range(int(x), int(y) + 1): cpus.append(int(i)) else: # remove this element from the list if c[0] == "^": cpus = [x for x in cpus if x != int(c[1:])] else: cpus.append(int(c)) cpus.sort() return ",".join(map(str, cpus)) if cpus == "all": cpumap = cpu_make_map("0-63") else: cpumap = cpu_make_map(f"{cpus}") try: xapi.VM.add_to_VCPUs_params_live(vm_uuid, f"cpumap{vcpu}", cpumap) return True # VM.add_to_VCPUs_params_live() implementation in xend 4.1+ has # a bug which makes the client call fail. # That code is accurate for all others XenAPI implementations, but # for that particular one, fallback to xm / xl instead. except Exception: # pylint: disable=broad-except return __salt__["cmd.run"]( f"{_get_xtool()} vcpu-pin {vm_} {vcpu} {cpus}", python_shell=False, ) def freemem(): """ Return an int representing the amount of memory that has not been given to virtual machines on this node CLI Example: .. code-block:: bash salt '*' virt.freemem """ return node_info()["free_memory"] def freecpu(): """ Return an int representing the number of unallocated cpus on this hypervisor CLI Example: .. code-block:: bash salt '*' virt.freecpu """ return node_info()["free_cpus"] def full_info(): """ Return the node_info, vm_info and freemem CLI Example: .. code-block:: bash salt '*' virt.full_info """ return {"node_info": node_info(), "vm_info": vm_info()} def shutdown(vm_): """ Send a soft shutdown signal to the named vm CLI Example: .. code-block:: bash salt '*' virt.shutdown <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.clean_shutdown(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def pause(vm_): """ Pause the named vm CLI Example: .. code-block:: bash salt '*' virt.pause <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.pause(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def resume(vm_): """ Resume the named vm CLI Example: .. code-block:: bash salt '*' virt.resume <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.unpause(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def start(config_): """ Start a defined domain CLI Example: .. code-block:: bash salt '*' virt.start <path to Xen cfg file> """ # FIXME / TODO # This function does NOT use the XenAPI. Instead, it use good old xm / xl. # On Xen Source, creating a virtual machine using XenAPI is really painful. # XCP / XS make it really easy using xapi.Async.VM.start instead. Anyone? return __salt__["cmd.run"](f"{_get_xtool()} create {config_}", python_shell=False) def reboot(vm_): """ Reboot a domain via ACPI request CLI Example: .. code-block:: bash salt '*' virt.reboot <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.clean_reboot(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def reset(vm_): """ Reset a VM by emulating the reset button on a physical machine CLI Example: .. code-block:: bash salt '*' virt.reset <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.hard_reboot(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def migrate(vm_, target, live=1, port=0, node=-1, ssl=None, change_home_server=0): """ Migrates the virtual machine to another hypervisor CLI Example: .. code-block:: bash salt '*' virt.migrate <vm name> <target hypervisor> [live] [port] [node] [ssl] [change_home_server] Optional values: live Use live migration port Use a specified port node Use specified NUMA node on target ssl use ssl connection for migration change_home_server change home server for managed domains """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False other_config = { "port": port, "node": node, "ssl": ssl, "change_home_server": change_home_server, } try: xapi.VM.migrate(vm_uuid, target, bool(live), other_config) return True except Exception: # pylint: disable=broad-except return False def stop(vm_): """ Hard power down the virtual machine, this is equivalent to pulling the power CLI Example: .. code-block:: bash salt '*' virt.stop <vm name> """ with _get_xapi_session() as xapi: vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False try: xapi.VM.hard_shutdown(vm_uuid) return True except Exception: # pylint: disable=broad-except return False def is_hyper(): """ Returns a bool whether or not this node is a hypervisor of any kind CLI Example: .. code-block:: bash salt '*' virt.is_hyper """ try: if __grains__["virtual_subtype"] != "Xen Dom0": return False except KeyError: # virtual_subtype isn't set everywhere. return False try: with salt.utils.files.fopen("/proc/modules") as fp_: if "xen_" not in salt.utils.stringutils.to_unicode(fp_.read()): return False except OSError: return False # there must be a smarter way... return "xenstore" in __salt__["cmd.run"](__grains__["ps"]) def vm_cputime(vm_=None): """ Return cputime used by the vms on this hyper in a list of dicts: .. code-block:: python [ 'your-vm': { 'cputime' <int> 'cputime_percent' <int> }, ... ] If you pass a VM name in as an argument then it will return info for just the named VM, otherwise it will return all VMs. CLI Example: .. code-block:: bash salt '*' virt.vm_cputime """ with _get_xapi_session() as xapi: def _info(vm_): host_rec = _get_record_by_label(xapi, "VM", vm_) host_cpus = len(host_rec["host_CPUs"]) if host_rec is False: return False host_metrics = _get_metrics_record(xapi, "VM", host_rec) vcpus = int(host_metrics["VCPUs_number"]) cputime = int(host_metrics["VCPUs_utilisation"]["0"]) cputime_percent = 0 if cputime: # Divide by vcpus to always return a number between 0 and 100 cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus return { "cputime": int(cputime), "cputime_percent": int(f"{cputime_percent:.0f}"), } info = {} if vm_: info[vm_] = _info(vm_) return info for vm_ in list_domains(): info[vm_] = _info(vm_) return info def vm_netstats(vm_=None): """ Return combined network counters used by the vms on this hyper in a list of dicts: .. code-block:: python [ 'your-vm': { 'io_read_kbs' : 0, 'io_total_read_kbs' : 0, 'io_total_write_kbs' : 0, 'io_write_kbs' : 0 }, ... ] If you pass a VM name in as an argument then it will return info for just the named VM, otherwise it will return all VMs. CLI Example: .. code-block:: bash salt '*' virt.vm_netstats """ with _get_xapi_session() as xapi: def _info(vm_): ret = {} vm_rec = _get_record_by_label(xapi, "VM", vm_) if vm_rec is False: return False for vif in vm_rec["VIFs"]: vif_rec = _get_record(xapi, "VIF", vif) ret[vif_rec["device"]] = _get_metrics_record(xapi, "VIF", vif_rec) del ret[vif_rec["device"]]["last_updated"] return ret info = {} if vm_: info[vm_] = _info(vm_) else: for vm_ in list_domains(): info[vm_] = _info(vm_) return info def vm_diskstats(vm_=None): """ Return disk usage counters used by the vms on this hyper in a list of dicts: .. code-block:: python [ 'your-vm': { 'io_read_kbs' : 0, 'io_write_kbs' : 0 }, ... ] If you pass a VM name in as an argument then it will return info for just the named VM, otherwise it will return all VMs. CLI Example: .. code-block:: bash salt '*' virt.vm_diskstats """ with _get_xapi_session() as xapi: def _info(vm_): ret = {} vm_uuid = _get_label_uuid(xapi, "VM", vm_) if vm_uuid is False: return False for vbd in xapi.VM.get_VBDs(vm_uuid): vbd_rec = _get_record(xapi, "VBD", vbd) ret[vbd_rec["device"]] = _get_metrics_record(xapi, "VBD", vbd_rec) del ret[vbd_rec["device"]]["last_updated"] return ret info = {} if vm_: info[vm_] = _info(vm_) else: for vm_ in list_domains(): info[vm_] = _info(vm_) return info