Skip to content

Commit

Permalink
Fix collection uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
bmclaughlin committed Aug 6, 2024
1 parent 606b7fe commit 0ff2a0d
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 72 deletions.
78 changes: 22 additions & 56 deletions plugins/module_utils/ah_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,16 @@ def __init__(self, argument_spec=None, direct_params=None, error_callback=None,

def build_url(self, endpoint, query_params=None):
# Make sure we start with /api/vX
if not endpoint.startswith("/"):
upload_endpoint = "content" in endpoint and "v3" in endpoint and "artifacts" in endpoint
if upload_endpoint and not endpoint.startswith("/api"):
endpoint = "/api/{0}".format(endpoint)
if not endpoint.startswith("/") and not upload_endpoint:
endpoint = "/{0}".format(endpoint)
if not endpoint.startswith("/api/") and not self.path_prefix.startswith("/api/"):
if not endpoint.startswith("/api/") and not self.path_prefix.startswith("/api/") and not upload_endpoint:
endpoint = "api/{0}/v3{1}".format(self.path_prefix, endpoint)
if not endpoint.startswith("/api/") and self.path_prefix.startswith("/api/"):
if not endpoint.startswith("/api/") and self.path_prefix.startswith("/api/") and not upload_endpoint:
endpoint = "{0}/v3{1}".format(self.path_prefix, endpoint)
if not endpoint.endswith("/") and "?" not in endpoint:
if not endpoint.endswith("/") and "?" not in endpoint and not upload_endpoint:
endpoint = "{0}/".format(endpoint)

# Update the URL path with the endpoint
Expand Down Expand Up @@ -379,56 +382,19 @@ def get_only(self, endpoint, name_or_id=None, allow_none=True, key="url", **kwar

def authenticate(self, **kwargs):
if self.username and self.password:
# Attempt to get a token from /v3/auth/token/ by giving it our username/password combo
# If we have a username and password, we need to get a session cookie
api_token_url = self.build_url("auth/token").geturl()
try:
try:
response = self.session.open(
"POST",
api_token_url,
validate_certs=self.verify_ssl,
timeout=self.request_timeout,
follow_redirects=True,
force_basic_auth=True,
url_username=self.username,
url_password=self.password,
headers={"Content-Type": "application/json"},
)
except HTTPError:
test_url = self.build_url("namespaces").geturl()
self.basic_auth = True
basic_str = base64.b64encode("{0}:{1}".format(self.username, self.password).encode("ascii"))
response = self.session.open(
"GET",
test_url,
validate_certs=self.verify_ssl,
timeout=self.request_timeout,
headers={
"Content-Type": "application/json",
"Authorization": "Basic {0}".format(basic_str.decode("ascii")),
},
)
except HTTPError as he:
try:
resp = he.read()
except Exception as e:
resp = "unknown {0}".format(e)
self.fail_json(msg="Failed to get token: {0}".format(he), response=resp)
except (Exception) as e:
# Sanity check: Did the server send back some kind of internal error?
self.fail_json(msg="Failed to get token: {0}".format(e))

token_response = None
if not self.basic_auth:
try:
token_response = response.read()
response_json = loads(token_response)
self.oauth_token = response_json["token"]
except (Exception) as e:
self.fail_json(msg="Failed to extract token information from login response: {0}".format(e), **{"response": token_response})

# If we have neither of these, then we can try un-authenticated access
test_url = self.build_url("namespaces").geturl()
self.basic_auth = True
basic_str = base64.b64encode("{0}:{1}".format(self.username, self.password).encode("ascii"))
self.session.open(
"GET",
test_url,
validate_certs=self.verify_ssl,
timeout=self.request_timeout,
headers={
"Content-Type": "application/json",
"Authorization": "Basic {0}".format(basic_str.decode("ascii")),
},
)
self.authenticated = True

def existing_item_add_url(self, existing_item, endpoint, key="url"):
Expand Down Expand Up @@ -730,7 +696,7 @@ def wait_for_complete(self, task_url):
time.sleep(1)
return

def upload(self, path, endpoint, wait=True, item_type="unknown"):
def upload(self, path, endpoint, wait=True, repository="staging", item_type="unknown"):
if "://" in path:
tmppath = fetch_file(self, path)
path = path.split("/")[-1]
Expand All @@ -739,7 +705,7 @@ def upload(self, path, endpoint, wait=True, item_type="unknown"):
ct, body = self.prepare_multipart(path)
response = self.make_request(
"POST",
endpoint,
"{0}/content/{1}/v3/{2}/".format(self.path_prefix, repository, endpoint),
**{
"data": body,
"headers": {"Content-Type": str(ct)},
Expand Down
12 changes: 10 additions & 2 deletions plugins/modules/ah_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
- Collection artifact file path.
- If version is not specified, version will be derived from file name.
type: str
repository:
description:
- Name of the destination collection for the repository (staging for uploads).
required: False
type: str
default: 'staging'
wait:
description:
- Waits for the collection to be uploaded
Expand Down Expand Up @@ -114,6 +120,7 @@ def main():
namespace=dict(required=True),
name=dict(required=True),
path=dict(),
repository=dict(default='staging'),
wait=dict(type="bool", default=True),
interval=dict(default=10.0, type="float"),
timeout=dict(default=None, type="int"),
Expand All @@ -130,6 +137,7 @@ def main():
namespace = module.params.get("namespace")
name = module.params.get("name")
path = module.params.get("path")
repository = module.params.get("repository")
wait = module.params.get("wait")
interval = module.params.get("interval")
timeout = module.params.get("timeout")
Expand Down Expand Up @@ -176,7 +184,7 @@ def main():
module.json_output["deleted"] = True
module.wait_for_complete(module.json_output["task"])
# Upload new collection
module.upload(path, "artifacts/collections", wait, item_type="collections")
module.upload(path, "artifacts/collections", wait, repository, item_type="collections")
module.json_output["changed"] = True
# Get new collection version
existing_item = module.get_endpoint(collection_endpoint, **{"return_none_on_404": True})
Expand All @@ -187,7 +195,7 @@ def main():
interval=interval
)
elif existing_item is None:
module.upload(path, "artifacts/collections", wait, item_type="collections")
module.upload(path, "artifacts/collections", wait, repository, item_type="collections")
module.json_output["changed"] = True
if auto_approve:
module.approve(
Expand Down
10 changes: 9 additions & 1 deletion plugins/modules/ah_collection_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
- Can be a URL
required: True
type: str
repository:
description:
- Name of the collection's repository
- Defaults to 'staging'
required: False
type: str
wait:
description:
- Wait for the collection to be uploaded.
Expand Down Expand Up @@ -59,6 +65,7 @@ def main():
# Any additional arguments that are not fields of the item can be added here
argument_spec = dict(
path=dict(required=True),
repository=dict(required=False),
wait=dict(type="bool", default=True),
)

Expand All @@ -67,9 +74,10 @@ def main():

# Extract our parameters
path = module.params.get("path")
repository = module.params.get("repository") or "staging"
wait = module.params.get("wait")

module.upload(path, "artifacts/collections", wait, item_type="collections")
module.upload(path, "artifacts/collections", wait, repository, item_type="collections")
module.exit_json(**module.json_output)


Expand Down
1 change: 1 addition & 0 deletions roles/collection/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
name: "{{ __collection.name }}"
version: "{{ __collection.version | default(omit) }}"
path: "{{ __collection.path | default(omit) }}"
repository: "{{ __collection.repository | default(omit) }}"
wait: "{{ __collection.wait | default(omit) }}"
auto_approve: "{{ __collection.auto_approve | default(omit) }}"
timeout: "{{ __collection.timeout | default(omit) }}"
Expand Down
15 changes: 2 additions & 13 deletions tests/playbooks/testing_collections_playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
collections:
- galaxy.galaxy
vars:
ah_path_prefix: 'galaxy'
ah_path_prefix: '/api/galaxy'
ah_hostname: "{{ lookup('ansible.builtin.env', 'AH_HOST') }}"
ah_username: "{{ lookup('ansible.builtin.env', 'AH_USERNAME') }}"
ah_password: "{{ lookup('ansible.builtin.env', 'AH_PASSWORD') }}"
Expand Down Expand Up @@ -47,7 +47,7 @@
- name: community_test
company: Community Test
email: [email protected]
avatar_url: https://github.com/ansible/awx-logos/blob/master/awx/ui/client/assets/logo-header.svg
avatar_url: https://github.com/ansible/awx-logos/blob/master/awx/ui/client/assets/192.png
description: string
resources: "# Community\nA Namespace test with changes"
links:
Expand All @@ -57,7 +57,6 @@
- name: test_namespace
- name: galaxy


- name: Rename namespace
ansible.builtin.include_role:
name: namespace
Expand Down Expand Up @@ -120,16 +119,6 @@
ah_path_prefix: "{{ ah_path_prefix }}"
validate_certs: "{{ ah_validate_certs }}"

- name: Add EE Registry
ah_ee_registry:
name: myreg
url: https://registry.redhat.io
ah_host: "{{ ah_hostname }}"
ah_username: "{{ ah_username }}"
ah_password: "{{ ah_password }}"
ah_path_prefix: "{{ ah_path_prefix }}"
validate_certs: "{{ ah_validate_certs }}"

- name: Download Tower tarball
ansible.builtin.get_url:
url: https://galaxy.ansible.com/download/infra-controller_configuration-2.4.0.tar.gz
Expand Down

0 comments on commit 0ff2a0d

Please sign in to comment.