diff options
author | Ansible Core Team <info@ansible.com> | 2020-03-09 09:40:29 +0000 |
---|---|---|
committer | Ansible Core Team <info@ansible.com> | 2020-03-09 09:40:29 +0000 |
commit | 6e048cc2689d033b7757174d582077dd4af494b5 (patch) | |
tree | 05eb51738d05d26c992b439214c3dd7ffd1af538 /lib/ansible/module_utils/xenserver.py | |
parent | cb06e04e718f73173a6dcae1b082637063bae786 (diff) | |
download | ansible-6e048cc2689d033b7757174d582077dd4af494b5.tar.gz |
Migrated to community.general
Diffstat (limited to 'lib/ansible/module_utils/xenserver.py')
-rw-r--r-- | lib/ansible/module_utils/xenserver.py | 862 |
1 files changed, 0 insertions, 862 deletions
diff --git a/lib/ansible/module_utils/xenserver.py b/lib/ansible/module_utils/xenserver.py deleted file mode 100644 index dbc6a0adbe..0000000000 --- a/lib/ansible/module_utils/xenserver.py +++ /dev/null @@ -1,862 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright: (c) 2018, Bojan Vitnik <bvitnik@mainstream.rs> -# 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 - -import atexit -import time -import re -import traceback - -XENAPI_IMP_ERR = None -try: - import XenAPI - HAS_XENAPI = True -except ImportError: - HAS_XENAPI = False - XENAPI_IMP_ERR = traceback.format_exc() - -from ansible.module_utils.basic import env_fallback, missing_required_lib -from ansible.module_utils.common.network import is_mac -from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION - - -def xenserver_common_argument_spec(): - return dict( - hostname=dict(type='str', - aliases=['host', 'pool'], - required=False, - default='localhost', - fallback=(env_fallback, ['XENSERVER_HOST']), - ), - username=dict(type='str', - aliases=['user', 'admin'], - required=False, - default='root', - fallback=(env_fallback, ['XENSERVER_USER'])), - password=dict(type='str', - aliases=['pass', 'pwd'], - required=False, - no_log=True, - fallback=(env_fallback, ['XENSERVER_PASSWORD'])), - validate_certs=dict(type='bool', - required=False, - default=True, - fallback=(env_fallback, ['XENSERVER_VALIDATE_CERTS'])), - ) - - -def xapi_to_module_vm_power_state(power_state): - """Maps XAPI VM power states to module VM power states.""" - module_power_state_map = { - "running": "poweredon", - "halted": "poweredoff", - "suspended": "suspended", - "paused": "paused" - } - - return module_power_state_map.get(power_state) - - -def module_to_xapi_vm_power_state(power_state): - """Maps module VM power states to XAPI VM power states.""" - vm_power_state_map = { - "poweredon": "running", - "poweredoff": "halted", - "restarted": "running", - "suspended": "suspended", - "shutdownguest": "halted", - "rebootguest": "running", - } - - return vm_power_state_map.get(power_state) - - -def is_valid_ip_addr(ip_addr): - """Validates given string as IPv4 address for given string. - - Args: - ip_addr (str): string to validate as IPv4 address. - - Returns: - bool: True if string is valid IPv4 address, else False. - """ - ip_addr_split = ip_addr.split('.') - - if len(ip_addr_split) != 4: - return False - - for ip_addr_octet in ip_addr_split: - if not ip_addr_octet.isdigit(): - return False - - ip_addr_octet_int = int(ip_addr_octet) - - if ip_addr_octet_int < 0 or ip_addr_octet_int > 255: - return False - - return True - - -def is_valid_ip_netmask(ip_netmask): - """Validates given string as IPv4 netmask. - - Args: - ip_netmask (str): string to validate as IPv4 netmask. - - Returns: - bool: True if string is valid IPv4 netmask, else False. - """ - ip_netmask_split = ip_netmask.split('.') - - if len(ip_netmask_split) != 4: - return False - - valid_octet_values = ['0', '128', '192', '224', '240', '248', '252', '254', '255'] - - for ip_netmask_octet in ip_netmask_split: - if ip_netmask_octet not in valid_octet_values: - return False - - if ip_netmask_split[0] != '255' and (ip_netmask_split[1] != '0' or ip_netmask_split[2] != '0' or ip_netmask_split[3] != '0'): - return False - elif ip_netmask_split[1] != '255' and (ip_netmask_split[2] != '0' or ip_netmask_split[3] != '0'): - return False - elif ip_netmask_split[2] != '255' and ip_netmask_split[3] != '0': - return False - - return True - - -def is_valid_ip_prefix(ip_prefix): - """Validates given string as IPv4 prefix. - - Args: - ip_prefix (str): string to validate as IPv4 prefix. - - Returns: - bool: True if string is valid IPv4 prefix, else False. - """ - if not ip_prefix.isdigit(): - return False - - ip_prefix_int = int(ip_prefix) - - if ip_prefix_int < 0 or ip_prefix_int > 32: - return False - - return True - - -def ip_prefix_to_netmask(ip_prefix, skip_check=False): - """Converts IPv4 prefix to netmask. - - Args: - ip_prefix (str): IPv4 prefix to convert. - skip_check (bool): Skip validation of IPv4 prefix - (default: False). Use if you are sure IPv4 prefix is valid. - - Returns: - str: IPv4 netmask equivalent to given IPv4 prefix if - IPv4 prefix is valid, else an empty string. - """ - if skip_check: - ip_prefix_valid = True - else: - ip_prefix_valid = is_valid_ip_prefix(ip_prefix) - - if ip_prefix_valid: - return '.'.join([str((0xffffffff << (32 - int(ip_prefix)) >> i) & 0xff) for i in [24, 16, 8, 0]]) - else: - return "" - - -def ip_netmask_to_prefix(ip_netmask, skip_check=False): - """Converts IPv4 netmask to prefix. - - Args: - ip_netmask (str): IPv4 netmask to convert. - skip_check (bool): Skip validation of IPv4 netmask - (default: False). Use if you are sure IPv4 netmask is valid. - - Returns: - str: IPv4 prefix equivalent to given IPv4 netmask if - IPv4 netmask is valid, else an empty string. - """ - if skip_check: - ip_netmask_valid = True - else: - ip_netmask_valid = is_valid_ip_netmask(ip_netmask) - - if ip_netmask_valid: - return str(sum([bin(int(i)).count("1") for i in ip_netmask.split(".")])) - else: - return "" - - -def is_valid_ip6_addr(ip6_addr): - """Validates given string as IPv6 address. - - Args: - ip6_addr (str): string to validate as IPv6 address. - - Returns: - bool: True if string is valid IPv6 address, else False. - """ - ip6_addr = ip6_addr.lower() - ip6_addr_split = ip6_addr.split(':') - - if ip6_addr_split[0] == "": - ip6_addr_split.pop(0) - - if ip6_addr_split[-1] == "": - ip6_addr_split.pop(-1) - - if len(ip6_addr_split) > 8: - return False - - if ip6_addr_split.count("") > 1: - return False - elif ip6_addr_split.count("") == 1: - ip6_addr_split.remove("") - else: - if len(ip6_addr_split) != 8: - return False - - ip6_addr_hextet_regex = re.compile('^[0-9a-f]{1,4}$') - - for ip6_addr_hextet in ip6_addr_split: - if not bool(ip6_addr_hextet_regex.match(ip6_addr_hextet)): - return False - - return True - - -def is_valid_ip6_prefix(ip6_prefix): - """Validates given string as IPv6 prefix. - - Args: - ip6_prefix (str): string to validate as IPv6 prefix. - - Returns: - bool: True if string is valid IPv6 prefix, else False. - """ - if not ip6_prefix.isdigit(): - return False - - ip6_prefix_int = int(ip6_prefix) - - if ip6_prefix_int < 0 or ip6_prefix_int > 128: - return False - - return True - - -def get_object_ref(module, name, uuid=None, obj_type="VM", fail=True, msg_prefix=""): - """Finds and returns a reference to arbitrary XAPI object. - - An object is searched by using either name (name_label) or UUID - with UUID taken precedence over name. - - Args: - module: Reference to Ansible module object. - name (str): Name (name_label) of an object to search for. - uuid (str): UUID of an object to search for. - obj_type (str): Any valid XAPI object type. See XAPI docs. - fail (bool): Should function fail with error message if object - is not found or exit silently (default: True). The function - always fails if multiple objects with same name are found. - msg_prefix (str): A string error messages should be prefixed - with (default: ""). - - Returns: - XAPI reference to found object or None if object is not found - and fail=False. - """ - xapi_session = XAPI.connect(module) - - if obj_type in ["template", "snapshot"]: - real_obj_type = "VM" - elif obj_type == "home server": - real_obj_type = "host" - elif obj_type == "ISO image": - real_obj_type = "VDI" - else: - real_obj_type = obj_type - - obj_ref = None - - # UUID has precedence over name. - if uuid: - try: - # Find object by UUID. If no object is found using given UUID, - # an exception will be generated. - obj_ref = xapi_session.xenapi_request("%s.get_by_uuid" % real_obj_type, (uuid,)) - except XenAPI.Failure as f: - if fail: - module.fail_json(msg="%s%s with UUID '%s' not found!" % (msg_prefix, obj_type, uuid)) - elif name: - try: - # Find object by name (name_label). - obj_ref_list = xapi_session.xenapi_request("%s.get_by_name_label" % real_obj_type, (name,)) - except XenAPI.Failure as f: - module.fail_json(msg="XAPI ERROR: %s" % f.details) - - # If obj_ref_list is empty. - if not obj_ref_list: - if fail: - module.fail_json(msg="%s%s with name '%s' not found!" % (msg_prefix, obj_type, name)) - # If obj_ref_list contains multiple object references. - elif len(obj_ref_list) > 1: - module.fail_json(msg="%smultiple %ss with name '%s' found! Please use UUID." % (msg_prefix, obj_type, name)) - # The obj_ref_list contains only one object reference. - else: - obj_ref = obj_ref_list[0] - else: - module.fail_json(msg="%sno valid name or UUID supplied for %s!" % (msg_prefix, obj_type)) - - return obj_ref - - -def gather_vm_params(module, vm_ref): - """Gathers all VM parameters available in XAPI database. - - Args: - module: Reference to Ansible module object. - vm_ref (str): XAPI reference to VM. - - Returns: - dict: VM parameters. - """ - # We silently return empty vm_params if bad vm_ref was supplied. - if not vm_ref or vm_ref == "OpaqueRef:NULL": - return {} - - xapi_session = XAPI.connect(module) - - try: - vm_params = xapi_session.xenapi.VM.get_record(vm_ref) - - # We need some params like affinity, VBDs, VIFs, VDIs etc. dereferenced. - - # Affinity. - if vm_params['affinity'] != "OpaqueRef:NULL": - vm_affinity = xapi_session.xenapi.host.get_record(vm_params['affinity']) - vm_params['affinity'] = vm_affinity - else: - vm_params['affinity'] = {} - - # VBDs. - vm_vbd_params_list = [xapi_session.xenapi.VBD.get_record(vm_vbd_ref) for vm_vbd_ref in vm_params['VBDs']] - - # List of VBDs is usually sorted by userdevice but we sort just - # in case. We need this list sorted by userdevice so that we can - # make positional pairing with module.params['disks']. - vm_vbd_params_list = sorted(vm_vbd_params_list, key=lambda vm_vbd_params: int(vm_vbd_params['userdevice'])) - vm_params['VBDs'] = vm_vbd_params_list - - # VDIs. - for vm_vbd_params in vm_params['VBDs']: - if vm_vbd_params['VDI'] != "OpaqueRef:NULL": - vm_vdi_params = xapi_session.xenapi.VDI.get_record(vm_vbd_params['VDI']) - else: - vm_vdi_params = {} - - vm_vbd_params['VDI'] = vm_vdi_params - - # VIFs. - vm_vif_params_list = [xapi_session.xenapi.VIF.get_record(vm_vif_ref) for vm_vif_ref in vm_params['VIFs']] - - # List of VIFs is usually sorted by device but we sort just - # in case. We need this list sorted by device so that we can - # make positional pairing with module.params['networks']. - vm_vif_params_list = sorted(vm_vif_params_list, key=lambda vm_vif_params: int(vm_vif_params['device'])) - vm_params['VIFs'] = vm_vif_params_list - - # Networks. - for vm_vif_params in vm_params['VIFs']: - if vm_vif_params['network'] != "OpaqueRef:NULL": - vm_network_params = xapi_session.xenapi.network.get_record(vm_vif_params['network']) - else: - vm_network_params = {} - - vm_vif_params['network'] = vm_network_params - - # Guest metrics. - if vm_params['guest_metrics'] != "OpaqueRef:NULL": - vm_guest_metrics = xapi_session.xenapi.VM_guest_metrics.get_record(vm_params['guest_metrics']) - vm_params['guest_metrics'] = vm_guest_metrics - else: - vm_params['guest_metrics'] = {} - - # Detect customization agent. - xenserver_version = get_xenserver_version(module) - - if (xenserver_version[0] >= 7 and xenserver_version[1] >= 0 and vm_params.get('guest_metrics') and - "feature-static-ip-setting" in vm_params['guest_metrics']['other']): - vm_params['customization_agent'] = "native" - else: - vm_params['customization_agent'] = "custom" - - except XenAPI.Failure as f: - module.fail_json(msg="XAPI ERROR: %s" % f.details) - - return vm_params - - -def gather_vm_facts(module, vm_params): - """Gathers VM facts. - - Args: - module: Reference to Ansible module object. - vm_params (dict): A dictionary with VM parameters as returned - by gather_vm_params() function. - - Returns: - dict: VM facts. - """ - # We silently return empty vm_facts if no vm_params are available. - if not vm_params: - return {} - - xapi_session = XAPI.connect(module) - - # Gather facts. - vm_facts = { - "state": xapi_to_module_vm_power_state(vm_params['power_state'].lower()), - "name": vm_params['name_label'], - "name_desc": vm_params['name_description'], - "uuid": vm_params['uuid'], - "is_template": vm_params['is_a_template'], - "folder": vm_params['other_config'].get('folder', ''), - "hardware": { - "num_cpus": int(vm_params['VCPUs_max']), - "num_cpu_cores_per_socket": int(vm_params['platform'].get('cores-per-socket', '1')), - "memory_mb": int(int(vm_params['memory_dynamic_max']) / 1048576), - }, - "disks": [], - "cdrom": {}, - "networks": [], - "home_server": vm_params['affinity'].get('name_label', ''), - "domid": vm_params['domid'], - "platform": vm_params['platform'], - "other_config": vm_params['other_config'], - "xenstore_data": vm_params['xenstore_data'], - "customization_agent": vm_params['customization_agent'], - } - - for vm_vbd_params in vm_params['VBDs']: - if vm_vbd_params['type'] == "Disk": - vm_disk_sr_params = xapi_session.xenapi.SR.get_record(vm_vbd_params['VDI']['SR']) - - vm_disk_params = { - "size": int(vm_vbd_params['VDI']['virtual_size']), - "name": vm_vbd_params['VDI']['name_label'], - "name_desc": vm_vbd_params['VDI']['name_description'], - "sr": vm_disk_sr_params['name_label'], - "sr_uuid": vm_disk_sr_params['uuid'], - "os_device": vm_vbd_params['device'], - "vbd_userdevice": vm_vbd_params['userdevice'], - } - - vm_facts['disks'].append(vm_disk_params) - elif vm_vbd_params['type'] == "CD": - if vm_vbd_params['empty']: - vm_facts['cdrom'].update(type="none") - else: - vm_facts['cdrom'].update(type="iso") - vm_facts['cdrom'].update(iso_name=vm_vbd_params['VDI']['name_label']) - - for vm_vif_params in vm_params['VIFs']: - vm_guest_metrics_networks = vm_params['guest_metrics'].get('networks', {}) - - vm_network_params = { - "name": vm_vif_params['network']['name_label'], - "mac": vm_vif_params['MAC'], - "vif_device": vm_vif_params['device'], - "mtu": vm_vif_params['MTU'], - "ip": vm_guest_metrics_networks.get("%s/ip" % vm_vif_params['device'], ''), - "prefix": "", - "netmask": "", - "gateway": "", - "ip6": [vm_guest_metrics_networks[ipv6] for ipv6 in sorted(vm_guest_metrics_networks.keys()) if ipv6.startswith("%s/ipv6/" % - vm_vif_params['device'])], - "prefix6": "", - "gateway6": "", - } - - if vm_params['customization_agent'] == "native": - if vm_vif_params['ipv4_addresses'] and vm_vif_params['ipv4_addresses'][0]: - vm_network_params['prefix'] = vm_vif_params['ipv4_addresses'][0].split('/')[1] - vm_network_params['netmask'] = ip_prefix_to_netmask(vm_network_params['prefix']) - - vm_network_params['gateway'] = vm_vif_params['ipv4_gateway'] - - if vm_vif_params['ipv6_addresses'] and vm_vif_params['ipv6_addresses'][0]: - vm_network_params['prefix6'] = vm_vif_params['ipv6_addresses'][0].split('/')[1] - - vm_network_params['gateway6'] = vm_vif_params['ipv6_gateway'] - - elif vm_params['customization_agent'] == "custom": - vm_xenstore_data = vm_params['xenstore_data'] - - for f in ['prefix', 'netmask', 'gateway', 'prefix6', 'gateway6']: - vm_network_params[f] = vm_xenstore_data.get("vm-data/networks/%s/%s" % (vm_vif_params['device'], f), "") - - vm_facts['networks'].append(vm_network_params) - - return vm_facts - - -def set_vm_power_state(module, vm_ref, power_state, timeout=300): - """Controls VM power state. - - Args: - module: Reference to Ansible module object. - vm_ref (str): XAPI reference to VM. - power_state (str): Power state to put VM into. Accepted values: - - - poweredon - - poweredoff - - restarted - - suspended - - shutdownguest - - rebootguest - - timeout (int): timeout in seconds (default: 300). - - Returns: - tuple (bool, str): Bool element is True if VM power state has - changed by calling this function, else False. Str element carries - a value of resulting power state as defined by XAPI - 'running', - 'halted' or 'suspended'. - """ - # Fail if we don't have a valid VM reference. - if not vm_ref or vm_ref == "OpaqueRef:NULL": - module.fail_json(msg="Cannot set VM power state. Invalid VM reference supplied!") - - xapi_session = XAPI.connect(module) - - power_state = power_state.replace('_', '').replace('-', '').lower() - vm_power_state_resulting = module_to_xapi_vm_power_state(power_state) - - state_changed = False - - try: - # Get current state of the VM. - vm_power_state_current = xapi_to_module_vm_power_state(xapi_session.xenapi.VM.get_power_state(vm_ref).lower()) - - if vm_power_state_current != power_state: - if power_state == "poweredon": - if not module.check_mode: - # VM can be in either halted, suspended, paused or running state. - # For VM to be in running state, start has to be called on halted, - # resume on suspended and unpause on paused VM. - if vm_power_state_current == "poweredoff": - xapi_session.xenapi.VM.start(vm_ref, False, False) - elif vm_power_state_current == "suspended": - xapi_session.xenapi.VM.resume(vm_ref, False, False) - elif vm_power_state_current == "paused": - xapi_session.xenapi.VM.unpause(vm_ref) - elif power_state == "poweredoff": - if not module.check_mode: - # hard_shutdown will halt VM regardless of current state. - xapi_session.xenapi.VM.hard_shutdown(vm_ref) - elif power_state == "restarted": - # hard_reboot will restart VM only if VM is in paused or running state. - if vm_power_state_current in ["paused", "poweredon"]: - if not module.check_mode: - xapi_session.xenapi.VM.hard_reboot(vm_ref) - else: - module.fail_json(msg="Cannot restart VM in state '%s'!" % vm_power_state_current) - elif power_state == "suspended": - # running state is required for suspend. - if vm_power_state_current == "poweredon": - if not module.check_mode: - xapi_session.xenapi.VM.suspend(vm_ref) - else: - module.fail_json(msg="Cannot suspend VM in state '%s'!" % vm_power_state_current) - elif power_state == "shutdownguest": - # running state is required for guest shutdown. - if vm_power_state_current == "poweredon": - if not module.check_mode: - if timeout == 0: - xapi_session.xenapi.VM.clean_shutdown(vm_ref) - else: - task_ref = xapi_session.xenapi.Async.VM.clean_shutdown(vm_ref) - task_result = wait_for_task(module, task_ref, timeout) - - if task_result: - module.fail_json(msg="Guest shutdown task failed: '%s'!" % task_result) - else: - module.fail_json(msg="Cannot shutdown guest when VM is in state '%s'!" % vm_power_state_current) - elif power_state == "rebootguest": - # running state is required for guest reboot. - if vm_power_state_current == "poweredon": - if not module.check_mode: - if timeout == 0: - xapi_session.xenapi.VM.clean_reboot(vm_ref) - else: - task_ref = xapi_session.xenapi.Async.VM.clean_reboot(vm_ref) - task_result = wait_for_task(module, task_ref, timeout) - - if task_result: - module.fail_json(msg="Guest reboot task failed: '%s'!" % task_result) - else: - module.fail_json(msg="Cannot reboot guest when VM is in state '%s'!" % vm_power_state_current) - else: - module.fail_json(msg="Requested VM power state '%s' is unsupported!" % power_state) - - state_changed = True - except XenAPI.Failure as f: - module.fail_json(msg="XAPI ERROR: %s" % f.details) - - return (state_changed, vm_power_state_resulting) - - -def wait_for_task(module, task_ref, timeout=300): - """Waits for async XAPI task to finish. - - Args: - module: Reference to Ansible module object. - task_ref (str): XAPI reference to task. - timeout (int): timeout in seconds (default: 300). - - Returns: - str: failure message on failure, else an empty string. - """ - # Fail if we don't have a valid task reference. - if not task_ref or task_ref == "OpaqueRef:NULL": - module.fail_json(msg="Cannot wait for task. Invalid task reference supplied!") - - xapi_session = XAPI.connect(module) - - interval = 2 - - result = "" - - # If we have to wait indefinitely, make time_left larger than 0 so we can - # enter while loop. - if timeout == 0: - time_left = 1 - else: - time_left = timeout - - try: - while time_left > 0: - task_status = xapi_session.xenapi.task.get_status(task_ref).lower() - - if task_status == "pending": - # Task is still running. - time.sleep(interval) - - # We decrease time_left only if we don't wait indefinitely. - if timeout != 0: - time_left -= interval - - continue - elif task_status == "success": - # Task is done. - break - else: - # Task failed. - result = task_status - break - else: - # We timed out. - result = "timeout" - - xapi_session.xenapi.task.destroy(task_ref) - except XenAPI.Failure as f: - module.fail_json(msg="XAPI ERROR: %s" % f.details) - - return result - - -def wait_for_vm_ip_address(module, vm_ref, timeout=300): - """Waits for VM to acquire an IP address. - - Args: - module: Reference to Ansible module object. - vm_ref (str): XAPI reference to VM. - timeout (int): timeout in seconds (default: 300). - - Returns: - dict: VM guest metrics as retrieved by - VM_guest_metrics.get_record() XAPI method with info - on IP address acquired. - """ - # Fail if we don't have a valid VM reference. - if not vm_ref or vm_ref == "OpaqueRef:NULL": - module.fail_json(msg="Cannot wait for VM IP address. Invalid VM reference supplied!") - - xapi_session = XAPI.connect(module) - - vm_guest_metrics = {} - - try: - # We translate VM power state string so that error message can be - # consistent with module VM power states. - vm_power_state = xapi_to_module_vm_power_state(xapi_session.xenapi.VM.get_power_state(vm_ref).lower()) - - if vm_power_state != 'poweredon': - module.fail_json(msg="Cannot wait for VM IP address when VM is in state '%s'!" % vm_power_state) - - interval = 2 - - # If we have to wait indefinitely, make time_left larger than 0 so we can - # enter while loop. - if timeout == 0: - time_left = 1 - else: - time_left = timeout - - while time_left > 0: - vm_guest_metrics_ref = xapi_session.xenapi.VM.get_guest_metrics(vm_ref) - - if vm_guest_metrics_ref != "OpaqueRef:NULL": - vm_guest_metrics = xapi_session.xenapi.VM_guest_metrics.get_record(vm_guest_metrics_ref) - vm_ips = vm_guest_metrics['networks'] - - if "0/ip" in vm_ips: - break - - time.sleep(interval) - - # We decrease time_left only if we don't wait indefinitely. - if timeout != 0: - time_left -= interval - else: - # We timed out. - module.fail_json(msg="Timed out waiting for VM IP address!") - - except XenAPI.Failure as f: - module.fail_json(msg="XAPI ERROR: %s" % f.details) - - return vm_guest_metrics - - -def get_xenserver_version(module): - """Returns XenServer version. - - Args: - module: Reference to Ansible module object. - - Returns: - list: Element [0] is major version. Element [1] is minor version. - Element [2] is update number. - """ - xapi_session = XAPI.connect(module) - - host_ref = xapi_session.xenapi.session.get_this_host(xapi_session._session) - - try: - xenserver_version = [int(version_number) for version_number in xapi_session.xenapi.host.get_software_version(host_ref)['product_version'].split('.')] - except ValueError: - xenserver_version = [0, 0, 0] - - return xenserver_version - - -class XAPI(object): - """Class for XAPI session management.""" - _xapi_session = None - - @classmethod - def connect(cls, module, disconnect_atexit=True): - """Establishes XAPI connection and returns session reference. - - If no existing session is available, establishes a new one - and returns it, else returns existing one. - - Args: - module: Reference to Ansible module object. - disconnect_atexit (bool): Controls if method should - register atexit handler to disconnect from XenServer - on module exit (default: True). - - Returns: - XAPI session reference. - """ - if cls._xapi_session is not None: - return cls._xapi_session - - hostname = module.params['hostname'] - username = module.params['username'] - password = module.params['password'] - ignore_ssl = not module.params['validate_certs'] - - if hostname == 'localhost': - cls._xapi_session = XenAPI.xapi_local() - username = '' - password = '' - else: - # If scheme is not specified we default to http:// because https:// - # is problematic in most setups. - if not hostname.startswith("http://") and not hostname.startswith("https://"): - hostname = "http://%s" % hostname - - try: - # ignore_ssl is supported in XenAPI library from XenServer 7.2 - # SDK onward but there is no way to tell which version we - # are using. TypeError will be raised if ignore_ssl is not - # supported. Additionally, ignore_ssl requires Python 2.7.9 - # or newer. - cls._xapi_session = XenAPI.Session(hostname, ignore_ssl=ignore_ssl) - except TypeError: - # Try without ignore_ssl. - cls._xapi_session = XenAPI.Session(hostname) - - if not password: - password = '' - - try: - cls._xapi_session.login_with_password(username, password, ANSIBLE_VERSION, 'Ansible') - except XenAPI.Failure as f: - module.fail_json(msg="Unable to log on to XenServer at %s as %s: %s" % (hostname, username, f.details)) - - # Disabling atexit should be used in special cases only. - if disconnect_atexit: - atexit.register(cls._xapi_session.logout) - - return cls._xapi_session - - -class XenServerObject(object): - """Base class for all XenServer objects. - - This class contains active XAPI session reference and common - attributes with useful info about XenServer host/pool. - - Attributes: - module: Reference to Ansible module object. - xapi_session: Reference to XAPI session. - pool_ref (str): XAPI reference to a pool currently connected to. - default_sr_ref (str): XAPI reference to a pool default - Storage Repository. - host_ref (str): XAPI rerefence to a host currently connected to. - xenserver_version (list of str): Contains XenServer major and - minor version. - """ - - def __init__(self, module): - """Inits XenServerObject using common module parameters. - - Args: - module: Reference to Ansible module object. - """ - if not HAS_XENAPI: - module.fail_json(changed=False, msg=missing_required_lib("XenAPI"), exception=XENAPI_IMP_ERR) - - self.module = module - self.xapi_session = XAPI.connect(module) - - try: - self.pool_ref = self.xapi_session.xenapi.pool.get_all()[0] - self.default_sr_ref = self.xapi_session.xenapi.pool.get_default_SR(self.pool_ref) - self.xenserver_version = get_xenserver_version(module) - except XenAPI.Failure as f: - self.module.fail_json(msg="XAPI ERROR: %s" % f.details) |