ovirt: Add support to diff (#20698)

* cloud: ovirt: Add diff support to

* cloud: ovirt: Add ability to print nested list of objects

* cloud: ovirt: Fix waiting while reinstalling host

* cloud: ovirt: fix ovirt_vms 404 error

* cloud: ovirt: add check_mode support to ovirt_auth module
This commit is contained in:
Ondra Machacek 2017-02-02 19:50:52 +01:00 committed by Ryan Brown
commit ee7f1cde0e
5 changed files with 118 additions and 56 deletions

View file

@ -18,6 +18,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
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):