diff --git a/lib/ansible/module_utils/ovirt.py b/lib/ansible/module_utils/ovirt.py
index d4944da800..f4bb16702e 100644
--- a/lib/ansible/module_utils/ovirt.py
+++ b/lib/ansible/module_utils/ovirt.py
@@ -18,6 +18,7 @@
# along with Ansible. If not, see .
#
+import collections
import inspect
import os
import time
@@ -55,47 +56,56 @@ def get_dict_of_struct(struct, connection=None, fetch_nested=False, attributes=N
"""
Convert SDK Struct type into dictionary.
"""
+ res = {}
+
def remove_underscore(val):
if val.startswith('_'):
val = val[1:]
remove_underscore(val)
return val
- res = {}
+ def convert_value(value):
+ nested = False
+
+ if isinstance(value, sdk.Struct):
+ return get_dict_of_struct(value)
+ elif isinstance(value, Enum) or isinstance(value, datetime):
+ return str(value)
+ elif isinstance(value, list) or isinstance(value, sdk.List):
+ if isinstance(value, sdk.List) and fetch_nested and value.href:
+ try:
+ value = connection.follow_link(value)
+ nested = True
+ except sdk.Error:
+ value = []
+
+ ret = []
+ for i in value:
+ if isinstance(i, sdk.Struct):
+ if not nested:
+ ret.append(get_dict_of_struct(i))
+ else:
+ nested_obj = dict(
+ (attr, convert_value(getattr(i, attr)))
+ for attr in attributes if getattr(i, attr, None)
+ )
+ nested_obj['id'] = getattr(i, 'id', None),
+ ret.append(nested_obj)
+ elif isinstance(i, Enum):
+ ret.append(str(i))
+ else:
+ ret.append(i)
+ return ret
+ else:
+ return value
+
if struct is not None:
for key, value in struct.__dict__.items():
- nested = False
- key = remove_underscore(key)
if value is None:
continue
- elif isinstance(value, sdk.Struct):
- res[key] = get_dict_of_struct(value)
- elif isinstance(value, Enum) or isinstance(value, datetime):
- res[key] = str(value)
- elif isinstance(value, list) or isinstance(value, sdk.List):
- if isinstance(value, sdk.List) and fetch_nested and value.href:
- value = connection.follow_link(value)
- nested = True
-
- res[key] = []
- for i in value:
- if isinstance(i, sdk.Struct):
- if not nested:
- res[key].append(get_dict_of_struct(i))
- else:
- nested_obj = dict(
- (attr, getattr(i, attr))
- for attr in attributes if getattr(i, attr, None)
- )
- nested_obj['id'] = getattr(i, 'id', None),
- res[key].append(nested_obj)
- elif isinstance(i, Enum):
- res[key].append(str(i))
- else:
- res[key].append(i)
- else:
- res[key] = value
+ key = remove_underscore(key)
+ res[key] = convert_value(value)
return res
@@ -283,9 +293,6 @@ def wait(
if wait:
start = time.time()
while time.time() < start + timeout:
- # Sleep for `poll_interval` seconds if none of the conditions apply:
- time.sleep(float(poll_interval))
-
# Exit if the condition of entity is valid:
entity = get_entity(service)
if condition(entity):
@@ -293,6 +300,11 @@ def wait(
elif fail_condition(entity):
raise Exception("Error while waiting on result state of the entity.")
+ # Sleep for `poll_interval` seconds if none of the conditions apply:
+ time.sleep(float(poll_interval))
+
+ raise Exception("Timeout exceed while waiting on result state of the entity.")
+
def __get_auth_dict():
OVIRT_URL = os.environ.get('OVIRT_URL')
@@ -331,7 +343,7 @@ def ovirt_facts_full_argument_spec(**kwargs):
spec = dict(
auth=__get_auth_dict(),
fetch_nested=dict(default=False, type='bool'),
- nested_attributes=dict(type='list'),
+ nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
@@ -350,7 +362,7 @@ def ovirt_full_argument_spec(**kwargs):
wait=dict(default=True, type='bool'),
poll_interval=dict(default=3, type='int'),
fetch_nested=dict(default=False, type='bool'),
- nested_attributes=dict(type='list'),
+ nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
@@ -401,6 +413,7 @@ class BaseModule(object):
self._module = module
self._service = service
self._changed = changed
+ self._diff = {'after': dict(), 'before': dict()}
@property
def changed(self):
@@ -464,6 +477,15 @@ class BaseModule(object):
"""
pass
+ def diff_update(self, after, update):
+ for k, v in update.items():
+ if isinstance(v, collections.Mapping):
+ after[k] = self.diff_update(after.get(k, dict()), v)
+ else:
+ after[k] = update[k]
+ return after
+
+
def create(self, entity=None, result_state=None, fail_condition=lambda e: False, search_params=None, **kwargs):
"""
Method which is called when state of the entity is 'present'. If user
@@ -492,9 +514,25 @@ class BaseModule(object):
# Entity exists, so update it:
entity_service = self._service.service(entity.id)
if not self.update_check(entity):
+ new_entity = self.build_entity()
if not self._module.check_mode:
- entity_service.update(self.build_entity())
+ updated_entity = entity_service.update(new_entity)
self.post_update(entity)
+
+ # Update diffs only if user specified --diff paramter,
+ # so we don't useless overload API:
+ if self._module._diff:
+ before = get_dict_of_struct(
+ entity,
+ self._connection,
+ fetch_nested=True,
+ attributes=['name'],
+ )
+ after = before.copy()
+ self.diff_update(after, get_dict_of_struct(new_entity))
+ self._diff['before'] = before
+ self._diff['after'] = after
+
self.changed = True
else:
# Entity don't exists, so create it:
@@ -530,6 +568,7 @@ class BaseModule(object):
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
+ 'diff': self._diff,
}
def pre_remove(self, entity):
@@ -540,6 +579,12 @@ class BaseModule(object):
"""
pass
+ def entity_name(self, entity):
+ return "{e_type} '{e_name}'".format(
+ e_type=type(entity).__name__.lower(),
+ e_name=getattr(entity, 'name', None),
+ )
+
def remove(self, entity=None, search_params=None, **kwargs):
"""
Method which is called when state of the entity is 'absent'. If user
@@ -568,7 +613,6 @@ class BaseModule(object):
entity_service = self._service.service(entity.id)
if not self._module.check_mode:
entity_service.remove(**kwargs)
-
wait(
service=entity_service,
condition=lambda entity: not entity,
@@ -662,6 +706,7 @@ class BaseModule(object):
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
+ 'diff': self._diff,
}
def search_entity(self, search_params=None):
diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_auth.py b/lib/ansible/modules/cloud/ovirt/ovirt_auth.py
index f0597c7e14..7fed7a2adf 100644
--- a/lib/ansible/modules/cloud/ovirt/ovirt_auth.py
+++ b/lib/ansible/modules/cloud/ovirt/ovirt_auth.py
@@ -190,6 +190,7 @@ def main():
('state', 'absent', ['ovirt_auth']),
('state', 'present', ['username', 'password', 'url']),
],
+ supports_check_mode=True,
)
check_sdk(module)
diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py b/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py
index 06bfa1824b..e2e7c29bb7 100644
--- a/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py
+++ b/lib/ansible/modules/cloud/ovirt/ovirt_hosts.py
@@ -19,6 +19,7 @@
# along with Ansible. If not, see .
#
+import time
import traceback
try:
@@ -152,6 +153,12 @@ EXAMPLES = '''
state: upgraded
name: myhost
+# Reinstall host using public key
+- ovirt_hosts:
+ state: reinstalled
+ name: myhost
+ public_key: true
+
# Remove host
- ovirt_hosts:
state: absent
@@ -184,7 +191,7 @@ class HostsModule(BaseModule):
address=self._module.params['address'],
root_password=self._module.params['password'],
ssh=otypes.Ssh(
- authentication_method='publickey',
+ authentication_method=otypes.SshAuthenticationMethod.PUBLICKEY,
) if self._module.params['public_key'] else None,
kdump_status=otypes.KdumpStatus(
self._module.params['kdump_integration']
@@ -228,6 +235,15 @@ class HostsModule(BaseModule):
self._service.host_service(entity.id).activate()
self.changed = True
+ def post_reinstall(self, host):
+ wait(
+ service=self._service.service(host.id),
+ condition=lambda h: h.status != hoststate.MAINTENANCE,
+ fail_condition=failed_state,
+ wait=self._module.params['wait'],
+ timeout=self._module.params['timeout'],
+ )
+
def failed_state(host):
return host.status in [
@@ -315,23 +331,23 @@ def main():
state = module.params['state']
control_state(hosts_module)
if state == 'present':
- ret = hosts_module.create()
- ret['changed'] = hosts_module.action(
+ hosts_module.create()
+ ret = hosts_module.action(
action='activate',
action_condition=lambda h: h.status == hoststate.MAINTENANCE,
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
- )['changed'] or ret['changed']
+ )
elif state == 'absent':
ret = hosts_module.remove()
elif state == 'maintenance':
- ret = hosts_module.action(
+ hosts_module.action(
action='deactivate',
action_condition=lambda h: h.status != hoststate.MAINTENANCE,
wait_condition=lambda h: h.status == hoststate.MAINTENANCE,
fail_condition=failed_state,
)
- ret['changed'] = hosts_module.create()['changed'] or ret['changed']
+ ret = hosts_module.create()
elif state == 'upgraded':
ret = hosts_module.action(
action='upgrade',
@@ -348,19 +364,19 @@ def main():
fence_type='start',
)
elif state == 'stopped':
- ret = hosts_module.action(
+ hosts_module.action(
action='deactivate',
action_condition=lambda h: h.status not in [hoststate.MAINTENANCE, hoststate.DOWN],
wait_condition=lambda h: h.status in [hoststate.MAINTENANCE, hoststate.DOWN],
fail_condition=failed_state,
)
- ret['changed'] = hosts_module.action(
+ ret = hosts_module.action(
action='fence',
action_condition=lambda h: h.status != hoststate.DOWN,
- wait_condition=lambda h: h.status == hoststate.DOWN,
+ wait_condition=lambda h: h.status == hoststate.DOWN if module.params['wait'] else True,
fail_condition=failed_state,
fence_type='stop',
- )['changed'] or ret['changed']
+ )
elif state == 'restarted':
ret = hosts_module.action(
action='fence',
@@ -370,17 +386,18 @@ def main():
)
elif state == 'reinstalled':
# Deactivate host if not in maintanence:
- deactivate_changed = hosts_module.action(
+ hosts_module.action(
action='deactivate',
action_condition=lambda h: h.status not in [hoststate.MAINTENANCE, hoststate.DOWN],
wait_condition=lambda h: h.status in [hoststate.MAINTENANCE, hoststate.DOWN],
fail_condition=failed_state,
- )['changed']
+ )
# Reinstall host:
- install_changed = hosts_module.action(
+ hosts_module.action(
action='install',
action_condition=lambda h: h.status == hoststate.MAINTENANCE,
+ post_action=hosts_module.post_reinstall,
wait_condition=lambda h: h.status == hoststate.MAINTENANCE,
fail_condition=failed_state,
host=otypes.Host(
@@ -388,9 +405,9 @@ def main():
) if module.params['override_iptables'] else None,
root_password=module.params['password'],
ssh=otypes.Ssh(
- authentication_method='publickey',
+ authentication_method=otypes.SshAuthenticationMethod.PUBLICKEY,
) if module.params['public_key'] else None,
- )['changed']
+ )
# Activate host after reinstall:
ret = hosts_module.action(
@@ -399,8 +416,6 @@ def main():
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
)
- ret['changed'] = install_changed or deactivate_changed or ret['changed']
-
module.exit_json(**ret)
except Exception as e:
diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
index 6e5e16f4a8..ef6880d4af 100644
--- a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
+++ b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
@@ -34,6 +34,7 @@ from ansible.module_utils.ovirt import (
convert_to_bytes,
create_connection,
equal,
+ get_entity,
get_link_name,
ovirt_full_argument_spec,
search_by_name,
@@ -627,7 +628,7 @@ class VmsModule(BaseModule):
# Attach disk to VM:
disk_attachments_service = self._service.service(entity.id).disk_attachments_service()
- if disk_attachments_service.attachment_service(disk_id).get() is None:
+ if get_entity(disk_attachments_service.attachment_service(disk_id)) is None:
if not self._module.check_mode:
disk_attachments_service.add(
otypes.DiskAttachment(
diff --git a/lib/ansible/utils/module_docs_fragments/ovirt.py b/lib/ansible/utils/module_docs_fragments/ovirt.py
index d469ef83c1..932ddb4ad1 100644
--- a/lib/ansible/utils/module_docs_fragments/ovirt.py
+++ b/lib/ansible/utils/module_docs_fragments/ovirt.py
@@ -69,5 +69,5 @@ requirements:
notes:
- "In order to use this module you have to install oVirt Python SDK.
To ensure it's installed with correct version you can create the following task:
- pip: name=ovirt-engine-sdk-python version=4.0.0"
+ I(pip: name=ovirt-engine-sdk-python version=4.0.0)"
'''