From 95ef9fd9f9dea1f11c1077c5fddd9e7a630e1dc1 Mon Sep 17 00:00:00 2001 From: Ondra Machacek Date: Tue, 13 Dec 2016 15:14:09 +0100 Subject: [PATCH] cloud: ovirt: Add ovirt_tags and ovirt_tags_facts modules (#19295) --- lib/ansible/modules/cloud/ovirt/ovirt_tags.py | 213 ++++++++++++++++++ .../modules/cloud/ovirt/ovirt_tags_facts.py | 154 +++++++++++++ 2 files changed, 367 insertions(+) create mode 100644 lib/ansible/modules/cloud/ovirt/ovirt_tags.py create mode 100644 lib/ansible/modules/cloud/ovirt/ovirt_tags_facts.py diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_tags.py b/lib/ansible/modules/cloud/ovirt/ovirt_tags.py new file mode 100644 index 00000000000..29f4508f9ac --- /dev/null +++ b/lib/ansible/modules/cloud/ovirt/ovirt_tags.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016 Red Hat, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +import traceback + +try: + import ovirtsdk4.types as otypes +except ImportError: + pass + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ovirt import ( + BaseModule, + check_sdk, + create_connection, + equal, + ovirt_full_argument_spec, + search_by_name, +) + + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'version': '1.0'} + +DOCUMENTATION = ''' +--- +module: ovirt_tags +short_description: Module to manage tags in oVirt +version_added: "2.3" +author: "Ondra Machacek (@machacekondra)" +description: + - "This module manage tags in oVirt. It can also manage assignments + of those tags to entities." +options: + name: + description: + - "Name of the the tag to manage." + required: true + state: + description: + - "Should the tag be present or absent." + choices: ['present', 'absent'] + default: present + description: + description: + - "Description of the the tag to manage." + parent: + description: + - "Name of the parent tag." + vms: + description: + - "List of the VMs names, which should have assigned this tag." +extends_documentation_fragment: ovirt +''' + +EXAMPLES = ''' +# Examples don't contain auth parameter for simplicity, +# look at ovirt_auth module to see how to reuse authentication: + +# Create(if not exists) and assign tag to vms vm1 and vm2: +- ovirt_tags: + name: mytag + vms: + - vm1 + - vm2 + +# To detach all VMs from tag: +- ovirt_tags: + name: mytag + vms: [] + +# Remove tag +- ovirt_tags: + state: absent + name: mytag +''' + +RETURN = ''' +id: + description: ID of the tag which is managed + returned: On success if tag is found. + type: str + sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c +tag: + description: "Dictionary of all the tag attributes. Tag attributes can be found on your oVirt instance + at following url: https://ovirt.example.com/ovirt-engine/api/model#types/tag." + returned: On success if tag is found. +''' + + +class TagsModule(BaseModule): + + def build_entity(self): + return otypes.Tag( + name=self._module.params['name'], + description=self._module.params['description'], + parent=otypes.Tag( + name=self._module.params['parent'], + ) if self._module.params['parent'] else None, + ) + + def post_create(self, entity): + self.update_check(entity) + + def _update_tag_assignments(self, entity, name): + if self._module.params[name] is None: + return + + entities_service = getattr(self._connection.system_service(), '%s_service' % name)() + current_vms = [ + vm.name + for vm in entities_service.list(search='tag=%s' % self._module.params['name']) + ] + # Assign tags: + for entity_name in self._module.params[name]: + entity = search_by_name(entities_service, entity_name) + tags_service = entities_service.service(entity.id).tags_service() + current_tags = [tag.name for tag in tags_service.list()] + # Assign the tag: + if self._module.params['name'] not in current_tags: + if not self._module.check_mode: + tags_service.add( + tag=otypes.Tag( + name=self._module.params['name'], + ), + ) + self.changed = True + + # Unassign tags: + for entity_name in [e for e in current_vms if e not in self._module.params[name]]: + if not self._module.check_mode: + entity = search_by_name(entities_service, entity_name) + tags_service = entities_service.service(entity.id).tags_service() + tag_id = [tag.id for tag in tags_service.list() if tag.name == self._module.params['name']][0] + tags_service.tag_service(tag_id).remove() + self.changed = True + + def _get_parent(self, entity): + parent = None + if entity.parent: + parent = self._connection.follow_link(entity.parent).name + return parent + + def update_check(self, entity): + self._update_tag_assignments(entity, 'vms') + self._update_tag_assignments(entity, 'hosts') + return ( + equal(self._module.params.get('description'), entity.description) and + equal(self._module.params.get('parent'), self._get_parent(entity)) + ) + + +def main(): + argument_spec = ovirt_full_argument_spec( + state=dict( + choices=['present', 'absent'], + default='present', + ), + name=dict(default=None, required=True), + description=dict(default=None), + parent=dict(default=None), + vms=dict(default=None, type='list'), + hosts=dict(default=None, type='list'), + ) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + check_sdk(module) + + try: + connection = create_connection(module.params.pop('auth')) + tags_service = connection.system_service().tags_service() + tags_module = TagsModule( + connection=connection, + module=module, + service=tags_service, + ) + + state = module.params['state'] + if state == 'present': + ret = tags_module.create() + elif state == 'absent': + ret = tags_module.remove() + + module.exit_json(**ret) + except Exception as e: + module.fail_json(msg=str(e), exception=traceback.format_exc()) + finally: + connection.close(logout=False) + + +if __name__ == "__main__": + main() diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_tags_facts.py b/lib/ansible/modules/cloud/ovirt/ovirt_tags_facts.py new file mode 100644 index 00000000000..78e217906e7 --- /dev/null +++ b/lib/ansible/modules/cloud/ovirt/ovirt_tags_facts.py @@ -0,0 +1,154 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016 Red Hat, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +import fnmatch +import traceback + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ovirt import ( + check_sdk, + create_connection, + get_dict_of_struct, + ovirt_facts_full_argument_spec, + search_by_name, +) + + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'version': '1.0'} + +DOCUMENTATION = ''' +--- +module: ovirt_tags_facts +short_description: Retrieve facts about one or more oVirt tags +author: "Ondra Machacek (@machacekondra)" +version_added: "2.3" +description: + - "Retrieve facts about one or more oVirt tags." +notes: + - "This module creates a new top-level C(ovirt_tags) fact, which + contains a list of tags" +options: + name: + description: + - "Name of the tag which should be listed." + vm: + description: + - "Name of the VM, which tags should be listed." + host: + description: + - "Name of the host, which tags should be listed." +extends_documentation_fragment: ovirt +''' + +EXAMPLES = ''' +# Examples don't contain auth parameter for simplicity, +# look at ovirt_auth module to see how to reuse authentication: + +# Gather facts about all tags, which names start with C(tag): +- ovirt_tags_facts: + name: tag* +- debug: + var: tags + +# Gather facts about all tags, which are assigned to VM C(postgres): +- ovirt_tags_facts: + vm: postgres +- debug: + var: tags + +# Gather facts about all tags, which are assigned to host C(west): +- ovirt_tags_facts: + host: west +- debug: + var: tags +''' + +RETURN = ''' +ovirt_tags: + description: "List of dictionaries describing the tags. Tags attribues are mapped to dictionary keys, + all tags attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/tag." + returned: On success. + type: list +''' + + +def main(): + argument_spec = ovirt_facts_full_argument_spec( + name=dict(default=None), + host=dict(default=None), + vm=dict(default=None), + ) + module = AnsibleModule(argument_spec) + check_sdk(module) + + try: + connection = create_connection(module.params.pop('auth')) + tags_service = connection.system_service().tags_service() + tags = [] + all_tags = tags_service.list() + if module.params['name']: + tags.extend([ + t for t in all_tags + if fnmatch.fnmatch(t.name, module.params['name']) + ]) + if module.params['host']: + hosts_service = connection.system_service().hosts_service() + host = search_by_name(hosts_service, module.params['host']) + if host is None: + raise Exception("Host '%s' was not found." % module.params['host']) + tags.extend([ + tag for tag in hosts_service.host_service(host.id).tags_service().list() + ]) + if module.params['vm']: + vms_service = connection.system_service().vms_service() + vm = search_by_name(vms_service, module.params['vm']) + if vm is None: + raise Exception("Vm '%s' was not found." % module.params['vm']) + tags.extend([ + tag for tag in vms_service.vm_service(vm.id).tags_service().list() + ]) + + if not (module.params['vm'] or module.params['host'] or module.params['name']): + tags = all_tags + + module.exit_json( + changed=False, + ansible_facts=dict( + ovirt_tags=[ + get_dict_of_struct( + struct=t, + connection=connection, + fetch_nested=module.params['fetch_nested'], + attributes=module.params['nested_attributes'], + ) for t in tags + ], + ), + ) + except Exception as e: + module.fail_json(msg=str(e), exception=traceback.format_exc()) + finally: + connection.close(logout=False) + + +if __name__ == '__main__': + main()