From 7f66f084f14617fd7837ae2ee09fadd198b424cf Mon Sep 17 00:00:00 2001 From: John Westcott IV Date: Mon, 27 Apr 2020 14:11:23 -0400 Subject: [PATCH] Restructuring modules so that lookup don't happen if deleting --- .../plugins/modules/tower_credential.py | 17 +++++----- .../plugins/modules/tower_credential_type.py | 6 ++-- awx_collection/plugins/modules/tower_group.py | 18 +++++----- awx_collection/plugins/modules/tower_host.py | 12 +++---- .../plugins/modules/tower_inventory.py | 18 +++++----- .../plugins/modules/tower_inventory_source.py | 12 +++---- .../plugins/modules/tower_job_template.py | 34 +++++++++---------- .../plugins/modules/tower_notification.py | 22 ++++++------ .../plugins/modules/tower_organization.py | 12 +++---- .../plugins/modules/tower_project.py | 14 ++++---- awx_collection/plugins/modules/tower_team.py | 12 +++---- awx_collection/plugins/modules/tower_user.py | 12 +++---- .../modules/tower_workflow_job_template.py | 26 +++++++------- .../tower_workflow_job_template_node.py | 26 +++++++------- .../tower_inventory_source/tasks/main.yml | 12 +++---- .../targets/tower_job_template/tasks/main.yml | 5 +-- .../tasks/main.yml | 4 ++- .../tools/templates/tower_module.j2 | 24 ++++++------- 18 files changed, 143 insertions(+), 143 deletions(-) diff --git a/awx_collection/plugins/modules/tower_credential.py b/awx_collection/plugins/modules/tower_credential.py index 5e0717526b..2fe3ca45c2 100644 --- a/awx_collection/plugins/modules/tower_credential.py +++ b/awx_collection/plugins/modules/tower_credential.py @@ -382,10 +382,15 @@ def main(): 'name': name, 'credential_type': cred_type_id, } + if organization: lookup_data['organization'] = org_id credential = module.get_one('credentials', **{'data': lookup_data}) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(credential) + # Create credential input from legacy inputs credential_inputs = {} for legacy_input in OLD_INPUT_NAMES: @@ -415,14 +420,10 @@ def main(): if team: credential_fields['team'] = team_id - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(credential) - elif state == 'present': - # If the state was present we can let the module build or update the existing group, this will return on its own - module.create_or_update_if_needed( - credential, credential_fields, endpoint='credentials', item_type='credential' - ) + # If the state was present we can let the module build or update the existing group, this will return on its own + module.create_or_update_if_needed( + credential, credential_fields, endpoint='credentials', item_type='credential' + ) if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_credential_type.py b/awx_collection/plugins/modules/tower_credential_type.py index 5c3186bca0..71ecc81526 100644 --- a/awx_collection/plugins/modules/tower_credential_type.py +++ b/awx_collection/plugins/modules/tower_credential_type.py @@ -144,9 +144,9 @@ def main(): if state == 'absent': # If the state was absent we can let the module delete it if needed, the module will handle exiting from this module.delete_if_needed(credential_type) - elif state == 'present': - # If the state was present and we can let the module build or update the existing credential type, this will return on its own - module.create_or_update_if_needed(credential_type, credential_type_params, endpoint='credential_types', item_type='credential type') + + # If the state was present and we can let the module build or update the existing credential type, this will return on its own + module.create_or_update_if_needed(credential_type, credential_type_params, endpoint='credential_types', item_type='credential type') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_group.py b/awx_collection/plugins/modules/tower_group.py index 91504d4d9b..ec76ca40ad 100644 --- a/awx_collection/plugins/modules/tower_group.py +++ b/awx_collection/plugins/modules/tower_group.py @@ -123,6 +123,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(group) + # Create the data that gets sent for create and update group_fields = { 'name': new_name if new_name else name, @@ -149,15 +153,11 @@ def main(): if id_list: association_fields[relationship] = id_list - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(group) - elif state == 'present': - # If the state was present we can let the module build or update the existing group, this will return on its own - module.create_or_update_if_needed( - group, group_fields, endpoint='groups', item_type='group', - associations=association_fields - ) + # If the state was present we can let the module build or update the existing group, this will return on its own + module.create_or_update_if_needed( + group, group_fields, endpoint='groups', item_type='group', + associations=association_fields + ) if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_host.py b/awx_collection/plugins/modules/tower_host.py index 9d2698e4e5..27e4f5a048 100644 --- a/awx_collection/plugins/modules/tower_host.py +++ b/awx_collection/plugins/modules/tower_host.py @@ -119,6 +119,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(host) + # Create the data that gets sent for create and update host_fields = { 'name': new_name if new_name else name, @@ -130,12 +134,8 @@ def main(): if variables is not None: host_fields['variables'] = json.dumps(variables) - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(host) - elif state == 'present': - # If the state was present and we can let the module build or update the existing host, this will return on its own - module.create_or_update_if_needed(host, host_fields, endpoint='hosts', item_type='host') + # If the state was present and we can let the module build or update the existing host, this will return on its own + module.create_or_update_if_needed(host, host_fields, endpoint='hosts', item_type='host') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_inventory.py b/awx_collection/plugins/modules/tower_inventory.py index d17d202c98..151fa07232 100644 --- a/awx_collection/plugins/modules/tower_inventory.py +++ b/awx_collection/plugins/modules/tower_inventory.py @@ -119,6 +119,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(inventory) + # Create the data that gets sent for create and update inventory_fields = { 'name': name, @@ -131,16 +135,12 @@ def main(): if variables is not None: inventory_fields['variables'] = json.dumps(variables) - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(inventory) - elif state == 'present': - # We need to perform a check to make sure you are not trying to convert a regular inventory into a smart one. - if inventory and inventory['kind'] == '' and inventory_fields['kind'] == 'smart': - module.fail_json(msg='You cannot turn a regular inventory into a "smart" inventory.') + # We need to perform a check to make sure you are not trying to convert a regular inventory into a smart one. + if inventory and inventory['kind'] == '' and inventory_fields['kind'] == 'smart': + module.fail_json(msg='You cannot turn a regular inventory into a "smart" inventory.') - # If the state was present and we can let the module build or update the existing inventory, this will return on its own - module.create_or_update_if_needed(inventory, inventory_fields, endpoint='inventories', item_type='inventory') + # If the state was present and we can let the module build or update the existing inventory, this will return on its own + module.create_or_update_if_needed(inventory, inventory_fields, endpoint='inventories', item_type='inventory') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_inventory_source.py b/awx_collection/plugins/modules/tower_inventory_source.py index 0bd848bbec..f959580d01 100644 --- a/awx_collection/plugins/modules/tower_inventory_source.py +++ b/awx_collection/plugins/modules/tower_inventory_source.py @@ -198,6 +198,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(inventory_source) + # Create the data that gets sent for create and update inventory_source_fields = { 'name': new_name if new_name else name, @@ -234,12 +238,8 @@ def main(): if state == 'present' and not inventory_source and not inventory_source_fields['source']: module.fail_json(msg="If creating a new inventory source, the source param must be present") - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(inventory_source) - elif state == 'present': - # If the state was present we can let the module build or update the existing inventory_source, this will return on its own - module.create_or_update_if_needed(inventory_source, inventory_source_fields, endpoint='inventory_sources', item_type='inventory source') + # If the state was present we can let the module build or update the existing inventory_source, this will return on its own + module.create_or_update_if_needed(inventory_source, inventory_source_fields, endpoint='inventory_sources', item_type='inventory source') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_job_template.py b/awx_collection/plugins/modules/tower_job_template.py index 2d54ad7ad4..7282c7ec43 100644 --- a/awx_collection/plugins/modules/tower_job_template.py +++ b/awx_collection/plugins/modules/tower_job_template.py @@ -414,6 +414,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + # Create the data that gets sent for create and update new_fields = {} new_fields['name'] = new_name if new_name else name @@ -490,23 +494,19 @@ def main(): module._encrypted_changed_warning('survey_spec', existing_item, warning=True) on_change = update_survey - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state == 'present': - # 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='job_templates', item_type='job_template', - associations={ - 'credentials': credentials_ids, - 'labels': labels_ids, - 'notification_templates_success': notification_success_ids, - 'notification_templates_started': notification_start_ids, - 'notification_templates_error': notification_error_ids - }, - on_create=on_change, on_update=on_change, - ) + # 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='job_templates', item_type='job_template', + associations={ + 'credentials': credentials_ids, + 'labels': labels_ids, + 'notification_templates_success': notification_success_ids, + 'notification_templates_started': notification_start_ids, + 'notification_templates_error': notification_error_ids + }, + on_create=on_change, on_update=on_change, + ) if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_notification.py b/awx_collection/plugins/modules/tower_notification.py index bae4302449..875a912f84 100644 --- a/awx_collection/plugins/modules/tower_notification.py +++ b/awx_collection/plugins/modules/tower_notification.py @@ -416,6 +416,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + # Create notification_configuration from legacy inputs final_notification_configuration = {} for legacy_input in OLD_INPUT_NAMES: @@ -440,17 +444,13 @@ def main(): if messages is not None: new_fields['messages'] = messages - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state == 'present': - # 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='notification_templates', item_type='notification_template', - associations={ - } - ) + # 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='notification_templates', item_type='notification_template', + associations={ + } + ) if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_organization.py b/awx_collection/plugins/modules/tower_organization.py index 2b1de03f73..44bb47c787 100644 --- a/awx_collection/plugins/modules/tower_organization.py +++ b/awx_collection/plugins/modules/tower_organization.py @@ -108,6 +108,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(organization) + # Create the data that gets sent for create and update org_fields = {'name': name} if description is not None: @@ -117,12 +121,8 @@ def main(): if max_hosts is not None: org_fields['max_hosts'] = max_hosts - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(organization) - elif state == 'present': - # If the state was present and we can let the module build or update the existing organization, this will return on its own - module.create_or_update_if_needed(organization, org_fields, endpoint='organizations', item_type='organization') + # If the state was present and we can let the module build or update the existing organization, this will return on its own + module.create_or_update_if_needed(organization, org_fields, endpoint='organizations', item_type='organization') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_project.py b/awx_collection/plugins/modules/tower_project.py index 2d84b82c0b..d390d86185 100644 --- a/awx_collection/plugins/modules/tower_project.py +++ b/awx_collection/plugins/modules/tower_project.py @@ -236,6 +236,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(project) + # Create the data that gets sent for create and update project_fields = { 'name': name, @@ -260,7 +264,7 @@ def main(): if scm_type == '': project_fields['local_path'] = local_path - if state != 'absent' and (scm_update_cache_timeout != 0 and scm_update_on_launch is not True): + if scm_update_cache_timeout != 0 and scm_update_on_launch is not True: module.warn('scm_update_cache_timeout will be ignored since scm_update_on_launch was not set to true') # If we are doing a not manual project, register our on_change method @@ -269,12 +273,8 @@ def main(): if wait and scm_type != '': on_change = wait_for_project_update - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(project) - elif state == 'present': - # If the state was present and we can let the module build or update the existing project, this will return on its own - module.create_or_update_if_needed(project, project_fields, endpoint='projects', item_type='project', on_create=on_change, on_update=on_change) + # If the state was present and we can let the module build or update the existing project, this will return on its own + module.create_or_update_if_needed(project, project_fields, endpoint='projects', item_type='project', on_create=on_change, on_update=on_change) if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_team.py b/awx_collection/plugins/modules/tower_team.py index c581bebf4d..d7af5a616d 100644 --- a/awx_collection/plugins/modules/tower_team.py +++ b/awx_collection/plugins/modules/tower_team.py @@ -102,6 +102,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(team) + # Create the data that gets sent for create and update team_fields = { 'name': new_name if new_name else name, @@ -110,12 +114,8 @@ def main(): if description is not None: team_fields['description'] = description - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(team) - elif state == 'present': - # If the state was present and we can let the module build or update the existing team, this will return on its own - module.create_or_update_if_needed(team, team_fields, endpoint='teams', item_type='team') + # If the state was present and we can let the module build or update the existing team, this will return on its own + module.create_or_update_if_needed(team, team_fields, endpoint='teams', item_type='team') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_user.py b/awx_collection/plugins/modules/tower_user.py index eac8d70bed..f2f6b1fc31 100644 --- a/awx_collection/plugins/modules/tower_user.py +++ b/awx_collection/plugins/modules/tower_user.py @@ -147,6 +147,10 @@ def main(): } }) + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + # Create the data that gets sent for create and update new_fields = {} if username: @@ -164,12 +168,8 @@ def main(): if password: new_fields['password'] = password - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state == 'present': - # 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='users', item_type='user') + # 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='users', item_type='user') if __name__ == '__main__': diff --git a/awx_collection/plugins/modules/tower_workflow_job_template.py b/awx_collection/plugins/modules/tower_workflow_job_template.py index 198aa208fc..a58b6d40bc 100644 --- a/awx_collection/plugins/modules/tower_workflow_job_template.py +++ b/awx_collection/plugins/modules/tower_workflow_job_template.py @@ -175,6 +175,13 @@ def main(): organization_id = module.resolve_name_to_id('organizations', organization) search_fields['organization'] = new_fields['organization'] = organization_id + # Attempt to look up an existing item based on the provided data + existing_item = module.get_one('workflow_job_templates', **{'data': search_fields}) + + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + inventory = module.params.get('inventory') if inventory: new_fields['inventory'] = module.resolve_name_to_id('inventories', inventory) @@ -183,9 +190,6 @@ def main(): if webhook_credential: new_fields['webhook_credential'] = module.resolve_name_to_id('webhook_credential', webhook_credential) - # Attempt to look up an existing item based on the provided data - existing_item = module.get_one('workflow_job_templates', **{'data': search_fields}) - # Create the data that gets sent for create and update new_fields['name'] = new_name if new_name else name for field_name in ( @@ -213,16 +217,12 @@ def main(): module._encrypted_changed_warning('survey_spec', existing_item, warning=True) on_change = update_survey - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state == 'present': - # 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_templates', item_type='workflow_job_template', - on_create=on_change, on_update=on_change - ) + # 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_templates', item_type='workflow_job_template', + on_create=on_change, on_update=on_change + ) if __name__ == '__main__': 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 8e271014d1..2e8b74e843 100644 --- a/awx_collection/plugins/modules/tower_workflow_job_template_node.py +++ b/awx_collection/plugins/modules/tower_workflow_job_template_node.py @@ -218,6 +218,13 @@ def main(): workflow_job_template_id = wfjt_data['id'] search_fields['workflow_job_template'] = new_fields['workflow_job_template'] = workflow_job_template_id + # Attempt to look up an existing item based on the provided data + existing_item = module.get_one('workflow_job_template_nodes', **{'data': search_fields}) + + if state == 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + unified_job_template = module.params.get('unified_job_template') if unified_job_template: new_fields['unified_job_template'] = module.resolve_name_to_id('unified_job_templates', unified_job_template) @@ -226,9 +233,6 @@ def main(): if inventory: new_fields['inventory'] = module.resolve_name_to_id('inventory', inventory) - # Attempt to look up an existing item based on the provided data - existing_item = module.get_one('workflow_job_template_nodes', **{'data': search_fields}) - # Create the data that gets sent for create and update for field_name in ( 'identifier', 'extra_data', 'scm_branch', 'job_type', 'job_tags', 'skip_tags', @@ -262,16 +266,12 @@ def main(): # In the case of a new object, the utils need to know it is a node new_fields['type'] = 'workflow_job_template_node' - if state == 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state == 'present': - # 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', - associations=association_fields - ) + # 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', + associations=association_fields + ) if __name__ == '__main__': diff --git a/awx_collection/tests/integration/targets/tower_inventory_source/tasks/main.yml b/awx_collection/tests/integration/targets/tower_inventory_source/tasks/main.yml index 9cb82a231b..fb5f33c3ca 100644 --- a/awx_collection/tests/integration/targets/tower_inventory_source/tasks/main.yml +++ b/awx_collection/tests/integration/targets/tower_inventory_source/tasks/main.yml @@ -40,17 +40,13 @@ that: - "result is changed" -- name: Delete the source inventory +- name: Delete the inventory source with an invalid cred, source_project, sourece_script specified tower_inventory_source: name: "{{ openstack_inv_source }}" - description: Source for Test inventory inventory: "{{ openstack_inv }}" - credential: "{{ openstack_cred }}" - overwrite: true - update_on_launch: true - source_vars: - private: false - source: openstack + credential: "Does Not Exit" + source_project: "Does Not Exist" + source_script: "Does Not Exist" state: absent - assert: diff --git a/awx_collection/tests/integration/targets/tower_job_template/tasks/main.yml b/awx_collection/tests/integration/targets/tower_job_template/tasks/main.yml index bc43166ac3..af70d1afd6 100644 --- a/awx_collection/tests/integration/targets/tower_job_template/tasks/main.yml +++ b/awx_collection/tests/integration/targets/tower_job_template/tasks/main.yml @@ -147,10 +147,11 @@ - name: Delete Job Template 1 tower_job_template: name: "{{ jt1 }}" - project: "{{ proj1 }}" - inventory: Demo Inventory playbook: hello_world.yml job_type: run + project: "Does Not Exist" + inventory: "Does Not Exist" + webhook_credential: "Does Not Exist" state: absent register: result diff --git a/awx_collection/tests/integration/targets/tower_workflow_job_template/tasks/main.yml b/awx_collection/tests/integration/targets/tower_workflow_job_template/tasks/main.yml index 8a7a180ff9..6840dd515a 100644 --- a/awx_collection/tests/integration/targets/tower_workflow_job_template/tasks/main.yml +++ b/awx_collection/tests/integration/targets/tower_workflow_job_template/tasks/main.yml @@ -104,9 +104,11 @@ unified_job_template: "{{ jt1_name }}" workflow: "{{ wfjt_name }}" -- name: Delete a workflow job template +- name: Delete a workflow job template with an invalid inventory and webook_credential tower_workflow_job_template: name: "{{ wfjt_name }}" + inventory: "Does Not Exist" + webhook_credential: "Does Not Exist" state: absent register: result diff --git a/awx_collection/tools/templates/tower_module.j2 b/awx_collection/tools/templates/tower_module.j2 index 25d9e0a08a..5d687bfc24 100644 --- a/awx_collection/tools/templates/tower_module.j2 +++ b/awx_collection/tools/templates/tower_module.j2 @@ -188,6 +188,10 @@ def main(): } }) + if state is 'absent': + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + module.delete_if_needed(existing_item) + # Create the data that gets sent for create and update new_fields = {} {% for option in item['json']['actions']['POST'] %} @@ -203,20 +207,16 @@ def main(): {% endif %} {% endfor %} - if state is 'absent': - # If the state was absent we can let the module delete it if needed, the module will handle exiting from this - module.delete_if_needed(existing_item) - elif state is 'present': - # 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='{{ item_type }}', item_type='{{ singular_item_type }}', - associations={ + # 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='{{ item_type }}', item_type='{{ singular_item_type }}', + associations={ {% for association in associations[item_type] | default([]) %} - '{{ association['endpoint'] }}': {{ association['related_item'] }}_ids, + '{{ association['endpoint'] }}': {{ association['related_item'] }}_ids, {% endfor %} - } - ) + } + ) if __name__ == '__main__':