Initial commit for xenserver module_util unit tests (#50850)

pull/51761/head
Bojan Vitnik 6 years ago committed by Matt Clay
parent 33b07f322c
commit 64084d593e

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, Bojan Vitnik <bvitnik@mainstream.rs>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class AnsibleModuleException(Exception):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
class ExitJsonException(AnsibleModuleException):
pass
class FailJsonException(AnsibleModuleException):
pass
class FakeAnsibleModule:
def __init__(self, params=None, check_mode=False):
self.params = params
self.check_mode = check_mode
def exit_json(self, *args, **kwargs):
raise ExitJsonException(*args, **kwargs)
def fail_json(self, *args, **kwargs):
raise FailJsonException(*args, **kwargs)

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, Bojan Vitnik <bvitnik@mainstream.rs>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
FAKE_API_VERSION = "1.1"
class Failure(Exception):
def __init__(self, details):
self.details = details
def __str__(self):
return str(self.details)
class Session(object):
def __init__(self, uri, transport=None, encoding=None, verbose=0,
allow_none=1, ignore_ssl=False):
self.transport = transport
self._session = None
self.last_login_method = None
self.last_login_params = None
self.API_version = FAKE_API_VERSION
def _get_api_version(self):
return FAKE_API_VERSION
def _login(self, method, params):
self._session = "OpaqueRef:fake-xenapi-session-ref"
self.last_login_method = method
self.last_login_params = params
self.API_version = self._get_api_version()
def _logout(self):
self._session = None
self.last_login_method = None
self.last_login_params = None
self.API_version = FAKE_API_VERSION
def xenapi_request(self, methodname, params):
if methodname.startswith('login'):
self._login(methodname, params)
return None
elif methodname == 'logout' or methodname == 'session.logout':
self._logout()
return None
else:
# Should be patched with mocker.patch().
return None
def __getattr__(self, name):
if name == 'handle':
return self._session
elif name == 'xenapi':
# Should be patched with mocker.patch().
return None
elif name.startswith('login') or name.startswith('slave_local'):
return lambda *params: self._login(name, params)
elif name == 'logout':
return self._logout
def xapi_local():
return Session("http://_var_lib_xcp_xapi/")

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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
def fake_xenapi_ref(xenapi_class):
return "OpaqueRef:fake-xenapi-%s-ref" % xenapi_class
testcase_bad_xenapi_refs = {
"params": [
None,
'',
'OpaqueRef:NULL',
],
"ids": [
'none',
'empty',
'ref-null',
],
}

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 sys
import importlib
import os
import json
import pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from ansible.module_utils import six
from mock import MagicMock
@pytest.fixture
def fake_ansible_module(request):
"""Returns fake AnsibleModule with fake module params."""
if hasattr(request, 'param'):
return FakeAnsibleModule(request.param)
else:
params = {
"hostname": "somehost",
"username": "someuser",
"password": "somepwd",
"validate_certs": True,
}
return FakeAnsibleModule(params)
@pytest.fixture(autouse=True)
def XenAPI():
"""Imports and returns fake XenAPI module."""
# Import of fake XenAPI module is wrapped by fixture so that it does not
# affect other unit tests which could potentialy also use XenAPI module.
# First we use importlib.import_module() to import the module and assign
# it to a local symbol.
fake_xenapi = importlib.import_module('units.module_utils.xenserver.FakeXenAPI')
# Now we populate Python module cache with imported fake module using the
# original module name (XenAPI). That way, any 'import XenAPI' statement
# will just load already imported fake module from the cache.
sys.modules['XenAPI'] = fake_xenapi
return fake_xenapi
@pytest.fixture(autouse=True)
def xenserver(XenAPI):
"""Imports and returns xenserver module util."""
# Since we are wrapping fake XenAPI module inside a fixture, all modules
# that depend on it have to be imported inside a test function. To make
# this easier to handle and remove some code repetition, we wrap the import
# of xenserver module util with a fixture.
from ansible.module_utils import xenserver
return xenserver
@pytest.fixture
def mock_xenapi_failure(XenAPI, mocker):
"""
Returns mock object that raises XenAPI.Failure on any XenAPI
method call.
"""
fake_error_msg = "Fake XAPI method call error!"
# We need to use our MagicMock based class that passes side_effect to its
# children because calls to xenapi methods can generate an arbitrary
# hierarchy of mock objects. Any such object when called should use the
# same side_effect as its parent mock object.
class MagicMockSideEffect(MagicMock):
def _get_child_mock(self, **kw):
child_mock = super(MagicMockSideEffect, self)._get_child_mock(**kw)
child_mock.side_effect = self.side_effect
return child_mock
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', new=MagicMockSideEffect(), create=True)
mocked_xenapi.side_effect = XenAPI.Failure(fake_error_msg)
return mocked_xenapi, fake_error_msg
@pytest.fixture
def fixture_data_from_file(request):
"""Loads fixture data from files."""
if not hasattr(request, 'param'):
return {}
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
fixture_data = {}
if isinstance(request.param, six.string_types):
request.param = [request.param]
for fixture_name in request.param:
path = os.path.join(fixture_path, fixture_name)
with open(path) as f:
data = f.read()
try:
data = json.loads(data)
except Exception:
pass
fixture_data[fixture_name] = data
return fixture_data

@ -0,0 +1,73 @@
{
"cdrom": {
"type": "none"
},
"customization_agent": "native",
"disks": [
{
"name": "ansible-test-vm-1-C",
"name_desc": "C:\\",
"os_device": "xvda",
"size": 42949672960,
"sr": "Ansible Test Storage 1",
"sr_uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"vbd_userdevice": "0"
}
],
"domid": "143",
"folder": "/Ansible/Test",
"hardware": {
"memory_mb": 2048,
"num_cpu_cores_per_socket": 2,
"num_cpus": 2
},
"home_server": "",
"is_template": false,
"name": "ansible-test-vm-1",
"name_desc": "Created by Ansible",
"networks": [
{
"gateway": "10.0.0.1",
"gateway6": "",
"ip": "10.0.0.2",
"ip6": [
"fe80:0000:0000:0000:11e1:12c9:ef3b:75a0"
],
"mac": "7a:a6:48:1e:31:46",
"mtu": "1500",
"name": "Host internal management network",
"netmask": "255.255.255.0",
"prefix": "24",
"prefix6": "",
"vif_device": "0"
}
],
"other_config": {
"base_template_name": "Windows Server 2016 (64-bit)",
"folder": "/Ansible/Test",
"import_task": "OpaqueRef:e43eb71c-45d6-5351-09ff-96e4fb7d0fa5",
"install-methods": "cdrom",
"instant": "true",
"mac_seed": "366fe8e0-878b-4320-8731-90d1ed3c0b93"
},
"platform": {
"acpi": "1",
"apic": "true",
"cores-per-socket": "2",
"device_id": "0002",
"hpet": "true",
"nx": "true",
"pae": "true",
"timeoffset": "-28800",
"vga": "std",
"videoram": "8",
"viridian": "true",
"viridian_reference_tsc": "true",
"viridian_time_ref_count": "true"
},
"state": "poweredon",
"uuid": "81c373d7-a407-322f-911b-31386eb5215d",
"xenstore_data": {
"vm-data": ""
}
}

@ -0,0 +1,707 @@
{
"SR": {
"OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f": {
"PBDs": [],
"VDIs": [],
"allowed_operations": [
"unplug",
"plug",
"pbd_create",
"update",
"pbd_destroy",
"vdi_resize",
"vdi_clone",
"scan",
"vdi_snapshot",
"vdi_mirror",
"vdi_create",
"vdi_destroy"
],
"blobs": {},
"clustered": false,
"content_type": "",
"current_operations": {},
"introduced_by": "OpaqueRef:NULL",
"is_tools_sr": false,
"local_cache_enabled": false,
"name_description": "",
"name_label": "Ansible Test Storage 1",
"other_config": {
"auto-scan": "false"
},
"physical_size": "2521133219840",
"physical_utilisation": "1551485632512",
"shared": true,
"sm_config": {
"allocation": "thick",
"devserial": "scsi-3600a098038302d353624495242443848",
"multipathable": "true",
"use_vhd": "true"
},
"tags": [],
"type": "lvmohba",
"uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"virtual_allocation": "1556925644800"
}
},
"VBD": {
"OpaqueRef:1c0a7c6d-09e5-9b2c-bbe3-9a73aadcff9f": {
"VDI": "OpaqueRef:NULL",
"VM": "OpaqueRef:43a1b8d4-da96-cb08-10f5-fb368abed19c",
"allowed_operations": [
"attach",
"unpause",
"insert",
"pause"
],
"bootable": false,
"current_operations": {},
"currently_attached": true,
"device": "xvdd",
"empty": true,
"metrics": "OpaqueRef:1a36eae4-87c8-0945-cee9-c85a71fd843f",
"mode": "RO",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "CD",
"unpluggable": true,
"userdevice": "3",
"uuid": "e6aacd53-a2c8-649f-b405-93fcb811411a"
},
"OpaqueRef:ea4a4088-19c3-6db6-ebdf-c3c0ee4405a3": {
"VDI": "OpaqueRef:fd20510d-e9ca-b966-3b98-4ae547dacf9a",
"VM": "OpaqueRef:43a1b8d4-da96-cb08-10f5-fb368abed19c",
"allowed_operations": [
"attach",
"unpause",
"unplug",
"unplug_force",
"pause"
],
"bootable": true,
"current_operations": {},
"currently_attached": true,
"device": "xvda",
"empty": false,
"metrics": "OpaqueRef:ddbd70d4-7dde-b51e-6208-eb434b300009",
"mode": "RW",
"other_config": {
"owner": "true"
},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "Disk",
"unpluggable": true,
"userdevice": "0",
"uuid": "ffd6de9c-c416-1d52-3e9d-3bcbf567245e"
}
},
"VDI": {
"OpaqueRef:fd20510d-e9ca-b966-3b98-4ae547dacf9a": {
"SR": "OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f",
"VBDs": [
"OpaqueRef:ea4a4088-19c3-6db6-ebdf-c3c0ee4405a3"
],
"allow_caching": false,
"allowed_operations": [
"clone",
"snapshot"
],
"crash_dumps": [],
"current_operations": {},
"is_a_snapshot": false,
"is_tools_iso": false,
"location": "b807f67b-3f37-4a6e-ad6c-033f812ab093",
"managed": true,
"metadata_latest": false,
"metadata_of_pool": "",
"missing": false,
"name_description": "C:\\",
"name_label": "ansible-test-vm-1-C",
"on_boot": "persist",
"other_config": {},
"parent": "OpaqueRef:NULL",
"physical_utilisation": "43041947648",
"read_only": false,
"sharable": false,
"sm_config": {
"host_OpaqueRef:07a8da76-f1cf-f3b5-a531-6b751384f770": "RW",
"read-caching-enabled-on-92ac8132-276b-4d0f-9d3a-54db51e4a438": "false",
"read-caching-reason-92ac8132-276b-4d0f-9d3a-54db51e4a438": "LICENSE_RESTRICTION",
"vdi_type": "vhd"
},
"snapshot_of": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"storage_lock": false,
"tags": [],
"type": "system",
"uuid": "b807f67b-3f37-4a6e-ad6c-033f812ab093",
"virtual_size": "42949672960",
"xenstore_data": {}
}
},
"VIF": {
"OpaqueRef:38da2120-6086-5043-8383-ab0a53ede42a": {
"MAC": "7a:a6:48:1e:31:46",
"MAC_autogenerated": false,
"MTU": "1500",
"VM": "OpaqueRef:43a1b8d4-da96-cb08-10f5-fb368abed19c",
"allowed_operations": [
"attach",
"unplug"
],
"current_operations": {},
"currently_attached": true,
"device": "0",
"ipv4_addresses": [
"10.0.0.2/24"
],
"ipv4_allowed": [],
"ipv4_configuration_mode": "Static",
"ipv4_gateway": "10.0.0.1",
"ipv6_addresses": [
""
],
"ipv6_allowed": [],
"ipv6_configuration_mode": "None",
"ipv6_gateway": "",
"locking_mode": "network_default",
"metrics": "OpaqueRef:15502939-df0f-0095-1ce3-e51367199d27",
"network": "OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"uuid": "bd108d25-488a-f9b5-4c7b-02d40f1e38a8"
}
},
"VM": {
"OpaqueRef:43a1b8d4-da96-cb08-10f5-fb368abed19c": {
"HVM_boot_params": {
"order": "dc"
},
"HVM_boot_policy": "BIOS order",
"HVM_shadow_multiplier": 1.0,
"PCI_bus": "",
"PV_args": "",
"PV_bootloader": "",
"PV_bootloader_args": "",
"PV_kernel": "",
"PV_legacy_args": "",
"PV_ramdisk": "",
"VBDs": [
"OpaqueRef:1c0a7c6d-09e5-9b2c-bbe3-9a73aadcff9f",
"OpaqueRef:ea4a4088-19c3-6db6-ebdf-c3c0ee4405a3"
],
"VCPUs_at_startup": "2",
"VCPUs_max": "2",
"VCPUs_params": {},
"VGPUs": [],
"VIFs": [
"OpaqueRef:38da2120-6086-5043-8383-ab0a53ede42a"
],
"VTPMs": [],
"actions_after_crash": "restart",
"actions_after_reboot": "restart",
"actions_after_shutdown": "destroy",
"affinity": "OpaqueRef:NULL",
"allowed_operations": [
"changing_dynamic_range",
"migrate_send",
"pool_migrate",
"changing_VCPUs_live",
"suspend",
"hard_reboot",
"hard_shutdown",
"clean_reboot",
"clean_shutdown",
"pause",
"checkpoint",
"snapshot"
],
"appliance": "OpaqueRef:NULL",
"attached_PCIs": [],
"bios_strings": {
"bios-vendor": "Xen",
"bios-version": "",
"hp-rombios": "",
"oem-1": "Xen",
"oem-2": "MS_VM_CERT/SHA1/bdbeb6e0a816d43fa6d3fe8aaef04c2bad9d3e3d",
"system-manufacturer": "Xen",
"system-product-name": "HVM domU",
"system-serial-number": "",
"system-version": ""
},
"blobs": {},
"blocked_operations": {},
"children": [],
"consoles": [
"OpaqueRef:4fa7d34e-1fb6-9e88-1b21-41a3c6550d8b"
],
"crash_dumps": [],
"current_operations": {},
"domarch": "",
"domid": "143",
"generation_id": "3274224479562869847:6952848762503845513",
"guest_metrics": "OpaqueRef:453f21be-954d-2ca8-e38e-09741e91350c",
"ha_always_run": false,
"ha_restart_priority": "",
"hardware_platform_version": "0",
"has_vendor_device": false,
"is_a_snapshot": false,
"is_a_template": false,
"is_control_domain": false,
"is_default_template": false,
"is_snapshot_from_vmpp": false,
"is_vmss_snapshot": false,
"last_boot_CPU_flags": {
"features": "17cbfbff-f7fa3223-2d93fbff-00000023-00000001-000007ab-00000000-00000000-00001000-0c000000",
"vendor": "GenuineIntel"
},
"last_booted_record": "",
"memory_dynamic_max": "2147483648",
"memory_dynamic_min": "2147483648",
"memory_overhead": "20971520",
"memory_static_max": "2147483648",
"memory_static_min": "1073741824",
"memory_target": "2147483648",
"metrics": "OpaqueRef:6eede779-4e55-7cfb-8b8a-e4b9becf770b",
"name_description": "Created by Ansible",
"name_label": "ansible-test-vm-1",
"order": "0",
"other_config": {
"base_template_name": "Windows Server 2016 (64-bit)",
"folder": "/Ansible/Test",
"import_task": "OpaqueRef:e43eb71c-45d6-5351-09ff-96e4fb7d0fa5",
"install-methods": "cdrom",
"instant": "true",
"mac_seed": "366fe8e0-878b-4320-8731-90d1ed3c0b93"
},
"parent": "OpaqueRef:NULL",
"platform": {
"acpi": "1",
"apic": "true",
"cores-per-socket": "2",
"device_id": "0002",
"hpet": "true",
"nx": "true",
"pae": "true",
"timeoffset": "-28800",
"vga": "std",
"videoram": "8",
"viridian": "true",
"viridian_reference_tsc": "true",
"viridian_time_ref_count": "true"
},
"power_state": "Running",
"protection_policy": "OpaqueRef:NULL",
"recommendations": "<restrictions><restriction field=\"memory-static-max\" max=\"1649267441664\"/><restriction field=\"vcpus-max\" max=\"32\"/><restriction field=\"has-vendor-device\" value=\"true\"/><restriction max=\"255\" property=\"number-of-vbds\"/><restriction max=\"7\" property=\"number-of-vifs\"/></restrictions>",
"reference_label": "windows-server-2016-64bit",
"requires_reboot": false,
"resident_on": "OpaqueRef:07a8da76-f1cf-f3b5-a531-6b751384f770",
"shutdown_delay": "0",
"snapshot_info": {},
"snapshot_metadata": "",
"snapshot_of": "OpaqueRef:NULL",
"snapshot_schedule": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"start_delay": "0",
"suspend_SR": "OpaqueRef:NULL",
"suspend_VDI": "OpaqueRef:NULL",
"tags": [],
"transportable_snapshot_id": "",
"user_version": "1",
"uuid": "81c373d7-a407-322f-911b-31386eb5215d",
"version": "0",
"xenstore_data": {
"vm-data": ""
}
}
},
"VM_guest_metrics": {
"OpaqueRef:453f21be-954d-2ca8-e38e-09741e91350c": {
"PV_drivers_detected": true,
"PV_drivers_up_to_date": true,
"PV_drivers_version": {
"build": "1020",
"major": "7",
"micro": "0",
"minor": "1"
},
"can_use_hotplug_vbd": "yes",
"can_use_hotplug_vif": "yes",
"disks": {},
"last_updated": "20190113T19:40:34Z",
"live": true,
"memory": {},
"networks": {
"0/ip": "10.0.0.2",
"0/ipv6/0": "fe80:0000:0000:0000:11e1:12c9:ef3b:75a0"
},
"os_version": {
"distro": "windows",
"major": "6",
"minor": "2",
"name": "Microsoft Windows Server 2016 Standard|C:\\Windows|\\Device\\Harddisk0\\Partition2",
"spmajor": "0",
"spminor": "0"
},
"other": {
"data-ts": "1",
"error": "WTSQueryUserToken : 1008 failed.",
"feature-balloon": "1",
"feature-poweroff": "1",
"feature-reboot": "1",
"feature-s3": "1",
"feature-s4": "1",
"feature-setcomputername": "1",
"feature-static-ip-setting": "1",
"feature-suspend": "1",
"feature-ts": "1",
"feature-ts2": "1",
"feature-xs-batcmd": "1",
"has-vendor-device": "0",
"platform-feature-multiprocessor-suspend": "1"
},
"other_config": {},
"uuid": "9ea6803f-12ca-3d6a-47b7-c90a33b67b98"
}
},
"VM_metrics": {
"OpaqueRef:6eede779-4e55-7cfb-8b8a-e4b9becf770b": {
"VCPUs_CPU": {},
"VCPUs_flags": {},
"VCPUs_number": "2",
"VCPUs_params": {},
"VCPUs_utilisation": {},
"hvm": true,
"install_time": "20190113T19:31:47Z",
"last_updated": "19700101T00:00:00Z",
"memory_actual": "2147475456",
"nested_virt": false,
"nomigrate": false,
"other_config": {},
"start_time": "20190113T19:38:59Z",
"state": [],
"uuid": "c67fadf7-8143-0c92-c772-cd3901c18e70"
}
},
"host": {
"OpaqueRef:07a8da76-f1cf-f3b5-a531-6b751384f770": {
"API_version_major": "2",
"API_version_minor": "7",
"API_version_vendor": "XenSource",
"API_version_vendor_implementation": {},
"PBDs": [],
"PCIs": [],
"PGPUs": [],
"PIFs": [],
"address": "10.0.0.1",
"allowed_operations": [
"vm_migrate",
"provision",
"vm_resume",
"evacuate",
"vm_start"
],
"bios_strings": {},
"blobs": {},
"capabilities": [
"xen-3.0-x86_64",
"xen-3.0-x86_32p",
"hvm-3.0-x86_32",
"hvm-3.0-x86_32p",
"hvm-3.0-x86_64",
""
],
"chipset_info": {
"iommu": "true"
},
"control_domain": "OpaqueRef:a2a31555-f232-822b-8f36-10d75d44b79c",
"cpu_configuration": {},
"cpu_info": {
"cpu_count": "40",
"family": "6",
"features": "7ffefbff-bfebfbff-00000021-2c100800",
"features_hvm": "17cbfbff-f7fa3223-2d93fbff-00000023-00000001-000007ab-00000000-00000000-00001000-0c000000",
"features_pv": "17c9cbf5-f6f83203-2191cbf5-00000023-00000001-00000329-00000000-00000000-00001000-0c000000",
"flags": "fpu de tsc msr pae mce cx8 apic sep mca cmov pat clflush acpi mmx fxsr sse sse2 ht syscall nx lm constant_tsc arch_perfmon rep_good nopl nonstop_tsc eagerfpu pni pclmulqdq monitor est ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm ida arat epb pln pts dtherm fsgsbase bmi1 avx2 bmi2 erms xsaveopt cqm_llc cqm_occup_llc",
"model": "63",
"modelname": "Intel(R) Xeon(R) CPU E5-2660 v3 @ 2.60GHz",
"socket_count": "2",
"speed": "2597.064",
"stepping": "2",
"vendor": "GenuineIntel"
},
"crash_dump_sr": "OpaqueRef:ed72d7bf-4e53-67fc-17f5-e27b203042ba",
"crashdumps": [],
"current_operations": {},
"display": "enabled",
"edition": "free",
"enabled": true,
"external_auth_configuration": {},
"external_auth_service_name": "",
"external_auth_type": "",
"features": [],
"guest_VCPUs_params": {},
"ha_network_peers": [],
"ha_statefiles": [],
"host_CPUs": [
"OpaqueRef:f7e744f6-a6f9-c460-999a-c27e1395e2e0",
"OpaqueRef:f6e5dcf0-0453-8f3f-88c1-7ad6e2ef3dd1",
"OpaqueRef:f27a52fb-5feb-173d-1a07-d1735a83c2cc",
"OpaqueRef:ed65327a-508a-ccfc-dba6-2a0175cb2432",
"OpaqueRef:e41d2f2a-fe9e-72cb-8104-b22d6d314b13",
"OpaqueRef:e1988469-b814-5d10-17a6-bfd7c62d2b5f",
"OpaqueRef:d73967dc-b8d8-b47b-39f4-d599fdcabf55",
"OpaqueRef:cba9ebd9-40dc-0611-d1bb-aa661bd0bf70",
"OpaqueRef:c53d3110-4085-60af-8300-d879818789f7",
"OpaqueRef:bee0cf87-7df6-79a6-94e8-36f98e69ad20",
"OpaqueRef:bde28e83-213f-0e65-b6ad-0ae1ecebb98d",
"OpaqueRef:bbfefe67-f65f-98cb-c3fc-cb8ea0588006",
"OpaqueRef:b38ac595-afea-0ca0-49a0-9f5ef2368e3b",
"OpaqueRef:b14ef333-78b1-193d-02da-dc9bfed36912",
"OpaqueRef:afd478bf-57b9-0c79-f257-50aeb81504f1",
"OpaqueRef:a307cd3a-2132-2e42-4ebc-cc1c7780736d",
"OpaqueRef:a1a9df7d-88ba-64fd-a55c-0f6472e1753f",
"OpaqueRef:a0e39c9c-3e0b-fa03-e5d0-93a09aa77393",
"OpaqueRef:9fd5719b-36ab-8e25-7756-20a496ccb331",
"OpaqueRef:9ac4195d-ac07-cfe2-bc19-27ee54cf91fb",
"OpaqueRef:98c5c00c-1e2d-e22b-842e-79e85ce07873",
"OpaqueRef:961129bf-e695-f206-7297-64f9007a64f3",
"OpaqueRef:64368b4c-3488-2808-f0b3-42f2a656df2b",
"OpaqueRef:620dabc0-d7c5-0dc8-52df-3be25194c2fb",
"OpaqueRef:5cee2759-dd8e-7e1a-0727-21e196584030",
"OpaqueRef:58f70163-863d-5787-ffbb-2416cb16ca1e",
"OpaqueRef:4462f848-f396-653d-67f9-2bed13be2c58",
"OpaqueRef:40e800c2-19db-7cd8-c045-5ae93f908cae",
"OpaqueRef:3f84278b-dec6-ded0-1a33-4daa0ce75a2f",
"OpaqueRef:3ef14992-62f6-e1f0-5715-0ee02a834a9c",
"OpaqueRef:3e274c24-c55b-06f5-2c8f-415421043ab2",
"OpaqueRef:35ff27da-f286-7b70-adc1-a200880bb79f",
"OpaqueRef:2511aa53-8660-e442-3cd2-305982d1f751",
"OpaqueRef:21d234e3-138c-81ca-9ed8-febc81b874e9",
"OpaqueRef:1f9b4ee3-dcc7-114e-b401-dc3e94c07efa",
"OpaqueRef:1b94a981-d340-dd07-41c2-b3ff3c545fed",
"OpaqueRef:197ad104-64a8-5af3-8c7a-95f3d301aadd",
"OpaqueRef:1672e747-dc4b-737b-ddcf-0a373f966012",
"OpaqueRef:12ced494-a225-7584-456b-739331bb5114",
"OpaqueRef:0139ff72-62ac-1a6a-8f6f-cb01d8a4ee92"
],
"hostname": "ansible-test-host-1",
"license_params": {
"address1": "",
"address2": "",
"city": "",
"company": "",
"country": "",
"enable_xha": "true",
"expiry": "20291231T23:00:00Z",
"grace": "no",
"license_type": "",
"name": "",
"platform_filter": "false",
"postalcode": "",
"productcode": "",
"regular_nag_dialog": "false",
"restrict_ad": "false",
"restrict_batch_hotfix_apply": "true",
"restrict_checkpoint": "false",
"restrict_cifs": "true",
"restrict_connection": "false",
"restrict_cpu_masking": "false",
"restrict_dmc": "false",
"restrict_dr": "false",
"restrict_email_alerting": "false",
"restrict_equalogic": "false",
"restrict_export_resource_data": "true",
"restrict_gpu": "false",
"restrict_guest_agent_auto_update": "true",
"restrict_guest_ip_setting": "false",
"restrict_health_check": "false",
"restrict_historical_performance": "false",
"restrict_hotfix_apply": "false",
"restrict_integrated_gpu_passthrough": "false",
"restrict_intellicache": "false",
"restrict_lab": "false",
"restrict_live_patching": "true",
"restrict_marathon": "false",
"restrict_nested_virt": "true",
"restrict_netapp": "false",
"restrict_pci_device_for_auto_update": "true",
"restrict_pool_attached_storage": "false",
"restrict_pooling": "false",
"restrict_pvs_proxy": "true",
"restrict_qos": "false",
"restrict_rbac": "false",
"restrict_read_caching": "true",
"restrict_set_vcpus_number_live": "true",
"restrict_ssl_legacy_switch": "false",
"restrict_stage": "false",
"restrict_storage_xen_motion": "false",
"restrict_storagelink": "false",
"restrict_storagelink_site_recovery": "false",
"restrict_vgpu": "true",
"restrict_vif_locking": "false",
"restrict_vlan": "false",
"restrict_vm_memory_introspection": "true",
"restrict_vmpr": "false",
"restrict_vmss": "false",
"restrict_vss": "false",
"restrict_vswitch_controller": "false",
"restrict_web_selfservice": "true",
"restrict_web_selfservice_manager": "true",
"restrict_wlb": "true",
"restrict_xcm": "true",
"restrict_xen_motion": "false",
"serialnumber": "",
"sku_marketing_name": "Citrix XenServer",
"sku_type": "free",
"sockets": "2",
"state": "",
"version": ""
},
"license_server": {
"address": "localhost",
"port": "27000"
},
"local_cache_sr": "OpaqueRef:ed72d7bf-4e53-67fc-17f5-e27b203042ba",
"logging": {},
"memory_overhead": "4606619648",
"metrics": "OpaqueRef:82b6937a-60c2-96d8-4e78-9f9a1143033f",
"name_description": "",
"name_label": "ansible-test-host-1",
"other_config": {
"agent_start_time": "1532019557.",
"boot_time": "1530023264.",
"iscsi_iqn": "iqn.2018-06.com.example:c8bac750",
"last_blob_sync_time": "1547394076.36",
"multipathhandle": "dmp",
"multipathing": "true"
},
"patches": [
"OpaqueRef:f74ca18d-cfb7-e4fe-e5c4-819843de11e2",
"OpaqueRef:f53ff05e-8dd8-3a15-d3b0-8dcf6004fbe2",
"OpaqueRef:ed7f38da-1a50-a48b-60bf-933cabe8d7bc",
"OpaqueRef:e7bb1462-51a5-1aaf-3b56-11b8ebd83a94",
"OpaqueRef:d87b343b-6ba3-db8b-b80e-e02319ba5924",
"OpaqueRef:ccb00450-ed04-4eaa-e6d7-130ef3722374",
"OpaqueRef:b79b8864-11d9-1d5f-09e5-a66d7b64b9e2",
"OpaqueRef:9bebcc7d-61ae-126b-3be0-9156026e586f",
"OpaqueRef:740a1156-b991-00b8-ef50-fdbb22a4d911",
"OpaqueRef:71def430-754b-2bfb-6c93-ec3b67b754e4",
"OpaqueRef:6c73b00d-df66-1740-9578-2b14e46297ba",
"OpaqueRef:6a53d2ae-3d6b-32ed-705f-fd53f1304470",
"OpaqueRef:35a67684-b094-1c77-beff-8237d87c7a27",
"OpaqueRef:33da42c2-c421-9859-79b7-ce9b6c394a1b",
"OpaqueRef:2baa6b4b-9bbe-c1b2-23ce-c8c831ac581d",
"OpaqueRef:2ac3beea-dee2-44e7-9f67-5fd216e593a0",
"OpaqueRef:1bd8f24b-3190-6e7a-b36e-e2998197d062",
"OpaqueRef:1694ea26-4930-6ca1-036e-273438375de9",
"OpaqueRef:09813f03-0c6f-a6af-768f-ef4cdde2c641"
],
"power_on_config": {},
"power_on_mode": "",
"resident_VMs": [],
"sched_policy": "credit",
"software_version": {
"build_number": "release/falcon/master/8",
"date": "2017-05-11",
"db_schema": "5.120",
"dbv": "2017.0517",
"hostname": "f7d02093adae",
"linux": "4.4.0+10",
"network_backend": "openvswitch",
"platform_name": "XCP",
"platform_version": "2.3.0",
"product_brand": "XenServer",
"product_version": "7.2.0",
"product_version_text": "7.2",
"product_version_text_short": "7.2",
"xapi": "1.9",
"xen": "4.7.5-2.12",
"xencenter_max": "2.7",
"xencenter_min": "2.7"
},
"ssl_legacy": true,
"supported_bootloaders": [
"pygrub",
"eliloader"
],
"suspend_image_sr": "OpaqueRef:ed72d7bf-4e53-67fc-17f5-e27b203042ba",
"tags": [],
"updates": [
"OpaqueRef:b71938bf-4c4f-eb17-7e78-588e71297a74",
"OpaqueRef:91cfa47b-52f9-a4e3-4e78-52e3eb3e5141",
"OpaqueRef:e2209ae9-5362-3a20-f691-9294144e49f2",
"OpaqueRef:6ac77a0f-f079-8067-85cc-c9ae2f8dcca9",
"OpaqueRef:a17e721d-faf4-6ad1-c617-dd4899279534",
"OpaqueRef:6c9b814c-e1c2-b8be-198f-de358686b10a",
"OpaqueRef:fbaabbfe-88d5-d89b-5b3f-d6374601ca71",
"OpaqueRef:9eccc765-9726-d220-96b1-2e85adf77ecc",
"OpaqueRef:204558d7-dce0-2304-bdc5-80ec5fd7e3c3",
"OpaqueRef:65b14ae7-f440-0c4d-4af9-c7946b90fd2f",
"OpaqueRef:0760c608-b02e-743a-18a1-fa8f205374d6",
"OpaqueRef:1ced32ca-fec4-8b44-0e8f-753c97f2d93f",
"OpaqueRef:3fffd7c7-f4d1-6b03-a5b8-d75211bb7b8f",
"OpaqueRef:01befb95-412e-e9dd-5b5d-edd50df61cb1",
"OpaqueRef:a3f9481e-fe3d-1f00-235f-44d404f51128",
"OpaqueRef:507ee5fc-59d3-e635-21d5-98a5cace4bf2",
"OpaqueRef:7b4b5da1-54af-d0c4-3fea-394b4257bffe",
"OpaqueRef:f61edc83-91d9-a161-113f-00c110196238",
"OpaqueRef:7efce157-9b93-d116-f3f8-7eb0c6fb1a79"
],
"updates_requiring_reboot": [],
"uuid": "92ac8132-276b-4d0f-9d3a-54db51e4a438",
"virtual_hardware_platform_versions": [
"0",
"1",
"2"
]
}
},
"network": {
"OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724": {
"MTU": "1500",
"PIFs": [],
"VIFs": [],
"allowed_operations": [],
"assigned_ips": {
"OpaqueRef:8171dad1-f902-ec00-7ba2-9f92d8aa75ab": "169.254.0.3",
"OpaqueRef:9754a0ed-e100-d224-6a70-a55a9c2cedf9": "169.254.0.2"
},
"blobs": {},
"bridge": "xenapi",
"current_operations": {},
"default_locking_mode": "unlocked",
"managed": true,
"name_description": "Network on which guests will be assigned a private link-local IP address which can be used to talk XenAPI",
"name_label": "Host internal management network",
"other_config": {
"ip_begin": "169.254.0.1",
"ip_end": "169.254.255.254",
"is_guest_installer_network": "true",
"is_host_internal_management_network": "true",
"netmask": "255.255.0.0"
},
"tags": [],
"uuid": "dbb96525-944f-0d1a-54ed-e65cb6d07450"
}
}
}

@ -0,0 +1,87 @@
{
"cdrom": {
"type": "none"
},
"customization_agent": "custom",
"disks": [
{
"name": "ansible-test-vm-2-root",
"name_desc": "/",
"os_device": "xvda",
"size": 10737418240,
"sr": "Ansible Test Storage 1",
"sr_uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"vbd_userdevice": "0"
},
{
"name": "ansible-test-vm-2-mysql",
"name_desc": "/var/lib/mysql",
"os_device": "xvdb",
"size": 1073741824,
"sr": "Ansible Test Storage 1",
"sr_uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"vbd_userdevice": "1"
}
],
"domid": "140",
"folder": "/Ansible/Test",
"hardware": {
"memory_mb": 1024,
"num_cpu_cores_per_socket": 1,
"num_cpus": 1
},
"home_server": "ansible-test-host-2",
"is_template": false,
"name": "ansible-test-vm-2",
"name_desc": "Created by Ansible",
"networks": [
{
"gateway": "10.0.0.1",
"gateway6": "",
"ip": "169.254.0.2",
"ip6": [],
"mac": "16:87:31:70:d6:31",
"mtu": "1500",
"name": "Host internal management network",
"netmask": "255.255.255.0",
"prefix": "24",
"prefix6": "",
"vif_device": "0"
}
],
"other_config": {
"base_template_name": "CentOS 7",
"folder": "/Ansible/Test",
"import_task": "OpaqueRef:cf1402d3-b6c1-d908-fe62-06502e3b311a",
"install-methods": "cdrom,nfs,http,ftp",
"instant": "true",
"linux_template": "true",
"mac_seed": "0ab46664-f519-5383-166e-e4ea485ede7d"
},
"platform": {
"acpi": "1",
"apic": "true",
"cores-per-socket": "1",
"device_id": "0001",
"nx": "true",
"pae": "true",
"timeoffset": "0",
"vga": "std",
"videoram": "8",
"viridian": "false"
},
"state": "poweredon",
"uuid": "0a05d5ad-3e4b-f0dc-6101-8c56623958bc",
"xenstore_data": {
"vm-data": "",
"vm-data/networks": "",
"vm-data/networks/0": "",
"vm-data/networks/0/gateway": "10.0.0.1",
"vm-data/networks/0/ip": "10.0.0.3",
"vm-data/networks/0/mac": "16:87:31:70:d6:31",
"vm-data/networks/0/name": "Host internal management network",
"vm-data/networks/0/netmask": "255.255.255.0",
"vm-data/networks/0/prefix": "24",
"vm-data/networks/0/type": "static"
}
}

@ -0,0 +1,771 @@
{
"SR": {
"OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f": {
"PBDs": [],
"VDIs": [],
"allowed_operations": [
"unplug",
"plug",
"pbd_create",
"update",
"pbd_destroy",
"vdi_resize",
"vdi_clone",
"scan",
"vdi_snapshot",
"vdi_mirror",
"vdi_create",
"vdi_destroy"
],
"blobs": {},
"clustered": false,
"content_type": "",
"current_operations": {},
"introduced_by": "OpaqueRef:NULL",
"is_tools_sr": false,
"local_cache_enabled": false,
"name_description": "",
"name_label": "Ansible Test Storage 1",
"other_config": {
"auto-scan": "false"
},
"physical_size": "2521133219840",
"physical_utilisation": "1551485632512",
"shared": true,
"sm_config": {
"allocation": "thick",
"devserial": "scsi-3600a098038302d353624495242443848",
"multipathable": "true",
"use_vhd": "true"
},
"tags": [],
"type": "lvmohba",
"uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"virtual_allocation": "1556925644800"
}
},
"VBD": {
"OpaqueRef:510e214e-f0ba-3bc9-7834-a4f4d3fa33ef": {
"VDI": "OpaqueRef:NULL",
"VM": "OpaqueRef:08632af0-473e-5106-f400-7910229e49be",
"allowed_operations": [
"attach",
"unpause",
"insert",
"pause"
],
"bootable": false,
"current_operations": {},
"currently_attached": true,
"device": "xvdd",
"empty": true,
"metrics": "OpaqueRef:1075bebe-ba71-66ef-ba30-8afbc83bc6b5",
"mode": "RO",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "CD",
"unpluggable": true,
"userdevice": "3",
"uuid": "79ee1d8e-944b-3bfd-ba4c-a0c165d84f3d"
},
"OpaqueRef:6bc2c353-f132-926d-6e9b-e4d1d55a3760": {
"VDI": "OpaqueRef:102bef39-b134-d23a-9a50-490e1dbca8f7",
"VM": "OpaqueRef:08632af0-473e-5106-f400-7910229e49be",
"allowed_operations": [
"attach",
"unpause",
"pause"
],
"bootable": true,
"current_operations": {},
"currently_attached": true,
"device": "xvda",
"empty": false,
"metrics": "OpaqueRef:1c71ccde-d7e9-10fb-569c-993b880fa790",
"mode": "RW",
"other_config": {
"owner": ""
},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "Disk",
"unpluggable": false,
"userdevice": "0",
"uuid": "932fdf6d-7ac5-45e8-a48e-694af75726f1"
},
"OpaqueRef:9bd6decd-2e55-b55e-387d-c40aa67ff151": {
"VDI": "OpaqueRef:87b45ac6-af36-f4fd-6ebd-a08bed9001e4",
"VM": "OpaqueRef:08632af0-473e-5106-f400-7910229e49be",
"allowed_operations": [
"attach",
"unpause",
"unplug",
"unplug_force",
"pause"
],
"bootable": false,
"current_operations": {},
"currently_attached": true,
"device": "xvdb",
"empty": false,
"metrics": "OpaqueRef:b8424146-d3ea-4850-db9a-47f0059c10ac",
"mode": "RW",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "Disk",
"unpluggable": true,
"userdevice": "1",
"uuid": "c0c1e648-3690-e1fb-9f47-24b4df0cb458"
}
},
"VDI": {
"OpaqueRef:102bef39-b134-d23a-9a50-490e1dbca8f7": {
"SR": "OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f",
"VBDs": [
"OpaqueRef:6bc2c353-f132-926d-6e9b-e4d1d55a3760"
],
"allow_caching": false,
"allowed_operations": [
"clone",
"snapshot"
],
"crash_dumps": [],
"current_operations": {},
"is_a_snapshot": false,
"is_tools_iso": false,
"location": "fa1202b8-326f-4235-802e-fafbed66b26b",
"managed": true,
"metadata_latest": false,
"metadata_of_pool": "",
"missing": false,
"name_description": "/",
"name_label": "ansible-test-vm-2-root",
"on_boot": "persist",
"other_config": {},
"parent": "OpaqueRef:NULL",
"physical_utilisation": "10766778368",
"read_only": false,
"sharable": false,
"sm_config": {
"host_OpaqueRef:e87be804-57a1-532e-56ac-6c4910957be0": "RW",
"read-caching-enabled-on-dff6702e-bcb6-4704-8dd4-952e8c883365": "false",
"read-caching-reason-dff6702e-bcb6-4704-8dd4-952e8c883365": "LICENSE_RESTRICTION",
"vdi_type": "vhd"
},
"snapshot_of": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"storage_lock": false,
"tags": [],
"type": "system",
"uuid": "fa1202b8-326f-4235-802e-fafbed66b26b",
"virtual_size": "10737418240",
"xenstore_data": {}
},
"OpaqueRef:87b45ac6-af36-f4fd-6ebd-a08bed9001e4": {
"SR": "OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f",
"VBDs": [
"OpaqueRef:9bd6decd-2e55-b55e-387d-c40aa67ff151"
],
"allow_caching": false,
"allowed_operations": [
"clone",
"snapshot"
],
"crash_dumps": [],
"current_operations": {},
"is_a_snapshot": false,
"is_tools_iso": false,
"location": "ab3a4d72-f498-4687-86ce-ca937046db76",
"managed": true,
"metadata_latest": false,
"metadata_of_pool": "",
"missing": false,
"name_description": "/var/lib/mysql",
"name_label": "ansible-test-vm-2-mysql",
"on_boot": "persist",
"other_config": {},
"parent": "OpaqueRef:NULL",
"physical_utilisation": "1082130432",
"read_only": false,
"sharable": false,
"sm_config": {
"host_OpaqueRef:e87be804-57a1-532e-56ac-6c4910957be0": "RW",
"read-caching-enabled-on-dff6702e-bcb6-4704-8dd4-952e8c883365": "false",
"read-caching-reason-dff6702e-bcb6-4704-8dd4-952e8c883365": "LICENSE_RESTRICTION",
"vdi_type": "vhd"
},
"snapshot_of": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"storage_lock": false,
"tags": [],
"type": "user",
"uuid": "ab3a4d72-f498-4687-86ce-ca937046db76",
"virtual_size": "1073741824",
"xenstore_data": {}
}
},
"VIF": {
"OpaqueRef:9754a0ed-e100-d224-6a70-a55a9c2cedf9": {
"MAC": "16:87:31:70:d6:31",
"MAC_autogenerated": false,
"MTU": "1500",
"VM": "OpaqueRef:08632af0-473e-5106-f400-7910229e49be",
"allowed_operations": [
"attach",
"unplug"
],
"current_operations": {},
"currently_attached": true,
"device": "0",
"ipv4_addresses": [],
"ipv4_allowed": [],
"ipv4_configuration_mode": "None",
"ipv4_gateway": "",
"ipv6_addresses": [],
"ipv6_allowed": [],
"ipv6_configuration_mode": "None",
"ipv6_gateway": "",
"locking_mode": "network_default",
"metrics": "OpaqueRef:d74d5f20-f0ab-ee36-9a74-496ffb994232",
"network": "OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"uuid": "07b70134-9396-94fc-5105-179b430ce4f8"
}
},
"VM": {
"OpaqueRef:08632af0-473e-5106-f400-7910229e49be": {
"HVM_boot_params": {
"order": "cdn"
},
"HVM_boot_policy": "BIOS order",
"HVM_shadow_multiplier": 1.0,
"PCI_bus": "",
"PV_args": "",
"PV_bootloader": "",
"PV_bootloader_args": "",
"PV_kernel": "",
"PV_legacy_args": "",
"PV_ramdisk": "",
"VBDs": [
"OpaqueRef:510e214e-f0ba-3bc9-7834-a4f4d3fa33ef",
"OpaqueRef:9bd6decd-2e55-b55e-387d-c40aa67ff151",
"OpaqueRef:6bc2c353-f132-926d-6e9b-e4d1d55a3760"
],
"VCPUs_at_startup": "1",
"VCPUs_max": "1",
"VCPUs_params": {},
"VGPUs": [],
"VIFs": [
"OpaqueRef:9754a0ed-e100-d224-6a70-a55a9c2cedf9"
],
"VTPMs": [],
"actions_after_crash": "restart",
"actions_after_reboot": "restart",
"actions_after_shutdown": "destroy",
"affinity": "OpaqueRef:e87be804-57a1-532e-56ac-6c4910957be0",
"allowed_operations": [
"changing_dynamic_range",
"migrate_send",
"pool_migrate",
"changing_VCPUs_live",
"suspend",
"hard_reboot",
"hard_shutdown",
"clean_reboot",
"clean_shutdown",
"pause",
"checkpoint",
"snapshot"
],
"appliance": "OpaqueRef:NULL",
"attached_PCIs": [],
"bios_strings": {
"bios-vendor": "Xen",
"bios-version": "",
"hp-rombios": "",
"oem-1": "Xen",
"oem-2": "MS_VM_CERT/SHA1/bdbeb6e0a816d43fa6d3fe8aaef04c2bad9d3e3d",
"system-manufacturer": "Xen",
"system-product-name": "HVM domU",
"system-serial-number": "",
"system-version": ""
},
"blobs": {},
"blocked_operations": {},
"children": [],
"consoles": [
"OpaqueRef:2a24e023-a856-de30-aea3-2024bacdc71f"
],
"crash_dumps": [],
"current_operations": {},
"domarch": "",
"domid": "140",
"generation_id": "",
"guest_metrics": "OpaqueRef:150d2dfa-b634-7965-92ab-31fc26382683",
"ha_always_run": false,
"ha_restart_priority": "",
"hardware_platform_version": "0",
"has_vendor_device": false,
"is_a_snapshot": false,
"is_a_template": false,
"is_control_domain": false,
"is_default_template": false,
"is_snapshot_from_vmpp": false,
"is_vmss_snapshot": false,
"last_boot_CPU_flags": {
"features": "17cbfbff-f7fa3223-2d93fbff-00000023-00000001-000007ab-00000000-00000000-00001000-0c000000",
"vendor": "GenuineIntel"
},
"last_booted_record": "",
"memory_dynamic_max": "1073741824",
"memory_dynamic_min": "1073741824",
"memory_overhead": "11534336",
"memory_static_max": "1073741824",
"memory_static_min": "1073741824",
"memory_target": "1073741824",
"metrics": "OpaqueRef:b56b460b-6476-304d-b143-ce543ffab828",
"name_description": "Created by Ansible",
"name_label": "ansible-test-vm-2",
"order": "0",
"other_config": {
"base_template_name": "CentOS 7",
"folder": "/Ansible/Test",
"import_task": "OpaqueRef:cf1402d3-b6c1-d908-fe62-06502e3b311a",
"install-methods": "cdrom,nfs,http,ftp",
"instant": "true",
"linux_template": "true",
"mac_seed": "0ab46664-f519-5383-166e-e4ea485ede7d"
},
"parent": "OpaqueRef:NULL",
"platform": {
"acpi": "1",
"apic": "true",
"cores-per-socket": "1",
"device_id": "0001",
"nx": "true",
"pae": "true",
"timeoffset": "0",
"vga": "std",
"videoram": "8",
"viridian": "false"
},
"power_state": "Running",
"protection_policy": "OpaqueRef:NULL",
"recommendations": "<restrictions><restriction field=\"memory-static-max\" max=\"549755813888\" /><restriction field=\"vcpus-max\" max=\"16\" /><restriction property=\"number-of-vbds\" max=\"16\" /><restriction property=\"number-of-vifs\" max=\"7\" /><restriction field=\"allow-gpu-passthrough\" value=\"0\" /></restrictions>",
"reference_label": "",
"requires_reboot": false,
"resident_on": "OpaqueRef:e87be804-57a1-532e-56ac-6c4910957be0",
"shutdown_delay": "0",
"snapshot_info": {},
"snapshot_metadata": "",
"snapshot_of": "OpaqueRef:NULL",
"snapshot_schedule": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"start_delay": "0",
"suspend_SR": "OpaqueRef:NULL",
"suspend_VDI": "OpaqueRef:NULL",
"tags": [],
"transportable_snapshot_id": "",
"user_version": "1",
"uuid": "0a05d5ad-3e4b-f0dc-6101-8c56623958bc",
"version": "0",
"xenstore_data": {
"vm-data": "",
"vm-data/networks": "",
"vm-data/networks/0": "",
"vm-data/networks/0/gateway": "10.0.0.1",
"vm-data/networks/0/ip": "10.0.0.3",
"vm-data/networks/0/mac": "16:87:31:70:d6:31",
"vm-data/networks/0/name": "Host internal management network",
"vm-data/networks/0/netmask": "255.255.255.0",
"vm-data/networks/0/prefix": "24",
"vm-data/networks/0/type": "static"
}
}
},
"VM_guest_metrics": {
"OpaqueRef:150d2dfa-b634-7965-92ab-31fc26382683": {
"PV_drivers_detected": true,
"PV_drivers_up_to_date": true,
"PV_drivers_version": {
"build": "90977",
"major": "6",
"micro": "0",
"minor": "5"
},
"can_use_hotplug_vbd": "unspecified",
"can_use_hotplug_vif": "unspecified",
"disks": {},
"last_updated": "20190113T19:36:26Z",
"live": true,
"memory": {},
"networks": {
"0/ip": "169.254.0.2"
},
"os_version": {
"distro": "centos",
"major": "7",
"minor": "2",
"name": "CentOS Linux release 7.2.1511 (Core)",
"uname": "3.10.0-327.22.2.el7.x86_64"
},
"other": {
"feature-balloon": "1",
"feature-shutdown": "1",
"feature-suspend": "1",
"feature-vcpu-hotplug": "1",
"has-vendor-device": "0",
"platform-feature-multiprocessor-suspend": "1"
},
"other_config": {},
"uuid": "5c9d1be5-7eee-88f2-46c3-df1d44f9cdb5"
}
},
"VM_metrics": {
"OpaqueRef:b56b460b-6476-304d-b143-ce543ffab828": {
"VCPUs_CPU": {},
"VCPUs_flags": {},
"VCPUs_number": "1",
"VCPUs_params": {},
"VCPUs_utilisation": {},
"hvm": true,
"install_time": "20190113T19:32:46Z",
"last_updated": "19700101T00:00:00Z",
"memory_actual": "1073729536",
"nested_virt": false,
"nomigrate": false,
"other_config": {},
"start_time": "20190113T19:35:15Z",
"state": [],
"uuid": "876dd44c-aad1-97bf-9ee5-4cd58eac7163"
}
},
"host": {
"OpaqueRef:e87be804-57a1-532e-56ac-6c4910957be0": {
"API_version_major": "2",
"API_version_minor": "7",
"API_version_vendor": "XenSource",
"API_version_vendor_implementation": {},
"PBDs": [],
"PCIs": [],
"PGPUs": [],
"PIFs": [],
"address": "10.0.0.1",
"allowed_operations": [
"vm_migrate",
"provision",
"vm_resume",
"evacuate",
"vm_start"
],
"bios_strings": {},
"blobs": {},
"capabilities": [
"xen-3.0-x86_64",
"xen-3.0-x86_32p",
"hvm-3.0-x86_32",
"hvm-3.0-x86_32p",
"hvm-3.0-x86_64",
""
],
"chipset_info": {
"iommu": "true"
},
"control_domain": "OpaqueRef:ffcc92a1-8fde-df6f-a501-44b37811286b",
"cpu_configuration": {},
"cpu_info": {
"cpu_count": "40",
"family": "6",
"features": "7ffefbff-bfebfbff-00000021-2c100800",
"features_hvm": "17cbfbff-f7fa3223-2d93fbff-00000023-00000001-000007ab-00000000-00000000-00001000-0c000000",
"features_pv": "17c9cbf5-f6f83203-2191cbf5-00000023-00000001-00000329-00000000-00000000-00001000-0c000000",
"flags": "fpu de tsc msr pae mce cx8 apic sep mca cmov pat clflush acpi mmx fxsr sse sse2 ht syscall nx lm constant_tsc arch_perfmon rep_good nopl nonstop_tsc eagerfpu pni pclmulqdq monitor est ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm ida arat epb pln pts dtherm fsgsbase bmi1 avx2 bmi2 erms xsaveopt cqm_llc cqm_occup_llc",
"model": "63",
"modelname": "Intel(R) Xeon(R) CPU E5-2660 v3 @ 2.60GHz",
"socket_count": "2",
"speed": "2597.070",
"stepping": "2",
"vendor": "GenuineIntel"
},
"crash_dump_sr": "OpaqueRef:0b984cec-a36c-ce84-7b34-9f0088352d55",
"crashdumps": [],
"current_operations": {},
"display": "enabled",
"edition": "free",
"enabled": true,
"external_auth_configuration": {},
"external_auth_service_name": "",
"external_auth_type": "",
"features": [],
"guest_VCPUs_params": {},
"ha_network_peers": [],
"ha_statefiles": [],
"host_CPUs": [
"OpaqueRef:ec3ba9c4-9b57-236b-3eaa-b157affc1621",
"OpaqueRef:e6de7ab3-f4ad-f271-e51b-e3d8c041d3fb",
"OpaqueRef:e519ef88-bf41-86ac-16b3-c178cb4b78b1",
"OpaqueRef:e48f1bc1-98ba-89e5-ab69-821c625f7f82",
"OpaqueRef:e2659936-3de6-dbca-cc44-4af50960b2b7",
"OpaqueRef:d0da1e31-20ac-4aff-8897-e80df8200648",
"OpaqueRef:cec473ba-41a8-439d-b397-be0c60467b5d",
"OpaqueRef:ce88014d-b06c-c959-0624-04d79b791885",
"OpaqueRef:c656ca58-41fe-3689-d322-174aa5798beb",
"OpaqueRef:c0a21f14-8f46-19de-1cf4-530a34c4aa17",
"OpaqueRef:bf70c061-7b45-0497-7ef6-65a236e898e8",
"OpaqueRef:b7a2ba0f-f11b-3633-ad47-4f5f76a600a8",
"OpaqueRef:b4fef1fa-3aae-9790-f47e-6a17f645339c",
"OpaqueRef:b4594721-f8f4-4475-61c5-4efeec1733f1",
"OpaqueRef:9dcba36f-c29f-478f-f578-d1ea347410a6",
"OpaqueRef:987897e8-1184-917e-6a5f-e205d0c739e5",
"OpaqueRef:90f06d64-be18-7fdf-36ba-bbd696a26cf3",
"OpaqueRef:90150bc1-e604-4cd4-35ad-9cfa8e985de3",
"OpaqueRef:838f4ad4-8ad2-0d6c-a74e-26baa461de3d",
"OpaqueRef:736fb523-d347-e8c0-089b-c9811d3c1195",
"OpaqueRef:7137b479-87d4-9097-a684-e54cc4de5d09",
"OpaqueRef:6e08fa1d-7d7b-d9be-1574-ffe95bd515fd",
"OpaqueRef:6b9e6ecd-54e5-4248-5aea-ee5b99248818",
"OpaqueRef:65d56b24-3445-b444-5125-c91e6966fd29",
"OpaqueRef:60908eca-1e5c-c938-5b76-e8ff9d8899ab",
"OpaqueRef:46e96878-c076-2164-2373-6cdd108c2436",
"OpaqueRef:40ccdaf4-6008-2b83-92cb-ca197f73433f",
"OpaqueRef:3bc8133a-ccb2-6790-152f-b3f577517751",
"OpaqueRef:38c8edd8-0621-76de-53f6-86bef2a9e05c",
"OpaqueRef:342c1bab-a211-a0eb-79a5-780bd5ad1f23",
"OpaqueRef:1e20e6d0-5502-0dff-4f17-5d35eb833af1",
"OpaqueRef:176baafa-0e63-7000-f754-25e2a6b74959",
"OpaqueRef:16cab1a2-0111-b2af-6dfe-3724b79e6b6b",
"OpaqueRef:0f213647-8362-9c5e-e99b-0ebaefc609ce",
"OpaqueRef:0e019819-b41f-0bfb-d4ee-dd5484fea9b6",
"OpaqueRef:0d39212f-82ba-190c-b304-19b3fa491fff",
"OpaqueRef:087ce3ad-3b66-ae1e-3130-3ae640dcc638",
"OpaqueRef:0730f24c-87ed-8296-8f14-3036e5ad2357",
"OpaqueRef:04c27426-4895-39a7-9ade-ef33d3721c26",
"OpaqueRef:017b27bf-0270-19e7-049a-5a9b3bb54898"
],
"hostname": "ansible-test-host-2",
"license_params": {
"address1": "",
"address2": "",
"city": "",
"company": "",
"country": "",
"enable_xha": "true",
"expiry": "20291231T23:00:00Z",
"grace": "no",
"license_type": "",
"name": "",
"platform_filter": "false",
"postalcode": "",
"productcode": "",
"regular_nag_dialog": "false",
"restrict_ad": "false",
"restrict_batch_hotfix_apply": "true",
"restrict_checkpoint": "false",
"restrict_cifs": "true",
"restrict_connection": "false",
"restrict_cpu_masking": "false",
"restrict_dmc": "false",
"restrict_dr": "false",
"restrict_email_alerting": "false",
"restrict_equalogic": "false",
"restrict_export_resource_data": "true",
"restrict_gpu": "false",
"restrict_guest_agent_auto_update": "true",
"restrict_guest_ip_setting": "false",
"restrict_health_check": "false",
"restrict_historical_performance": "false",
"restrict_hotfix_apply": "false",
"restrict_integrated_gpu_passthrough": "false",
"restrict_intellicache": "false",
"restrict_lab": "false",
"restrict_live_patching": "true",
"restrict_marathon": "false",
"restrict_nested_virt": "true",
"restrict_netapp": "false",
"restrict_pci_device_for_auto_update": "true",
"restrict_pool_attached_storage": "false",
"restrict_pooling": "false",
"restrict_pvs_proxy": "true",
"restrict_qos": "false",
"restrict_rbac": "false",
"restrict_read_caching": "true",
"restrict_set_vcpus_number_live": "true",
"restrict_ssl_legacy_switch": "false",
"restrict_stage": "false",
"restrict_storage_xen_motion": "false",
"restrict_storagelink": "false",
"restrict_storagelink_site_recovery": "false",
"restrict_vgpu": "true",
"restrict_vif_locking": "false",
"restrict_vlan": "false",
"restrict_vm_memory_introspection": "true",
"restrict_vmpr": "false",
"restrict_vmss": "false",
"restrict_vss": "false",
"restrict_vswitch_controller": "false",
"restrict_web_selfservice": "true",
"restrict_web_selfservice_manager": "true",
"restrict_wlb": "true",
"restrict_xcm": "true",
"restrict_xen_motion": "false",
"serialnumber": "",
"sku_marketing_name": "Citrix XenServer",
"sku_type": "free",
"sockets": "2",
"state": "",
"version": ""
},
"license_server": {
"address": "localhost",
"port": "27000"
},
"local_cache_sr": "OpaqueRef:0b984cec-a36c-ce84-7b34-9f0088352d55",
"logging": {},
"memory_overhead": "4865126400",
"metrics": "OpaqueRef:f55653cb-92eb-8257-f2ee-7a2d1c2d6aef",
"name_description": "",
"name_label": "ansible-test-host-2",
"other_config": {
"agent_start_time": "1532019582.",
"boot_time": "1528986759.",
"iscsi_iqn": "iqn.2018-06.com.example:87b7637d",
"last_blob_sync_time": "1547394065.41",
"multipathhandle": "dmp",
"multipathing": "true"
},
"patches": [
"OpaqueRef:f5bd18b6-1423-893a-5d7f-7095338e6a2d",
"OpaqueRef:eecb0b95-87fb-a53e-651c-9741efd18bb6",
"OpaqueRef:e92c9ef3-2e51-1a36-d400-9e237982b782",
"OpaqueRef:cc98226c-2c08-799e-5f15-7761a398e4a0",
"OpaqueRef:c4f35e66-d064-55a7-6946-7f4b145275a6",
"OpaqueRef:c3794494-f894-6141-b811-f37a8fe60094",
"OpaqueRef:bcf61af7-63a9-e430-5b7c-a740ba470596",
"OpaqueRef:b58ac71e-797e-6f66-71ad-fe298c94fd10",
"OpaqueRef:a2ea18fd-5343-f8db-718d-f059c2a8cce0",
"OpaqueRef:929db459-6861-c588-158f-70f763331d6d",
"OpaqueRef:92962d94-2205-f6e1-12f9-b55a99fd824d",
"OpaqueRef:65dfb07a-f90d-dad9-9ab8-1cc2b1e79afb",
"OpaqueRef:537a87c4-3bf4-969f-f06a-2dd8d3a018a2",
"OpaqueRef:32dd1de3-c9c8-bcbb-27a0-83d4a930876d",
"OpaqueRef:30a8ccc8-74a9-b31f-0403-66b117e281b6",
"OpaqueRef:24545c44-ffd1-8a28-18c6-3d008bf4d63e",
"OpaqueRef:1fcef81b-7c44-a4db-f59a-c4a147da9c49",
"OpaqueRef:1e98a240-514b-1863-5518-c771d0ebf579",
"OpaqueRef:1632cab2-b268-6ce8-4f7b-ce7fd4bfa1eb"
],
"power_on_config": {},
"power_on_mode": "",
"resident_VMs": [],
"sched_policy": "credit",
"software_version": {
"build_number": "release/falcon/master/8",
"date": "2017-05-11",
"db_schema": "5.120",
"dbv": "2017.0517",
"hostname": "f7d02093adae",
"linux": "4.4.0+10",
"network_backend": "openvswitch",
"platform_name": "XCP",
"platform_version": "2.3.0",
"product_brand": "XenServer",
"product_version": "7.2.0",
"product_version_text": "7.2",
"product_version_text_short": "7.2",
"xapi": "1.9",
"xen": "4.7.5-2.12",
"xencenter_max": "2.7",
"xencenter_min": "2.7"
},
"ssl_legacy": true,
"supported_bootloaders": [
"pygrub",
"eliloader"
],
"suspend_image_sr": "OpaqueRef:0b984cec-a36c-ce84-7b34-9f0088352d55",
"tags": [],
"updates": [
"OpaqueRef:7b4b5da1-54af-d0c4-3fea-394b4257bffe",
"OpaqueRef:fbaabbfe-88d5-d89b-5b3f-d6374601ca71",
"OpaqueRef:507ee5fc-59d3-e635-21d5-98a5cace4bf2",
"OpaqueRef:6c9b814c-e1c2-b8be-198f-de358686b10a",
"OpaqueRef:a17e721d-faf4-6ad1-c617-dd4899279534",
"OpaqueRef:6ac77a0f-f079-8067-85cc-c9ae2f8dcca9",
"OpaqueRef:f61edc83-91d9-a161-113f-00c110196238",
"OpaqueRef:b71938bf-4c4f-eb17-7e78-588e71297a74",
"OpaqueRef:01befb95-412e-e9dd-5b5d-edd50df61cb1",
"OpaqueRef:a3f9481e-fe3d-1f00-235f-44d404f51128",
"OpaqueRef:0760c608-b02e-743a-18a1-fa8f205374d6",
"OpaqueRef:204558d7-dce0-2304-bdc5-80ec5fd7e3c3",
"OpaqueRef:9eccc765-9726-d220-96b1-2e85adf77ecc",
"OpaqueRef:91cfa47b-52f9-a4e3-4e78-52e3eb3e5141",
"OpaqueRef:3fffd7c7-f4d1-6b03-a5b8-d75211bb7b8f",
"OpaqueRef:7efce157-9b93-d116-f3f8-7eb0c6fb1a79",
"OpaqueRef:e2209ae9-5362-3a20-f691-9294144e49f2",
"OpaqueRef:1ced32ca-fec4-8b44-0e8f-753c97f2d93f",
"OpaqueRef:65b14ae7-f440-0c4d-4af9-c7946b90fd2f"
],
"updates_requiring_reboot": [],
"uuid": "dff6702e-bcb6-4704-8dd4-952e8c883365",
"virtual_hardware_platform_versions": [
"0",
"1",
"2"
]
}
},
"network": {
"OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724": {
"MTU": "1500",
"PIFs": [],
"VIFs": [],
"allowed_operations": [],
"assigned_ips": {
"OpaqueRef:8171dad1-f902-ec00-7ba2-9f92d8aa75ab": "169.254.0.3",
"OpaqueRef:9754a0ed-e100-d224-6a70-a55a9c2cedf9": "169.254.0.2"
},
"blobs": {},
"bridge": "xenapi",
"current_operations": {},
"default_locking_mode": "unlocked",
"managed": true,
"name_description": "Network on which guests will be assigned a private link-local IP address which can be used to talk XenAPI",
"name_label": "Host internal management network",
"other_config": {
"ip_begin": "169.254.0.1",
"ip_end": "169.254.255.254",
"is_guest_installer_network": "true",
"is_host_internal_management_network": "true",
"netmask": "255.255.0.0"
},
"tags": [],
"uuid": "dbb96525-944f-0d1a-54ed-e65cb6d07450"
}
}
}

@ -0,0 +1,75 @@
{
"cdrom": {
"type": "none"
},
"customization_agent": "custom",
"disks": [
{
"name": "ansible-test-vm-3-root",
"name_desc": "/",
"os_device": "xvda",
"size": 8589934592,
"sr": "Ansible Test Storage 1",
"sr_uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"vbd_userdevice": "0"
}
],
"domid": "-1",
"folder": "",
"hardware": {
"memory_mb": 1024,
"num_cpu_cores_per_socket": 1,
"num_cpus": 1
},
"home_server": "",
"is_template": false,
"name": "ansible-test-vm-3",
"name_desc": "Created by Ansible",
"networks": [
{
"gateway": "",
"gateway6": "",
"ip": "169.254.0.3",
"ip6": [],
"mac": "72:fb:c7:ac:b9:97",
"mtu": "1500",
"name": "Host internal management network",
"netmask": "",
"prefix": "",
"prefix6": "",
"vif_device": "0"
}
],
"other_config": {
"auto_poweron": "true",
"base_template_name": "zatemplate",
"import_task": "OpaqueRef:9948fd82-6d79-8882-2f01-4edc8795e361",
"install-methods": "cdrom,nfs,http,ftp",
"install-repository": "http://mirror.centos.org/centos-6/6.2/os/x86_64/",
"instant": "true",
"last_shutdown_action": "Destroy",
"last_shutdown_initiator": "external",
"last_shutdown_reason": "halted",
"last_shutdown_time": "20140314T21:16:41Z",
"linux_template": "true",
"mac_seed": "06e27068-70c2-4c69-614b-7c54b5a4a781",
"rhel6": "true"
},
"platform": {
"acpi": "true",
"apic": "true",
"cores-per-socket": "1",
"nx": "false",
"pae": "true",
"viridian": "true"
},
"state": "poweredoff",
"uuid": "8f5bc97c-42fa-d619-aba4-d25eced735e0",
"xenstore_data": {
"vm-data": "",
"vm-data/networks": "",
"vm-data/networks/0": "",
"vm-data/networks/0/mac": "72:fb:c7:ac:b9:97",
"vm-data/networks/0/name": "Host internal management network"
}
}

@ -0,0 +1,420 @@
{
"SR": {
"OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f": {
"PBDs": [],
"VDIs": [],
"allowed_operations": [
"unplug",
"plug",
"pbd_create",
"update",
"pbd_destroy",
"vdi_resize",
"vdi_clone",
"scan",
"vdi_snapshot",
"vdi_mirror",
"vdi_create",
"vdi_destroy"
],
"blobs": {},
"clustered": false,
"content_type": "",
"current_operations": {},
"introduced_by": "OpaqueRef:NULL",
"is_tools_sr": false,
"local_cache_enabled": false,
"name_description": "",
"name_label": "Ansible Test Storage 1",
"other_config": {
"auto-scan": "false"
},
"physical_size": "2521133219840",
"physical_utilisation": "1551485632512",
"shared": true,
"sm_config": {
"allocation": "thick",
"devserial": "scsi-3600a098038302d353624495242443848",
"multipathable": "true",
"use_vhd": "true"
},
"tags": [],
"type": "lvmohba",
"uuid": "767b30e4-f8db-a83d-8ba7-f5e6e732e06f",
"virtual_allocation": "1556925644800"
}
},
"VBD": {
"OpaqueRef:024b722e-8d0f-65e6-359e-f301a009b683": {
"VDI": "OpaqueRef:NULL",
"VM": "OpaqueRef:957f576a-2347-1789-80db-4beb50466bc2",
"allowed_operations": [
"attach",
"insert"
],
"bootable": false,
"current_operations": {},
"currently_attached": false,
"device": "",
"empty": true,
"metrics": "OpaqueRef:81509584-b22f-bc71-3c4e-e6c3bdca71f0",
"mode": "RO",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "CD",
"unpluggable": true,
"userdevice": "3",
"uuid": "38d850d0-c402-490e-6b97-1d23558c4e0e"
},
"OpaqueRef:235f4f04-1dc9-9fa5-c229-a1df187ba48c": {
"VDI": "OpaqueRef:4d3e9fc7-ae61-b312-e0a8-b53bee06282e",
"VM": "OpaqueRef:957f576a-2347-1789-80db-4beb50466bc2",
"allowed_operations": [
"attach"
],
"bootable": true,
"current_operations": {},
"currently_attached": false,
"device": "xvda",
"empty": false,
"metrics": "OpaqueRef:529f6071-5627-28c5-1f41-ee8c0733f1da",
"mode": "RW",
"other_config": {
"owner": ""
},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"storage_lock": false,
"type": "Disk",
"unpluggable": false,
"userdevice": "0",
"uuid": "3fd7d35c-cb9d-f0c4-726b-e188ef0dc446"
}
},
"VDI": {
"OpaqueRef:4d3e9fc7-ae61-b312-e0a8-b53bee06282e": {
"SR": "OpaqueRef:f746e964-e0fe-c36d-d60b-6897cfde583f",
"VBDs": [
"OpaqueRef:235f4f04-1dc9-9fa5-c229-a1df187ba48c"
],
"allow_caching": false,
"allowed_operations": [
"forget",
"generate_config",
"update",
"resize",
"destroy",
"clone",
"copy",
"snapshot"
],
"crash_dumps": [],
"current_operations": {},
"is_a_snapshot": false,
"is_tools_iso": false,
"location": "bdd0baeb-5447-4963-9e71-a5ff6e85fa59",
"managed": true,
"metadata_latest": false,
"metadata_of_pool": "",
"missing": false,
"name_description": "/",
"name_label": "ansible-test-vm-3-root",
"on_boot": "persist",
"other_config": {
"content_id": "cd8e8b2b-f158-c519-02f0-81d130fe83c5"
},
"parent": "OpaqueRef:NULL",
"physical_utilisation": "8615100416",
"read_only": false,
"sharable": false,
"sm_config": {
"vdi_type": "vhd"
},
"snapshot_of": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"storage_lock": false,
"tags": [],
"type": "system",
"uuid": "bdd0baeb-5447-4963-9e71-a5ff6e85fa59",
"virtual_size": "8589934592",
"xenstore_data": {}
}
},
"VIF": {
"OpaqueRef:8171dad1-f902-ec00-7ba2-9f92d8aa75ab": {
"MAC": "72:fb:c7:ac:b9:97",
"MAC_autogenerated": true,
"MTU": "1500",
"VM": "OpaqueRef:957f576a-2347-1789-80db-4beb50466bc2",
"allowed_operations": [
"attach"
],
"current_operations": {},
"currently_attached": false,
"device": "0",
"ipv4_addresses": [],
"ipv4_allowed": [],
"ipv4_configuration_mode": "None",
"ipv4_gateway": "",
"ipv6_addresses": [],
"ipv6_allowed": [],
"ipv6_configuration_mode": "None",
"ipv6_gateway": "",
"locking_mode": "network_default",
"metrics": "OpaqueRef:e5b53fb1-3e99-4bf5-6b00-95fdba1f2610",
"network": "OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724",
"other_config": {},
"qos_algorithm_params": {},
"qos_algorithm_type": "",
"qos_supported_algorithms": [],
"runtime_properties": {},
"status_code": "0",
"status_detail": "",
"uuid": "94bd4913-4940-437c-a1c3-50f7eb354c55"
}
},
"VM": {
"OpaqueRef:957f576a-2347-1789-80db-4beb50466bc2": {
"HVM_boot_params": {
"order": ""
},
"HVM_boot_policy": "",
"HVM_shadow_multiplier": 1.0,
"PCI_bus": "",
"PV_args": "graphical utf8",
"PV_bootloader": "pygrub",
"PV_bootloader_args": "",
"PV_kernel": "",
"PV_legacy_args": "",
"PV_ramdisk": "",
"VBDs": [
"OpaqueRef:235f4f04-1dc9-9fa5-c229-a1df187ba48c",
"OpaqueRef:024b722e-8d0f-65e6-359e-f301a009b683"
],
"VCPUs_at_startup": "1",
"VCPUs_max": "1",
"VCPUs_params": {},
"VGPUs": [],
"VIFs": [
"OpaqueRef:8171dad1-f902-ec00-7ba2-9f92d8aa75ab"
],
"VTPMs": [],
"actions_after_crash": "restart",
"actions_after_reboot": "restart",
"actions_after_shutdown": "destroy",
"affinity": "OpaqueRef:NULL",
"allowed_operations": [
"changing_dynamic_range",
"changing_shadow_memory",
"changing_static_range",
"make_into_template",
"migrate_send",
"destroy",
"export",
"start_on",
"start",
"clone",
"copy",
"snapshot"
],
"appliance": "OpaqueRef:NULL",
"attached_PCIs": [],
"bios_strings": {
"bios-vendor": "Xen",
"bios-version": "",
"hp-rombios": "",
"oem-1": "Xen",
"oem-2": "MS_VM_CERT/SHA1/bdbeb6e0a816d43fa6d3fe8aaef04c2bad9d3e3d",
"system-manufacturer": "Xen",
"system-product-name": "HVM domU",
"system-serial-number": "",
"system-version": ""
},
"blobs": {},
"blocked_operations": {},
"children": [],
"consoles": [],
"crash_dumps": [],
"current_operations": {},
"domarch": "",
"domid": "-1",
"generation_id": "",
"guest_metrics": "OpaqueRef:6a8acd85-4cab-4e52-27d5-5f4a51c1bf69",
"ha_always_run": false,
"ha_restart_priority": "",
"hardware_platform_version": "0",
"has_vendor_device": false,
"is_a_snapshot": false,
"is_a_template": false,
"is_control_domain": false,
"is_default_template": false,
"is_snapshot_from_vmpp": false,
"is_vmss_snapshot": false,
"last_boot_CPU_flags": {
"features": "17c9cbf5-f6f83203-2191cbf5-00000023-00000001-00000329-00000000-00000000-00001000-0c000000",
"vendor": "GenuineIntel"
},
"last_booted_record": "",
"memory_dynamic_max": "1073741824",
"memory_dynamic_min": "1073741824",
"memory_overhead": "10485760",
"memory_static_max": "1073741824",
"memory_static_min": "536870912",
"memory_target": "0",
"metrics": "OpaqueRef:87fc5829-478b-1dcd-989f-50e8ba58a87d",
"name_description": "Created by Ansible",
"name_label": "ansible-test-vm-3",
"order": "0",
"other_config": {
"auto_poweron": "true",
"base_template_name": "zatemplate",
"import_task": "OpaqueRef:9948fd82-6d79-8882-2f01-4edc8795e361",
"install-methods": "cdrom,nfs,http,ftp",
"install-repository": "http://mirror.centos.org/centos-6/6.2/os/x86_64/",
"instant": "true",
"last_shutdown_action": "Destroy",
"last_shutdown_initiator": "external",
"last_shutdown_reason": "halted",
"last_shutdown_time": "20140314T21:16:41Z",
"linux_template": "true",
"mac_seed": "06e27068-70c2-4c69-614b-7c54b5a4a781",
"rhel6": "true"
},
"parent": "OpaqueRef:NULL",
"platform": {
"acpi": "true",
"apic": "true",
"cores-per-socket": "1",
"nx": "false",
"pae": "true",
"viridian": "true"
},
"power_state": "Halted",
"protection_policy": "OpaqueRef:NULL",
"recommendations": "<restrictions><restriction field=\"memory-static-max\" max=\"17179869184\" /><restriction field=\"vcpus-max\" max=\"8\" /><restriction property=\"number-of-vbds\" max=\"7\" /><restriction property=\"number-of-vifs\" max=\"7\" /></restrictions>",
"reference_label": "",
"requires_reboot": false,
"resident_on": "OpaqueRef:NULL",
"shutdown_delay": "0",
"snapshot_info": {},
"snapshot_metadata": "",
"snapshot_of": "OpaqueRef:NULL",
"snapshot_schedule": "OpaqueRef:NULL",
"snapshot_time": "19700101T00:00:00Z",
"snapshots": [],
"start_delay": "0",
"suspend_SR": "OpaqueRef:NULL",
"suspend_VDI": "OpaqueRef:NULL",
"tags": [
"web-frontend"
],
"transportable_snapshot_id": "",
"user_version": "1",
"uuid": "8f5bc97c-42fa-d619-aba4-d25eced735e0",
"version": "0",
"xenstore_data": {
"vm-data": "",
"vm-data/networks": "",
"vm-data/networks/0": "",
"vm-data/networks/0/mac": "72:fb:c7:ac:b9:97",
"vm-data/networks/0/name": "Host internal management network"
}
}
},
"VM_guest_metrics": {
"OpaqueRef:6a8acd85-4cab-4e52-27d5-5f4a51c1bf69": {
"PV_drivers_detected": true,
"PV_drivers_up_to_date": true,
"PV_drivers_version": {
"build": "46676",
"major": "5",
"micro": "100",
"minor": "6"
},
"can_use_hotplug_vbd": "unspecified",
"can_use_hotplug_vif": "unspecified",
"disks": {},
"last_updated": "20190113T19:36:07Z",
"live": true,
"memory": {},
"networks": {
"0/ip": "169.254.0.3"
},
"os_version": {
"distro": "centos",
"major": "6",
"minor": "10",
"name": "CentOS release 6.10 (Final)",
"uname": "2.6.32-754.6.3.el6.x86_64"
},
"other": {
"feature-balloon": "1",
"has-vendor-device": "0",
"platform-feature-multiprocessor-suspend": "1"
},
"other_config": {},
"uuid": "3928a6a4-1acd-c134-ed35-eb0ccfaed65c"
}
},
"VM_metrics": {
"OpaqueRef:87fc5829-478b-1dcd-989f-50e8ba58a87d": {
"VCPUs_CPU": {},
"VCPUs_flags": {},
"VCPUs_number": "0",
"VCPUs_params": {},
"VCPUs_utilisation": {
"0": 0.0
},
"hvm": false,
"install_time": "20190113T19:35:05Z",
"last_updated": "19700101T00:00:00Z",
"memory_actual": "1073741824",
"nested_virt": false,
"nomigrate": false,
"other_config": {},
"start_time": "19700101T00:00:00Z",
"state": [],
"uuid": "6cb05fe9-b83e-34c8-29e0-3b793e1da661"
}
},
"host": {},
"network": {
"OpaqueRef:8a404c5e-5673-ab69-5d6f-5a35a33b8724": {
"MTU": "1500",
"PIFs": [],
"VIFs": [],
"allowed_operations": [],
"assigned_ips": {
"OpaqueRef:8171dad1-f902-ec00-7ba2-9f92d8aa75ab": "169.254.0.3",
"OpaqueRef:9754a0ed-e100-d224-6a70-a55a9c2cedf9": "169.254.0.2"
},
"blobs": {},
"bridge": "xenapi",
"current_operations": {},
"default_locking_mode": "unlocked",
"managed": true,
"name_description": "Network on which guests will be assigned a private link-local IP address which can be used to talk XenAPI",
"name_label": "Host internal management network",
"other_config": {
"ip_begin": "169.254.0.1",
"ip_end": "169.254.255.254",
"is_guest_installer_network": "true",
"is_host_internal_management_network": "true",
"netmask": "255.255.0.0"
},
"tags": [],
"uuid": "dbb96525-944f-0d1a-54ed-e65cb6d07450"
}
}
}

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from .common import testcase_bad_xenapi_refs
testcase_gather_vm_params_and_facts = {
"params": [
["ansible-test-vm-1-params.json", "ansible-test-vm-1-facts.json"],
["ansible-test-vm-2-params.json", "ansible-test-vm-2-facts.json"],
["ansible-test-vm-3-params.json", "ansible-test-vm-3-facts.json"],
],
"ids": [
"ansible-test-vm-1",
"ansible-test-vm-2",
"ansible-test-vm-3",
],
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids'])
def test_gather_vm_params_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests return of empty dict on bad vm_ref."""
assert xenserver.gather_vm_params(fake_ansible_module, vm_ref) == {}
def test_gather_vm_facts_no_vm_params(fake_ansible_module, xenserver):
"""Tests return of empty facts dict when vm_params is not available"""
assert xenserver.gather_vm_facts(fake_ansible_module, None) == {}
assert xenserver.gather_vm_facts(fake_ansible_module, {}) == {}
@pytest.mark.parametrize('fixture_data_from_file',
testcase_gather_vm_params_and_facts['params'],
ids=testcase_gather_vm_params_and_facts['ids'],
indirect=True)
def test_gather_vm_params_and_facts(mocker, fake_ansible_module, XenAPI, xenserver, fixture_data_from_file):
"""Tests proper parsing of VM parameters and facts."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
if "params" in list(fixture_data_from_file.keys())[0]:
params_file = list(fixture_data_from_file.keys())[0]
facts_file = list(fixture_data_from_file.keys())[1]
else:
params_file = list(fixture_data_from_file.keys())[1]
facts_file = list(fixture_data_from_file.keys())[0]
mocked_returns = {
"VM.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM'][obj_ref],
"VM_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM_metrics'][obj_ref],
"VM_guest_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM_guest_metrics'][obj_ref],
"VBD.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VBD'][obj_ref],
"VDI.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VDI'][obj_ref],
"SR.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['SR'][obj_ref],
"VIF.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VIF'][obj_ref],
"network.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['network'][obj_ref],
"host.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['host'][obj_ref],
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible.module_utils.xenserver.get_xenserver_version', return_value=['7', '2'])
vm_ref = list(fixture_data_from_file[params_file]['VM'].keys())[0]
assert xenserver.gather_vm_facts(fake_ansible_module, xenserver.gather_vm_params(fake_ansible_module, vm_ref)) == fixture_data_from_file[facts_file]

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from .common import fake_xenapi_ref
def test_get_object_ref_xenapi_failure(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests catching of XenAPI failures."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', side_effect=XenAPI.Failure('Fake XAPI method call error!'))
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name")
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: Fake XAPI method call error!"
def test_get_object_ref_bad_uuid_and_name(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests failure on bad object uuid and/or name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request')
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, None, msg_prefix="Test: ")
mocked_xenapi.xenapi_request.assert_not_called()
assert exc_info.value.kwargs['msg'] == "Test: no valid name or UUID supplied for VM!"
def test_get_object_ref_uuid_not_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when object is not found by uuid."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', side_effect=XenAPI.Failure('Fake XAPI not found error!'))
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", uuid="fake-uuid", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == "Test: VM with UUID 'fake-uuid' not found!"
assert xenserver.get_object_ref(fake_ansible_module, "name", uuid="fake-uuid", fail=False, msg_prefix="Test: ") is None
def test_get_object_ref_name_not_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when object is not found by name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', return_value=[])
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == "Test: VM with name 'name' not found!"
assert xenserver.get_object_ref(fake_ansible_module, "name", fail=False, msg_prefix="Test: ") is None
def test_get_object_ref_name_multiple_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when multiple objects are found by name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', return_value=[fake_xenapi_ref('VM'), fake_xenapi_ref('VM')])
error_msg = "Test: multiple VMs with name 'name' found! Please use UUID."
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == error_msg
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", fail=False, msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == error_msg

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
def test_xapi_to_module_vm_power_state_bad_power_state(xenserver):
"""Tests that None is returned on bad power state."""
assert xenserver.xapi_to_module_vm_power_state("bad") is None
def test_module_to_xapi_vm_power_state_bad_power_state(xenserver):
"""Tests that None is returned on bad power state."""
assert xenserver.module_to_xapi_vm_power_state("bad") is None

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
testcase_is_valid_mac_addr = [
('A4-23-8D-F8-C9-E5', True),
('35:71:F4:11:0B:D8', True),
('b3-bd-20-59-0c-cf', True),
('32:61:ca:65:f1:f4', True),
('asdf', False),
('A4-23-8D-G8-C9-E5', False),
('A4-3-8D-F8-C9-E5', False),
('A4-23-88D-F8-C9-E5', False),
('A4-23-8D-F8-C9_E5', False),
('A4-23--8D-F8-C9-E5', False),
]
testcase_is_valid_ip_addr = [
('0.0.0.0', True),
('10.0.0.1', True),
('192.168.0.1', True),
('255.255.255.255', True),
('asdf', False),
('a.b.c.d', False),
('345.345.345.345', False),
('-10.0.0.1', False),
]
testcase_is_valid_ip_netmask = [
('240.0.0.0', True),
('255.224.0.0', True),
('255.255.248.0', True),
('255.255.255.255', True),
('asdf', False),
('a.b.c.d', False),
('192.168.0.1', False),
('255.0.248.0', False),
]
testcase_is_valid_ip_prefix = [
('0', True),
('16', True),
('24', True),
('32', True),
('asdf', False),
('-10', False),
('60', False),
('60s', False),
]
testcase_ip_prefix_to_netmask = {
"params": [
('0', '0.0.0.0'),
('8', '255.0.0.0'),
('11', '255.224.0.0'),
('16', '255.255.0.0'),
('21', '255.255.248.0'),
('24', '255.255.255.0'),
('26', '255.255.255.192'),
('32', '255.255.255.255'),
('a', ''),
('60', ''),
],
"ids": [
'0',
'8',
'11',
'16',
'21',
'24',
'26',
'32',
'a',
'60',
],
}
testcase_ip_netmask_to_prefix = {
"params": [
('0.0.0.0', '0'),
('255.0.0.0', '8'),
('255.224.0.0', '11'),
('255.255.0.0', '16'),
('255.255.248.0', '21'),
('255.255.255.0', '24'),
('255.255.255.192', '26'),
('255.255.255.255', '32'),
('a', ''),
('60', ''),
],
"ids": [
'0.0.0.0',
'255.0.0.0',
'255.224.0.0',
'255.255.0.0',
'255.255.248.0',
'255.255.255.0',
'255.255.255.192',
'255.255.255.255',
'a',
'60',
],
}
testcase_is_valid_ip6_addr = [
('::1', True),
('2001:DB8:0:0:8:800:200C:417A', True),
('2001:DB8::8:800:200C:417A', True),
('FF01::101', True),
('asdf', False),
('2001:DB8:0:0:8:800:200C:417A:221', False),
('FF01::101::2', False),
('2001:db8:85a3::8a2e:370k:7334', False),
]
testcase_is_valid_ip6_prefix = [
('0', True),
('56', True),
('78', True),
('128', True),
('asdf', False),
('-10', False),
('345', False),
('60s', False),
]
@pytest.mark.parametrize('mac_addr, result', testcase_is_valid_mac_addr)
def test_is_valid_mac_addr(xenserver, mac_addr, result):
"""Tests against examples of valid and invalid mac addresses."""
assert xenserver.is_valid_mac_addr(mac_addr) is result
@pytest.mark.parametrize('ip_addr, result', testcase_is_valid_ip_addr)
def test_is_valid_ip_addr(xenserver, ip_addr, result):
"""Tests against examples of valid and invalid ip addresses."""
assert xenserver.is_valid_ip_addr(ip_addr) is result
@pytest.mark.parametrize('ip_netmask, result', testcase_is_valid_ip_netmask)
def test_is_valid_ip_netmask(xenserver, ip_netmask, result):
"""Tests against examples of valid and invalid ip netmasks."""
assert xenserver.is_valid_ip_netmask(ip_netmask) is result
@pytest.mark.parametrize('ip_prefix, result', testcase_is_valid_ip_prefix)
def test_is_valid_ip_prefix(xenserver, ip_prefix, result):
"""Tests against examples of valid and invalid ip prefixes."""
assert xenserver.is_valid_ip_prefix(ip_prefix) is result
@pytest.mark.parametrize('ip_prefix, ip_netmask', testcase_ip_prefix_to_netmask['params'], ids=testcase_ip_prefix_to_netmask['ids'])
def test_ip_prefix_to_netmask(xenserver, ip_prefix, ip_netmask):
"""Tests ip prefix to netmask conversion."""
assert xenserver.ip_prefix_to_netmask(ip_prefix) == ip_netmask
@pytest.mark.parametrize('ip_netmask, ip_prefix', testcase_ip_netmask_to_prefix['params'], ids=testcase_ip_netmask_to_prefix['ids'])
def test_ip_netmask_to_prefix(xenserver, ip_netmask, ip_prefix):
"""Tests ip netmask to prefix conversion."""
assert xenserver.ip_netmask_to_prefix(ip_netmask) == ip_prefix
@pytest.mark.parametrize('ip6_addr, result', testcase_is_valid_ip6_addr)
def test_is_valid_ip6_addr(xenserver, ip6_addr, result):
"""Tests against examples of valid and invalid ip6 addresses."""
assert xenserver.is_valid_ip6_addr(ip6_addr) is result
@pytest.mark.parametrize('ip6_prefix, result', testcase_is_valid_ip6_prefix)
def test_is_valid_ip6_prefix(xenserver, ip6_prefix, result):
"""Tests against examples of valid and invalid ip6 prefixes."""
assert xenserver.is_valid_ip6_prefix(ip6_prefix) is result

@ -0,0 +1,413 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from .common import fake_xenapi_ref, testcase_bad_xenapi_refs
testcase_set_vm_power_state_bad_transitions = {
"params": [
('restarted', 'Halted', "Cannot restart VM in state 'poweredoff'!"),
('restarted', 'Suspended', "Cannot restart VM in state 'suspended'!"),
('suspended', 'Halted', "Cannot suspend VM in state 'poweredoff'!"),
('suspended', 'Paused', "Cannot suspend VM in state 'paused'!"),
('shutdownguest', 'Halted', "Cannot shutdown guest when VM is in state 'poweredoff'."),
('shutdownguest', 'Suspended', "Cannot shutdown guest when VM is in state 'suspended'."),
('shutdownguest', 'Paused', "Cannot shutdown guest when VM is in state 'paused'."),
('rebootguest', 'Halted', "Cannot reboot guest when VM is in state 'poweredoff'."),
('rebootguest', 'Suspended', "Cannot reboot guest when VM is in state 'suspended'."),
('rebootguest', 'Paused', "Cannot reboot guest when VM is in state 'paused'."),
],
"ids": [
"poweredoff->restarted",
"suspended->restarted",
"poweredoff->suspended",
"paused->suspended",
"poweredoff->shutdownguest",
"suspended->shutdownguest",
"paused->shutdownguest",
"poweredoff->rebootguest",
"suspended->rebootguest",
"paused->rebootguest",
],
}
testcase_set_vm_power_state_task_timeout = {
"params": [
('shutdownguest', "Guest shutdown task failed: 'timeout'!"),
('rebootguest', "Guest reboot task failed: 'timeout'!"),
],
"ids": [
"shutdownguest-timeout",
"rebootguest-timeout",
],
}
testcase_set_vm_power_state_no_transitions = {
"params": [
('poweredon', "Running"),
('Poweredon', "Running"),
('powered-on', "Running"),
('Powered_on', "Running"),
('poweredoff', "Halted"),
('Poweredoff', "Halted"),
('powered-off', "Halted"),
('powered_off', "Halted"),
('suspended', "Suspended"),
('Suspended', "Suspended"),
],
"ids": [
"poweredon",
"poweredon-cap",
"poweredon-dash",
"poweredon-under",
"poweredoff",
"poweredoff-cap",
"poweredoff-dash",
"poweredoff-under",
"suspended",
"suspended-cap",
],
}
testcase_set_vm_power_state_transitions = {
"params": [
('poweredon', 'Halted', 'running', 'VM.start'),
('Poweredon', 'Halted', 'running', 'VM.start'),
('powered-on', 'Halted', 'running', 'VM.start'),
('Powered_on', 'Halted', 'running', 'VM.start'),
('poweredon', 'Suspended', 'running', 'VM.resume'),
('Poweredon', 'Suspended', 'running', 'VM.resume'),
('powered-on', 'Suspended', 'running', 'VM.resume'),
('Powered_on', 'Suspended', 'running', 'VM.resume'),
('poweredon', 'Paused', 'running', 'VM.unpause'),
('Poweredon', 'Paused', 'running', 'VM.unpause'),
('powered-on', 'Paused', 'running', 'VM.unpause'),
('Powered_on', 'Paused', 'running', 'VM.unpause'),
('poweredoff', 'Running', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Running', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Running', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Running', 'halted', 'VM.hard_shutdown'),
('poweredoff', 'Suspended', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Suspended', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Suspended', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Suspended', 'halted', 'VM.hard_shutdown'),
('poweredoff', 'Paused', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Paused', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Paused', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Paused', 'halted', 'VM.hard_shutdown'),
('restarted', 'Running', 'running', 'VM.hard_reboot'),
('Restarted', 'Running', 'running', 'VM.hard_reboot'),
('restarted', 'Paused', 'running', 'VM.hard_reboot'),
('Restarted', 'Paused', 'running', 'VM.hard_reboot'),
('suspended', 'Running', 'suspended', 'VM.suspend'),
('Suspended', 'Running', 'suspended', 'VM.suspend'),
('shutdownguest', 'Running', 'halted', 'VM.clean_shutdown'),
('Shutdownguest', 'Running', 'halted', 'VM.clean_shutdown'),
('shutdown-guest', 'Running', 'halted', 'VM.clean_shutdown'),
('shutdown_guest', 'Running', 'halted', 'VM.clean_shutdown'),
('rebootguest', 'Running', 'running', 'VM.clean_reboot'),
('rebootguest', 'Running', 'running', 'VM.clean_reboot'),
('reboot-guest', 'Running', 'running', 'VM.clean_reboot'),
('reboot_guest', 'Running', 'running', 'VM.clean_reboot'),
],
"ids": [
"poweredoff->poweredon",
"poweredoff->poweredon-cap",
"poweredoff->poweredon-dash",
"poweredoff->poweredon-under",
"suspended->poweredon",
"suspended->poweredon-cap",
"suspended->poweredon-dash",
"suspended->poweredon-under",
"paused->poweredon",
"paused->poweredon-cap",
"paused->poweredon-dash",
"paused->poweredon-under",
"poweredon->poweredoff",
"poweredon->poweredoff-cap",
"poweredon->poweredoff-dash",
"poweredon->poweredoff-under",
"suspended->poweredoff",
"suspended->poweredoff-cap",
"suspended->poweredoff-dash",
"suspended->poweredoff-under",
"paused->poweredoff",
"paused->poweredoff-cap",
"paused->poweredoff-dash",
"paused->poweredoff-under",
"poweredon->restarted",
"poweredon->restarted-cap",
"paused->restarted",
"paused->restarted-cap",
"poweredon->suspended",
"poweredon->suspended-cap",
"poweredon->shutdownguest",
"poweredon->shutdownguest-cap",
"poweredon->shutdownguest-dash",
"poweredon->shutdownguest-under",
"poweredon->rebootguest",
"poweredon->rebootguest-cap",
"poweredon->rebootguest-dash",
"poweredon->rebootguest-under",
],
}
testcase_set_vm_power_state_transitions_async = {
"params": [
('shutdownguest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('Shutdownguest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('shutdown-guest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('shutdown_guest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('rebootguest', 'Running', 'running', 'Async.VM.clean_reboot'),
('rebootguest', 'Running', 'running', 'Async.VM.clean_reboot'),
('reboot-guest', 'Running', 'running', 'Async.VM.clean_reboot'),
('reboot_guest', 'Running', 'running', 'Async.VM.clean_reboot'),
],
"ids": [
"poweredon->shutdownguest",
"poweredon->shutdownguest-cap",
"poweredon->shutdownguest-dash",
"poweredon->shutdownguest-under",
"poweredon->rebootguest",
"poweredon->rebootguest-cap",
"poweredon->rebootguest-dash",
"poweredon->rebootguest-under",
],
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids'])
def test_set_vm_power_state_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, vm_ref, None)
assert exc_info.value.kwargs['msg'] == "Cannot set VM power state. Invalid VM reference supplied!"
def test_set_vm_power_state_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), "poweredon")
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: %s" % mock_xenapi_failure[1]
def test_set_vm_power_state_bad_power_state(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests failure on unsupported power state."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
}
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), "bad")
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert exc_info.value.kwargs['msg'] == "Requested VM power state 'bad' is unsupported!"
@pytest.mark.parametrize('power_state_desired, power_state_current, error_msg',
testcase_set_vm_power_state_bad_transitions['params'],
ids=testcase_set_vm_power_state_bad_transitions['ids'])
def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current, error_msg):
"""Tests failure on bad power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
}
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired)
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert exc_info.value.kwargs['msg'] == error_msg
@pytest.mark.parametrize('power_state, error_msg',
testcase_set_vm_power_state_task_timeout['params'],
ids=testcase_set_vm_power_state_task_timeout['ids'])
def test_set_vm_power_state_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver, power_state, error_msg):
"""Tests failure on async task timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
"Async.VM.clean_shutdown.return_value": fake_xenapi_ref('task'),
"Async.VM.clean_reboot.return_value": fake_xenapi_ref('task'),
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible.module_utils.xenserver.wait_for_task', return_value="timeout")
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state, timeout=1)
# Beside VM.get_power_state() only one of Async.VM.clean_shutdown or
# Async.VM.clean_reboot should have been called additionally.
assert len(mocked_xenapi.method_calls) == 2
assert exc_info.value.kwargs['msg'] == error_msg
@pytest.mark.parametrize('power_state_desired, power_state_current',
testcase_set_vm_power_state_no_transitions['params'],
ids=testcase_set_vm_power_state_no_transitions['ids'])
def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current):
"""Tests regular invocation without power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
}
mocked_xenapi.configure_mock(**mocked_returns)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired)
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert result[0] is False
assert result[1] == power_state_current.lower()
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'],
ids=testcase_set_vm_power_state_transitions['ids'])
def test_set_vm_power_state_transition(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
"""Tests regular invocation with power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
}
mocked_xenapi.configure_mock(**mocked_returns)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=0)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_called_once()
# Beside VM.get_power_state() only activated_xenapi_method should have
# been called additionally.
assert len(mocked_xenapi.method_calls) == 2
assert result[0] is True
assert result[1] == power_state_resulting
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions_async['params'],
ids=testcase_set_vm_power_state_transitions_async['ids'])
def test_set_vm_power_state_transition_async(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
"""
Tests regular invocation with async power state transition
(shutdownguest and rebootguest only).
"""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
"%s.return_value" % activated_xenapi_method: fake_xenapi_ref('task'),
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible.module_utils.xenserver.wait_for_task', return_value="")
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=1)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_called_once()
# Beside VM.get_power_state() only activated_xenapi_method should have
# been called additionally.
assert len(mocked_xenapi.method_calls) == 2
assert result[0] is True
assert result[1] == power_state_resulting
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'],
ids=testcase_set_vm_power_state_transitions['ids'])
def test_set_vm_power_state_transition_check_mode(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
"""Tests regular invocation with power state transition in check mode."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
}
mocked_xenapi.configure_mock(**mocked_returns)
fake_ansible_module.check_mode = True
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=0)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_not_called()
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert result[0] is True
assert result[1] == power_state_resulting

@ -0,0 +1,220 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from .common import fake_xenapi_ref, testcase_bad_xenapi_refs
testcase_wait_for_vm_ip_address_bad_power_states = {
"params": [
'Halted',
'Paused',
'Suspended',
'Other',
],
"ids": [
'state-halted',
'state-paused',
'state-suspended',
'state-other',
]
}
testcase_wait_for_vm_ip_address_bad_guest_metrics = {
"params": [
('OpaqueRef:NULL', {"networks": {}}),
(fake_xenapi_ref('VM_guest_metrics'), {"networks": {}}),
],
"ids": [
'vm_guest_metrics_ref-null, no-ip',
'vm_guest_metrics_ref-ok, no-ip',
],
}
testcase_wait_for_task_all_statuses = {
"params": [
('Success', ''),
('Failure', 'failure'),
('Cancelling', 'cancelling'),
('Cancelled', 'cancelled'),
('Other', 'other'),
],
"ids": [
'task-success',
'task-failure',
'task-cancelling',
'task-cancelled',
'task-other',
]
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids'])
def test_wait_for_vm_ip_address_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, vm_ref)
assert exc_info.value.kwargs['msg'] == "Cannot wait for VM IP address. Invalid VM reference supplied!"
def test_wait_for_vm_ip_address_xenapi_failure(mock_xenapi_failure, xenserver, fake_ansible_module):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: %s" % mock_xenapi_failure[1]
@pytest.mark.parametrize('bad_power_state',
testcase_wait_for_vm_ip_address_bad_power_states['params'],
ids=testcase_wait_for_vm_ip_address_bad_power_states['ids'])
def test_wait_for_vm_ip_address_bad_power_state(mocker, fake_ansible_module, XenAPI, xenserver, bad_power_state):
"""Tests failure on bad power state."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": bad_power_state,
}
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
assert exc_info.value.kwargs['msg'] == ("Cannot wait for VM IP address when VM is in state '%s'." %
xenserver.xapi_to_module_vm_power_state(bad_power_state.lower()))
@pytest.mark.parametrize('bad_guest_metrics_ref, bad_guest_metrics',
testcase_wait_for_vm_ip_address_bad_guest_metrics['params'],
ids=testcase_wait_for_vm_ip_address_bad_guest_metrics['ids'])
def test_wait_for_vm_ip_address_timeout(mocker, fake_ansible_module, XenAPI, xenserver, bad_guest_metrics_ref, bad_guest_metrics):
"""Tests timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
"VM.get_guest_metrics.return_value": bad_guest_metrics_ref,
"VM_guest_metrics.get_record.return_value": bad_guest_metrics,
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'), timeout=1)
assert exc_info.value.kwargs['msg'] == "Timed out waiting for VM IP address!"
def test_wait_for_vm_ip_address(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests regular invocation."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
# This mock simulates regular VM IP acquirement lifecycle:
#
# 1) First, no guest metrics are available because VM is not yet fully
# booted and guest agent is not yet started.
# 2) Next, guest agent is started and guest metrics are available but
# IP address is still not acquired.
# 3) Lastly, IP address is acquired by VM on its primary VIF.
mocked_returns = {
"VM.get_power_state.return_value": "Running",
"VM.get_guest_metrics.side_effect": [
'OpaqueRef:NULL',
fake_xenapi_ref('VM_guest_metrics'),
fake_xenapi_ref('VM_guest_metrics'),
],
"VM_guest_metrics.get_record.side_effect": [
{
"networks": {},
},
{
"networks": {
"0/ip": "192.168.0.1",
"1/ip": "10.0.0.1",
},
},
],
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
fake_guest_metrics = xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
assert fake_guest_metrics == mocked_returns['VM_guest_metrics.get_record.side_effect'][1]
@pytest.mark.parametrize('task_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids'])
def test_wait_for_task_bad_task_ref(fake_ansible_module, xenserver, task_ref):
"""Tests failure on bad task_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_task(fake_ansible_module, task_ref)
assert exc_info.value.kwargs['msg'] == "Cannot wait for task. Invalid task reference supplied!"
def test_wait_for_task_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'))
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: %s" % mock_xenapi_failure[1]
def test_wait_for_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"task.get_status.return_value": "Pending",
"task.destroy.return_value": None,
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'), timeout=1)
mocked_xenapi.task.destroy.assert_called_once()
assert fake_result == "timeout"
@pytest.mark.parametrize('task_status, result',
testcase_wait_for_task_all_statuses['params'],
ids=testcase_wait_for_task_all_statuses['ids'])
def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_status, result):
"""Tests regular invocation."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
# Mock will first return Pending status and on second invocation it will
# return one of possible final statuses.
mocked_returns = {
"task.get_status.side_effect": [
'Pending',
task_status,
],
"task.destroy.return_value": None,
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'))
mocked_xenapi.task.destroy.assert_called_once()
assert fake_result == result

@ -0,0 +1,175 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
import atexit
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION
testcase_module_local_conn = {
"params": [
{
"hostname": "localhost",
"username": "someuser",
"password": "somepwd",
"validate_certs": True,
},
],
"ids": [
"local-conn",
],
}
testcase_module_remote_conn = {
"params": [
{
"hostname": "somehost",
"username": "someuser",
"password": "somepwd",
"validate_certs": True,
},
],
"ids": [
"remote-conn",
],
}
testcase_module_remote_conn_scheme = {
"params": [
{
"hostname": "http://somehost",
"username": "someuser",
"password": "somepwd",
"validate_certs": True,
},
{
"hostname": "https://somehost",
"username": "someuser",
"password": "somepwd",
"validate_certs": True,
},
],
"ids": [
"remote-conn-http",
"remote-conn-https",
],
}
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True)
def test_xapi_connect_local_session(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses XenAPI.xapi_local() function."""
mocker.patch('XenAPI.xapi_local')
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
XenAPI.xapi_local.assert_called_once()
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True)
def test_xapi_connect_local_login(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses empty username and password."""
mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
XenAPI.Session.login_with_password.assert_called_once_with('', '', ANSIBLE_VERSION, 'Ansible')
def test_xapi_connect_login(mocker, fake_ansible_module, XenAPI, xenserver):
"""
Tests that username and password are properly propagated to
XenAPI.Session.login_with_password() function.
"""
mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
username = fake_ansible_module.params['username']
password = fake_ansible_module.params['password']
XenAPI.Session.login_with_password.assert_called_once_with(username, password, ANSIBLE_VERSION, 'Ansible')
def test_xapi_connect_login_failure(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that login failure is properly handled."""
fake_error_msg = "Fake XAPI login error!"
mocked_login = mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
mocked_login.side_effect = XenAPI.Failure(fake_error_msg)
hostname = fake_ansible_module.params['hostname']
username = fake_ansible_module.params['username']
with pytest.raises(FailJsonException) as exc_info:
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
assert exc_info.value.kwargs['msg'] == "Unable to log on to XenServer at http://%s as %s: %s" % (hostname, username, fake_error_msg)
@pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn_scheme['params'], ids=testcase_module_remote_conn_scheme['ids'], indirect=True)
def test_xapi_connect_remote_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that explicit scheme in hostname param is preserved."""
mocker.patch('XenAPI.Session')
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
XenAPI.Session.assert_called_once_with(hostname, ignore_ssl=ignore_ssl)
@pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn['params'], ids=testcase_module_remote_conn['ids'], indirect=True)
def test_xapi_connect_remote_no_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that proper scheme is prepended to hostname without scheme."""
mocker.patch('XenAPI.Session')
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
XenAPI.Session.assert_called_once_with("http://%s" % hostname, ignore_ssl=ignore_ssl)
def test_xapi_connect_support_ignore_ssl(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests proper handling of ignore_ssl support."""
mocked_session = mocker.patch('XenAPI.Session')
mocked_session.side_effect = TypeError()
with pytest.raises(TypeError) as exc_info:
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
XenAPI.Session.assert_called_with("http://%s" % hostname)
def test_xapi_connect_no_disconnect_atexit(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests skipping registration of atexit disconnect handler."""
mocker.patch('atexit.register')
xapi_session = xenserver.XAPI.connect(fake_ansible_module, disconnect_atexit=False)
atexit.register.assert_not_called()
def test_xapi_connect_singleton(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests if XAPI.connect() returns singleton."""
mocker.patch('XenAPI.Session')
xapi_session1 = xenserver.XAPI.connect(fake_ansible_module)
xapi_session2 = xenserver.XAPI.connect(fake_ansible_module)
XenAPI.Session.assert_called_once()
assert xapi_session1 == xapi_session2

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, 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 pytest
from .FakeAnsibleModule import FakeAnsibleModule, ExitJsonException, FailJsonException
from .common import fake_xenapi_ref
def test_xenserverobject_xenapi_lib_detection(mocker, fake_ansible_module, xenserver):
"""Tests XenAPI lib detection code."""
mocker.patch('ansible.module_utils.xenserver.HAS_XENAPI', new=False)
with pytest.raises(FailJsonException) as exc_info:
xenserver.XenServerObject(fake_ansible_module)
assert exc_info.value.kwargs['msg'] == "XenAPI.py required for this module! Please download XenServer SDK and copy XenAPI.py to your site-packages."
def test_xenserverobject_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.XenServerObject(fake_ansible_module)
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: %s" % mock_xenapi_failure[1]
def test_xenserverobject(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests successful creation of XenServerObject."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_returns = {
"pool.get_all.return_value": [fake_xenapi_ref('pool')],
"pool.get_default_SR.return_value": fake_xenapi_ref('SR'),
"session.get_this_host.return_value": fake_xenapi_ref('host'),
"host.get_software_version.return_value": {"product_version_text_short": "7.2"},
}
mocked_xenapi.configure_mock(**mocked_returns)
xso = xenserver.XenServerObject(fake_ansible_module)
assert xso.pool_ref == fake_xenapi_ref('pool')
assert xso.xenserver_version == ['7', '2']
Loading…
Cancel
Save