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
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. - 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/). - 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 - 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. - 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: 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 import StringIO
from ansible.module_utils.six.moves.urllib.error import HTTPError 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.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 ansible.module_utils.six.moves.configparser import ConfigParser, NoOptionError
from socket import getaddrinfo, IPPROTO_TCP from socket import getaddrinfo, IPPROTO_TCP
import time 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): def get_one(self, endpoint, name_or_id=None, allow_none=True, check_exists=False, **kwargs):
new_kwargs = kwargs.copy() new_kwargs = kwargs.copy()
if name_or_id: response = None
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: # A named URL is pretty unique so if we have a ++ in the name then lets start by looking for that
new_data['or__id'] = int(name_or_id) # 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
new_data['or__{0}'.format(name_field)] = name_or_id if name_or_id is not None and '++' in name_or_id:
except ValueError: # Maybe someone gave us a named URL so lets see if we get anything from that.
# If we get a value error, then we didn't have an integer so we can just pass and fall down to the fail url_quoted_name = quote(name_or_id, safe="+")
new_data[name_field] = name_or_id named_endpoint = '{0}/{1}/'.format(endpoint, url_quoted_name)
new_kwargs['data'] = new_data named_response = self.get_endpoint(named_endpoint)
response = self.get_endpoint(endpoint, **new_kwargs) if named_response['status_code'] == 200 and 'json' in named_response:
if response['status_code'] != 200: # We found a named item but we expect to deal with a list view so mock that up
fail_msg = "Got a {0} response when trying to get one from {1}".format(response['status_code'], endpoint) response = {
if 'detail' in response.get('json', {}): 'json': {
fail_msg += ', detail: {0}'.format(response['json']['detail']) 'count': 1,
self.fail_json(msg=fail_msg) 'results': [named_response['json']],
}
}
if 'count' not in response['json'] or 'results' not in response['json']: # Since we didn't have a named URL, lets try and find it with a general search
self.fail_json(msg="The endpoint did not provide count and results") 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 response['json']['count'] == 0:
if allow_none: if allow_none:
@@ -423,7 +445,6 @@ class ControllerAPIModule(ControllerModule):
self.fail_wanted_one(response, endpoint, new_kwargs.get('data')) self.fail_wanted_one(response, endpoint, new_kwargs.get('data'))
if check_exists: if check_exists:
name_field = self.get_name_field_from_endpoint(endpoint)
self.json_output['id'] = response['json']['results'][0]['id'] self.json_output['id'] = response['json']['results'][0]['id']
self.exit_json(**self.json_output) 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/). - 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 - 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. - 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. - 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 %} {% else %}
- 3.7.0 initial release - 3.7.0 initial release