#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (c) 2021, Jyrki Gadinger # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later # Make coding more python3-ish from __future__ import (absolute_import, division, print_function) __metaclass__ = type DOCUMENTATION = r""" module: one_template short_description: Manages OpenNebula templates version_added: 2.4.0 requirements: - pyone description: - Manages OpenNebula templates. attributes: check_mode: support: partial details: - Note that check mode always returns C(changed=true) for existing templates, even if the template would not actually change. diff_mode: support: none options: id: description: - A O(id) of the template you would like to manage. If not set then a new template will be created with the given O(name). type: int name: description: - A O(name) of the template you would like to manage. If a template with the given name does not exist it will be created, otherwise it will be managed by this module. type: str template: description: - A string containing the template contents. type: str state: description: - V(present) - state that is used to manage the template. - V(absent) - delete the template. choices: ["present", "absent"] default: present type: str filter: description: - V(user_primary_group) - Resources belonging to the user's primary group. - V(user) - Resources belonging to the user. - V(all) - All resources. - V(user_groups) - Resources belonging to the user and any of his groups. choices: [user_primary_group, user, all, user_groups] default: user type: str version_added: 10.3.0 extends_documentation_fragment: - community.general.opennebula - community.general.attributes author: - "Jyrki Gadinger (@nilsding)" """ EXAMPLES = r""" - name: Fetch the TEMPLATE by id community.general.one_template: id: 6459 register: result - name: Print the TEMPLATE properties ansible.builtin.debug: var: result - name: Fetch the TEMPLATE by name community.general.one_template: name: tf-prd-users-workerredis-p6379a register: result - name: Create a new or update an existing TEMPLATE community.general.one_template: name: generic-opensuse template: | CONTEXT = [ HOSTNAME = "generic-opensuse" ] CPU = "1" CUSTOM_ATTRIBUTE = "" DISK = [ CACHE = "writeback", DEV_PREFIX = "sd", DISCARD = "unmap", IMAGE = "opensuse-leap-15.2", IMAGE_UNAME = "oneadmin", IO = "threads", SIZE = "" ] MEMORY = "2048" NIC = [ MODEL = "virtio", NETWORK = "testnet", NETWORK_UNAME = "oneadmin" ] OS = [ ARCH = "x86_64", BOOT = "disk0" ] SCHED_REQUIREMENTS = "CLUSTER_ID=\\"100\\"" VCPU = "2" - name: Delete the TEMPLATE by id community.general.one_template: id: 6459 state: absent """ RETURN = r""" id: description: Template ID. type: int returned: when O(state=present) sample: 153 name: description: Template name. type: str returned: when O(state=present) sample: app1 template: description: The parsed template. type: dict returned: when O(state=present) group_id: description: Template's group ID. type: int returned: when O(state=present) sample: 1 group_name: description: Template's group name. type: str returned: when O(state=present) sample: one-users owner_id: description: Template's owner ID. type: int returned: when O(state=present) sample: 143 owner_name: description: Template's owner name. type: str returned: when O(state=present) sample: ansible-test """ from ansible_collections.community.general.plugins.module_utils.opennebula import OpenNebulaModule class TemplateModule(OpenNebulaModule): def __init__(self): argument_spec = dict( id=dict(type='int', required=False), name=dict(type='str', required=False), state=dict(type='str', choices=['present', 'absent'], default='present'), template=dict(type='str', required=False), filter=dict(type='str', required=False, choices=['user_primary_group', 'user', 'all', 'user_groups'], default='user'), ) mutually_exclusive = [ ['id', 'name'] ] required_one_of = [('id', 'name')] required_if = [ ['state', 'present', ['template']] ] OpenNebulaModule.__init__(self, argument_spec, supports_check_mode=True, mutually_exclusive=mutually_exclusive, required_one_of=required_one_of, required_if=required_if) def run(self, one, module, result): params = module.params id = params.get('id') name = params.get('name') desired_state = params.get('state') template_data = params.get('template') filter = params.get('filter') self.result = {} template = self.get_template_instance(id, name, filter) needs_creation = False if not template and desired_state != 'absent': if id: module.fail_json(msg="There is no template with id=" + str(id)) else: needs_creation = True if desired_state == 'absent': self.result = self.delete_template(template) else: if needs_creation: self.result = self.create_template(name, template_data, filter) else: self.result = self.update_template(template, template_data, filter) self.exit() def get_template(self, predicate, filter): # filter was included, for discussions see: # Issue: https://github.com/ansible-collections/community.general/issues/9278 # PR: https://github.com/ansible-collections/community.general/pull/9547 # the other two parameters are used for pagination, -1 for both essentially means "return all" filter_values = {'user_primary_group': -4, 'user': -3, 'all': -2, 'user_groups': -1} pool = self.one.templatepool.info(filter_values[filter], -1, -1) for template in pool.VMTEMPLATE: if predicate(template): return template return None def get_template_by_id(self, template_id, filter): return self.get_template(lambda template: (template.ID == template_id), filter) def get_template_by_name(self, name, filter): return self.get_template(lambda template: (template.NAME == name), filter) def get_template_instance(self, requested_id, requested_name, filter): if requested_id: return self.get_template_by_id(requested_id, filter) else: return self.get_template_by_name(requested_name, filter) def get_template_info(self, template): info = { 'id': template.ID, 'name': template.NAME, 'template': template.TEMPLATE, 'user_name': template.UNAME, 'user_id': template.UID, 'group_name': template.GNAME, 'group_id': template.GID, } return info def create_template(self, name, template_data, filter): if not self.module.check_mode: self.one.template.allocate("NAME = \"" + name + "\"\n" + template_data) result = self.get_template_info(self.get_template_by_name(name, filter)) result['changed'] = True return result def update_template(self, template, template_data, filter): if not self.module.check_mode: # 0 = replace the whole template self.one.template.update(template.ID, template_data, 0) result = self.get_template_info(self.get_template_by_id(template.ID, filter)) if self.module.check_mode: # Unfortunately it is not easy to detect if the template would have changed, therefore always report a change here. result['changed'] = True else: # if the previous parsed template data is not equal to the updated one, this has changed result['changed'] = template.TEMPLATE != result['template'] return result def delete_template(self, template): if not template: return {'changed': False} if not self.module.check_mode: self.one.template.delete(template.ID) return {'changed': True} def main(): TemplateModule().run_module() if __name__ == '__main__': main()