Added support to collection for named urls (#14205)

This commit is contained in:
John Westcott IV 2023-07-27 09:22:41 -04:00 committed by GitHub
parent b549ae1efa
commit 5a63533967
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 126 additions and 22 deletions

View File

@ -68,6 +68,7 @@ Notable releases of the `awx.awx` collection:
- 7.0.0 is intended to be identical to the content prior to the migration, aside from changes necessary to function as a collection.
- 11.0.0 has no non-deprecated modules that depend on the deprecated `tower-cli` [PyPI](https://pypi.org/project/ansible-tower-cli/).
- 19.2.1 large renaming purged "tower" names (like options and module names), adding redirects for old names
- X.X.X added support of named URLs to all modules. Anywhere that previously accepted name or id can also support named URLs
- 0.0.1-devel is the version you should see if installing from source, which is intended for development and expected to be unstable.
The following notes are changes that may require changes to playbooks:

View File

@ -10,7 +10,7 @@ from ansible.module_utils.six import raise_from, string_types
from ansible.module_utils.six.moves import StringIO
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.six.moves.http_cookiejar import CookieJar
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlencode
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlencode, quote
from ansible.module_utils.six.moves.configparser import ConfigParser, NoOptionError
from socket import getaddrinfo, IPPROTO_TCP
import time
@ -383,29 +383,51 @@ class ControllerAPIModule(ControllerModule):
def get_one(self, endpoint, name_or_id=None, allow_none=True, check_exists=False, **kwargs):
new_kwargs = kwargs.copy()
if name_or_id:
name_field = self.get_name_field_from_endpoint(endpoint)
new_data = kwargs.get('data', {}).copy()
if name_field in new_data:
self.fail_json(msg="You can't specify the field {0} in your search data if using the name_or_id field".format(name_field))
response = None
try:
new_data['or__id'] = int(name_or_id)
new_data['or__{0}'.format(name_field)] = name_or_id
except ValueError:
# If we get a value error, then we didn't have an integer so we can just pass and fall down to the fail
new_data[name_field] = name_or_id
new_kwargs['data'] = new_data
# A named URL is pretty unique so if we have a ++ in the name then lets start by looking for that
# This also needs to go first because if there was data passed in kwargs and we do the next lookup first there may be results
if name_or_id is not None and '++' in name_or_id:
# Maybe someone gave us a named URL so lets see if we get anything from that.
url_quoted_name = quote(name_or_id, safe="+")
named_endpoint = '{0}/{1}/'.format(endpoint, url_quoted_name)
named_response = self.get_endpoint(named_endpoint)
response = self.get_endpoint(endpoint, **new_kwargs)
if response['status_code'] != 200:
fail_msg = "Got a {0} response when trying to get one from {1}".format(response['status_code'], endpoint)
if 'detail' in response.get('json', {}):
fail_msg += ', detail: {0}'.format(response['json']['detail'])
self.fail_json(msg=fail_msg)
if named_response['status_code'] == 200 and 'json' in named_response:
# We found a named item but we expect to deal with a list view so mock that up
response = {
'json': {
'count': 1,
'results': [named_response['json']],
}
}
if 'count' not in response['json'] or 'results' not in response['json']:
self.fail_json(msg="The endpoint did not provide count and results")
# Since we didn't have a named URL, lets try and find it with a general search
if response is None:
if name_or_id:
name_field = self.get_name_field_from_endpoint(endpoint)
new_data = kwargs.get('data', {}).copy()
if name_field in new_data:
self.fail_json(msg="You can't specify the field {0} in your search data if using the name_or_id field".format(name_field))
try:
new_data['or__id'] = int(name_or_id)
new_data['or__{0}'.format(name_field)] = name_or_id
except ValueError:
# If we get a value error, then we didn't have an integer so we can just pass and fall down to the fail
new_data[name_field] = name_or_id
new_kwargs['data'] = new_data
response = self.get_endpoint(endpoint, **new_kwargs)
if response['status_code'] != 200:
fail_msg = "Got a {0} response when trying to get one from {1}".format(response['status_code'], endpoint)
if 'detail' in response.get('json', {}):
fail_msg += ', detail: {0}'.format(response['json']['detail'])
self.fail_json(msg=fail_msg)
if 'count' not in response['json'] or 'results' not in response['json']:
self.fail_json(msg="The endpoint did not provide count and results")
if response['json']['count'] == 0:
if allow_none:
@ -423,7 +445,6 @@ class ControllerAPIModule(ControllerModule):
self.fail_wanted_one(response, endpoint, new_kwargs.get('data'))
if check_exists:
name_field = self.get_name_field_from_endpoint(endpoint)
self.json_output['id'] = response['json']['results'][0]['id']
self.exit_json(**self.json_output)

View File

@ -0,0 +1,8 @@
---
- name: Generate a random string for test
set_fact:
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
when: test_id is not defined
- include_tasks:
file: test_named_reference.yml

View File

@ -0,0 +1,73 @@
---
- block:
- name: generate random string for project
set_fact:
org_name: "AWX-Collection-tests-organization-org-{{ test_id }}"
cred: "AWX-Collection-tests-job_template-cred-{{ test_id }}"
inv: "AWX-Collection-tests-job_template-inv-{{ test_id }}"
proj: "AWX-Collection-tests-job_template-proj-{{ test_id }}"
jt: "AWX-Collection-tests-job_template-jt-{{ test_id }}"
- name: "Create a new organization"
organization:
name: "{{ org_name }}"
galaxy_credentials:
- Ansible Galaxy
- name: Create an inventory
inventory:
name: "{{ inv }}"
organization: "{{ org_name }}"
- name: Create a Demo Project
project:
name: "{{ proj }}"
organization: "{{ org_name }}"
state: present
scm_type: git
scm_url: https://github.com/ansible/ansible-tower-samples.git
- name: Create Credential
credential:
name: "{{ cred }}"
organization: "{{ org_name }}"
credential_type: Machine
- name: Create Job Template
job_template:
name: "{{ jt }}"
project: "{{ proj }}++{{ org_name }}"
inventory: "{{ inv }}++{{ org_name }}"
playbook: hello_world.yml
credentials:
- "{{ cred }}++Machine+ssh++"
job_type: run
state: present
always:
- name: Delete the Job Template
job_template:
name: "{{ jt }}"
state: absent
- name: Delete the Demo Project
project:
name: "{{ proj }}++{{ org_name }}"
state: absent
- name: Delete Credential
credential:
name: "{{ cred }}++Machine+ssh++{{ org_name }}"
credential_type: Machine
state: absent
- name: Delete the inventory
inventory:
name: "{{ inv }}++{{ org_name }}"
organization: "{{ org_name }}"
state: absent
- name: Remove the organization
organization:
name: "{{ org_name }}"
state: absent

View File

@ -75,6 +75,7 @@ Notable releases of the `{{ collection_namespace }}.{{ collection_package }}` co
- 11.0.0 has no non-deprecated modules that depend on the deprecated `tower-cli` [PyPI](https://pypi.org/project/ansible-tower-cli/).
- 19.2.1 large renaming purged "tower" names (like options and module names), adding redirects for old names
- 21.11.0 "tower" modules deprecated and symlinks removed.
- X.X.X added support of named URLs to all modules. Anywhere that previously accepted name or id can also support named URLs
- 0.0.1-devel is the version you should see if installing from source, which is intended for development and expected to be unstable.
{% else %}
- 3.7.0 initial release