From f9fcd3501810028537d8a53f794c004e58f086bd Mon Sep 17 00:00:00 2001 From: Freerk-Ole Zakfeld Date: Mon, 13 Jan 2025 16:35:18 +0100 Subject: [PATCH] Add Traits Module Change-Id: I7db759f716c1154cb0dd30e240af3a0420efab8f Signed-off-by: Freerk-Ole Zakfeld --- ci/roles/trait/defaults/main.yml | 1 + ci/roles/trait/tasks/main.yml | 23 +++++++ ci/run-collection.yml | 1 + plugins/modules/trait.py | 110 +++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 ci/roles/trait/defaults/main.yml create mode 100644 ci/roles/trait/tasks/main.yml create mode 100644 plugins/modules/trait.py diff --git a/ci/roles/trait/defaults/main.yml b/ci/roles/trait/defaults/main.yml new file mode 100644 index 00000000..c35f4579 --- /dev/null +++ b/ci/roles/trait/defaults/main.yml @@ -0,0 +1 @@ +trait_name: CUSTOM_ANSIBLE_TRAIT diff --git a/ci/roles/trait/tasks/main.yml b/ci/roles/trait/tasks/main.yml new file mode 100644 index 00000000..550c681d --- /dev/null +++ b/ci/roles/trait/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- openstack.cloud.trait: + cloud: "{{ cloud }}" + state: present + id: "{{ trait_name }}" + delegate_to: localhost + register: item + +- assert: + that: + - "'name' in item.trait" + - "item.trait.id == trait_name" + +- openstack.cloud.trait: + cloud: "{{ cloud }}" + state: absent + id: "{{ trait_name }}" + delegate_to: localhost + register: item + +- assert: + that: + - "'trait' not in item" diff --git a/ci/run-collection.yml b/ci/run-collection.yml index 6bafa6f2..dd7ddd99 100644 --- a/ci/run-collection.yml +++ b/ci/run-collection.yml @@ -36,6 +36,7 @@ - { role: object, tags: object } - { role: object_container, tags: object_container } - { role: port, tags: port } + - { role: trait, tags: trait } - { role: trunk, tags: trunk } - { role: project, tags: project } - { role: quota, tags: quota } diff --git a/plugins/modules/trait.py b/plugins/modules/trait.py new file mode 100644 index 00000000..f64eab6a --- /dev/null +++ b/plugins/modules/trait.py @@ -0,0 +1,110 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2025, ScaleUp Technologies GmbH & Co. KG +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = ''' +--- +module: trait +short_description: Add/Delete a trait from OpenStack +author: OpenStack Ansible SIG +description: + - Add or Delete a trait from OpenStack +options: + id: + description: + - ID/Name of this trait + required: true + type: str + state: + description: + - Should the resource be present or absent. + choices: [present, absent] + default: present + type: str +extends_documentation_fragment: +- openstack.cloud.openstack +''' + +EXAMPLES = ''' +# Creates a trait with the ID CUSTOM_WINDOWS_SPLA +- openstack.cloud.trait: + cloud: openstack + state: present + id: CUSTOM_WINDOWS_SPLA +''' + +RETURN = ''' +trait: + description: Dictionary describing the trait. + returned: On success when I(state) is 'present' + type: dict + contains: + id: + description: ID of the trait. + returned: success + type: str +''' + +from ansible_collections.openstack.cloud.plugins.module_utils.openstack import ( + OpenStackModule) + + +class TraitModule(OpenStackModule): + + argument_spec = dict( + id=dict(required=True), + state=dict(default='present', + choices=['absent', 'present']), + ) + + module_kwargs = dict( + supports_check_mode=True, + ) + + def _system_state_change(self, trait): + state = self.params['state'] + if state == 'present' and not trait: + return True + if state == 'absent' and trait: + return True + return False + + def run(self): + + state = self.params['state'] + id = self.params['id'] + + try: + trait = self.conn.placement.get_trait(id) + except self.sdk.exceptions.NotFoundException: + trait = None + + if self.ansible.check_mode: + self.exit_json(changed=self._system_state_change(trait), trait=trait) + + changed = False + if state == 'present': + if not trait: + trait = self.conn.placement.create_trait(id) + changed = True + + self.exit_json( + changed=changed, trait=trait.to_dict(computed=False)) + + elif state == 'absent': + if trait: + self.conn.placement.delete_trait(id, ignore_missing=False) + self.exit_json(changed=True) + + self.exit_json(changed=False) + + +def main(): + module = TraitModule() + module() + + +if __name__ == '__main__': + main()