diff options
4 files changed, 205 insertions, 1 deletions
diff --git a/awx_collection/plugins/module_utils/controller_api.py b/awx_collection/plugins/module_utils/controller_api.py index 567a753c8f..50d10f8104 100644 --- a/awx_collection/plugins/module_utils/controller_api.py +++ b/awx_collection/plugins/module_utils/controller_api.py @@ -903,6 +903,8 @@ class ControllerAPIModule(ControllerModule): item_name = existing_item['identifier'] elif item_type == 'credential_input_source': item_name = existing_item['id'] + elif item_type == 'instance': + item_name = existing_item['hostname'] else: item_name = existing_item['name'] item_id = existing_item['id'] diff --git a/awx_collection/plugins/modules/instance.py b/awx_collection/plugins/modules/instance.py new file mode 100644 index 0000000000..a20b6c831c --- /dev/null +++ b/awx_collection/plugins/modules/instance.py @@ -0,0 +1,148 @@ +#!/usr/bin/python +# coding: utf-8 -*- + + +# (c) 2022 Red Hat, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: instance +author: "Rick Elrod (@relrod)" +version_added: "4.3.0" +short_description: create, update, or destroy Automation Platform Controller instances. +description: + - Create, update, or destroy Automation Platform Controller instances. See + U(https://www.ansible.com/tower) for an overview. +options: + hostname: + description: + - Hostname of this instance. + required: True + type: str + capacity_adjustment: + description: + - Capacity adjustment (0 <= capacity_adjustment <= 1) + required: False + type: float + enabled: + description: + - If true, the instance will be enabled and used. + required: False + type: bool + default: True + managed_by_policy: + description: + - Managed by policy + required: False + default: True + type: bool + node_type: + description: + - Role that this node plays in the mesh. + choices: + - control + - execution + - hybrid + - hop + required: False + type: str + default: execution + node_state: + description: + - Indicates the current life cycle stage of this instance. + choices: + - provisioning + - provision-fail + - installed + - ready + - unavailable + - deprovisioning + - deprovision-fail + required: False + default: installed + type: str + listener_port: + description: + - Port that Receptor will listen for incoming connections on. + required: False + default: 27199 + type: int +extends_documentation_fragment: awx.awx.auth +''' + +EXAMPLES = ''' +- name: Create an instance + awx.awx.instance: + hostname: my-instance.prod.example.com + capacity_adjustment: 0.4 + listener_port: 31337 + +- name: Deprovision the instance + awx.awx.instance: + hostname: my-instance.prod.example.com + node_state: deprovisioning +''' + +from ..module_utils.controller_api import ControllerAPIModule + + +def main(): + # Any additional arguments that are not fields of the item can be added here + argument_spec = dict( + hostname=dict(required=True), + capacity_adjustment=dict(type='float'), + enabled=dict(type='bool'), + managed_by_policy=dict(type='bool'), + node_type=dict(type='str', choices=['control', 'execution', 'hybrid', 'hop']), + node_state=dict(type='str', choices=['provisioning', 'provision-fail', 'installed', 'ready', 'unavailable', 'deprovisioning', 'deprovision-fail']), + listener_port=dict(type='int'), + ) + + # Create a module for ourselves + module = ControllerAPIModule(argument_spec=argument_spec) + + # Extract our parameters + hostname = module.params.get('hostname') + capacity_adjustment = module.params.get('capacity_adjustment') + enabled = module.params.get('enabled') + managed_by_policy = module.params.get('managed_by_policy') + node_type = module.params.get('node_type') + node_state = module.params.get('node_state') + listener_port = module.params.get('listener_port') + + # Attempt to look up an existing item based on the provided data + existing_item = module.get_one('instances', name_or_id=hostname) + + # Create the data that gets sent for create and update + new_fields = {'hostname': hostname} + if capacity_adjustment is not None: + new_fields['capacity_adjustment'] = capacity_adjustment + if enabled is not None: + new_fields['enabled'] = enabled + if managed_by_policy is not None: + new_fields['managed_by_policy'] = managed_by_policy + if node_type is not None: + new_fields['node_type'] = node_type + if node_state is not None: + new_fields['node_state'] = node_state + if listener_port is not None: + new_fields['listener_port'] = listener_port + + module.create_or_update_if_needed( + existing_item, + new_fields, + endpoint='instances', + item_type='instance', + ) + + +if __name__ == '__main__': + main() diff --git a/awx_collection/test/awx/test_completeness.py b/awx_collection/test/awx/test_completeness.py index 93ddd52fea..43e225e4b8 100644 --- a/awx_collection/test/awx/test_completeness.py +++ b/awx_collection/test/awx/test_completeness.py @@ -82,7 +82,6 @@ needs_development = ['inventory_script', 'instance'] needs_param_development = { 'host': ['instance_id'], 'workflow_approval': ['description', 'execution_environment'], - 'instances': ['capacity_adjustment', 'enabled', 'hostname', 'ip_address', 'managed_by_policy', 'node_state', 'node_type'], } # ----------------------------------------------------------------------------------------------------------- diff --git a/awx_collection/tests/integration/targets/instance/tasks/main.yml b/awx_collection/tests/integration/targets/instance/tasks/main.yml new file mode 100644 index 0000000000..4d5a596971 --- /dev/null +++ b/awx_collection/tests/integration/targets/instance/tasks/main.yml @@ -0,0 +1,55 @@ +--- +- name: Generate hostnames + set_fact: + hostname1: "AWX-Collection-tests-instance1.{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}.example.com" + hostname2: "AWX-Collection-tests-instance2.{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}.example.com" + hostname3: "AWX-Collection-tests-instance3.{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}.example.com" + register: facts + +- name: Show hostnames + debug: + var: facts + +- block: + - name: Create an instance + awx.awx.instance: + hostname: "{{ item }}" + with_items: + - "{{ hostname1 }}" + - "{{ hostname2 }}" + register: result + + - assert: + that: + - result is changed + + - name: Create an instance with non-default config + awx.awx.instance: + hostname: "{{ hostname3 }}" + capacity_adjustment: 0.4 + listener_port: 31337 + register: result + + - assert: + that: + - result is changed + + - name: Update an instance + awx.awx.instance: + hostname: "{{ hostname1 }}" + capacity_adjustment: 0.7 + register: result + + - assert: + that: + - result is changed + + always: + - name: Deprovision the instances + awx.awx.instance: + hostname: "{{ item }}" + node_state: deprovisioning + with_items: + - "{{ hostname1 }}" + - "{{ hostname2 }}" + - "{{ hostname3 }}" |