diff --git a/awx_collection/plugins/module_utils/tower_api.py b/awx_collection/plugins/module_utils/tower_api.py index d41c32b772..2e03abbb1f 100644 --- a/awx_collection/plugins/module_utils/tower_api.py +++ b/awx_collection/plugins/module_utils/tower_api.py @@ -336,8 +336,8 @@ class TowerAPIModule(TowerModule): # If we have neither of these, then we can try un-authenticated access self.authenticated = True - - def delete_if_needed(self, existing_item, on_delete=None): + + def delete_if_needed(self, existing_item, on_delete=None, on_continue=None): # This will exit from the module on its own. # If the method successfully deletes an item and on_delete param is defined, # the on_delete parameter will be called as a method pasing in this object and the json from the response @@ -363,6 +363,10 @@ class TowerAPIModule(TowerModule): self.json_output['changed'] = True self.json_output['id'] = item_id self.exit_json(**self.json_output) + if on_continue is not None: + return self.json_output + else: + self.exit_json(**self.json_output) else: if 'json' in response and '__all__' in response['json']: self.fail_json(msg="Unable to delete {0} {1}: {2}".format(item_type, item_name, response['json']['__all__'][0])) @@ -375,7 +379,10 @@ class TowerAPIModule(TowerModule): else: self.fail_json(msg="Unable to delete {0} {1}: {2}".format(item_type, item_name, response['status_code'])) else: - self.exit_json(**self.json_output) + if on_continue is not None: + return None + else: + self.exit_json(**self.json_output) def modify_associations(self, association_endpoint, new_association_list): # if we got None instead of [] we are not modifying the association_list @@ -403,8 +410,8 @@ class TowerAPIModule(TowerModule): else: self.fail_json(msg="Failed to associate item {0}".format(response['json']['detail'])) - def create_if_needed(self, existing_item, new_item, endpoint, on_create=None, item_type='unknown', associations=None): - + def create_if_needed(self, existing_item, new_item, endpoint, on_create=None, on_continue=None, item_type='unknown', associations=None): + # This will exit from the module on its own # If the method successfully creates an item and on_create param is defined, # the on_create parameter will be called as a method pasing in this object and the json from the response @@ -430,6 +437,7 @@ class TowerAPIModule(TowerModule): item_name = self.get_item_name(new_item, allow_unknown=True) response = self.post_endpoint(endpoint, **{'data': new_item}) + if response['status_code'] == 201: self.json_output['name'] = 'unknown' for key in ('name', 'username', 'identifier', 'hostname'): @@ -438,6 +446,15 @@ class TowerAPIModule(TowerModule): self.json_output['id'] = response['json']['id'] self.json_output['changed'] = True item_url = response['json']['url'] + # 200 is response from approval node creation + elif response['status_code'] == 200 and item_type == 'workflow_job_template_approval_node': + self.json_output['name'] = 'unknown' + for key in ('name', 'username', 'identifier', 'hostname'): + if key in response['json']: + self.json_output['name'] = response['json'][key] + self.json_output['id'] = response['json']['id'] + self.json_output['changed'] = True + item_url = response['json']['url'] else: if 'json' in response and '__all__' in response['json']: self.fail_json(msg="Unable to create {0} {1}: {2}".format(item_type, item_name, response['json']['__all__'][0])) @@ -455,6 +472,9 @@ class TowerAPIModule(TowerModule): # If we have an on_create method and we actually changed something we can call on_create if on_create is not None and self.json_output['changed']: on_create(self, response['json']) + elif on_continue is not None: + last_data = response['json'] + return last_data else: self.exit_json(**self.json_output) @@ -518,7 +538,7 @@ class TowerAPIModule(TowerModule): return True return False - def update_if_needed(self, existing_item, new_item, on_update=None, associations=None): + def update_if_needed(self, existing_item, new_item, on_update=None, on_continue=None, associations=None): # This will exit from the module on its own # If the method successfully updates an item and on_update param is defined, # the on_update parameter will be called as a method pasing in this object and the json from the response @@ -578,14 +598,20 @@ class TowerAPIModule(TowerModule): else: last_data = response['json'] on_update(self, last_data) + elif on_continue is not None: + if response is None: + last_data = existing_item + else: + last_data = response['json'] + return last_data else: self.exit_json(**self.json_output) - - def create_or_update_if_needed(self, existing_item, new_item, endpoint=None, item_type='unknown', on_create=None, on_update=None, associations=None): + + def create_or_update_if_needed(self, existing_item, new_item, endpoint=None, item_type='unknown', on_create=None, on_update=None, on_continue=None, associations=None): if existing_item: - return self.update_if_needed(existing_item, new_item, on_update=on_update, associations=associations) + return self.update_if_needed(existing_item, new_item, on_update=on_update, on_continue=on_continue, associations=associations) else: - return self.create_if_needed(existing_item, new_item, endpoint, on_create=on_create, item_type=item_type, associations=associations) + return self.create_if_needed(existing_item, new_item, endpoint, on_create=on_create, item_type=item_type, on_continue=on_continue, associations=associations) def logout(self): if self.authenticated and self.oauth_token_id: diff --git a/awx_collection/plugins/modules/tower_workflow_job_template_node.py b/awx_collection/plugins/modules/tower_workflow_job_template_node.py index 0705de6785..f1e65b4d75 100644 --- a/awx_collection/plugins/modules/tower_workflow_job_template_node.py +++ b/awx_collection/plugins/modules/tower_workflow_job_template_node.py @@ -166,6 +166,10 @@ def main(): identifier=dict(required=True), workflow_job_template=dict(required=True, aliases=['workflow']), organization=dict(), + approval_node=dict(type='bool'), + name=dict(), + description=dict(), + timeout=dict(type='int'), extra_data=dict(type='dict'), inventory=dict(), scm_branch=dict(), @@ -180,6 +184,7 @@ def main(): success_nodes=dict(type='list', elements='str'), always_nodes=dict(type='list', elements='str'), failure_nodes=dict(type='list', elements='str'), + approval_nodes=dict(type='list', elements='str'), credentials=dict(type='list', elements='str'), state=dict(choices=['present', 'absent'], default='present'), ) @@ -190,7 +195,10 @@ def main(): # Extract our parameters identifier = module.params.get('identifier') state = module.params.get('state') - + approval_node = module.params.get('approval_node') + name = module.params.get('name') + description = module.params.get('description') + timeout = module.params.get('timeout') new_fields = {} search_fields = {'identifier': identifier} @@ -237,7 +245,7 @@ def main(): new_fields[field_name] = field_val association_fields = {} - for association in ('always_nodes', 'success_nodes', 'failure_nodes', 'credentials'): + for association in ('always_nodes', 'success_nodes', 'failure_nodes', 'approval_nodes', 'credentials'): name_list = module.params.get(association) if name_list is None: continue @@ -264,10 +272,31 @@ def main(): # If the state was present and we can let the module build or update the existing item, this will return on its own module.create_or_update_if_needed( existing_item, new_fields, - endpoint='workflow_job_template_nodes', item_type='workflow_job_template_node', + endpoint='workflow_job_template_nodes', item_type='workflow_job_template_node', on_continue=approval_node, associations=association_fields ) - - + if approval_node: + # Set Approval Fields + new_fields = {} + if name is not None: + new_fields['name'] = name + if description is not None: + new_fields['description'] = description + if timeout is not None: + new_fields['timeout'] = timeout + # Find created approval node ID + search_fields = {'identifier': identifier} + search_fields['workflow_job_template'] = workflow_job_template_id + workflow_job_template_node = module.get_one('workflow_job_template_nodes', **{'data': search_fields}) + workflow_job_template_node_id = workflow_job_template_node['id'] + # Due to not able to lookup workflow_approval_templates, none existing item + existing_item = {} + # module.fail_json(msg="workflow_job_template_nodes/{0}/create_approval_template/".format(workflow_job_template_node_id)) + module.create_or_update_if_needed( + existing_item, new_fields, + endpoint='workflow_job_template_nodes/' + str(workflow_job_template_node_id) + '/create_approval_template/', item_type='workflow_job_template_approval_node', on_continue=approval_node, + associations=association_fields + ) + module.exit_json(**module.json_output) if __name__ == '__main__': main()