Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate ah_collection #5

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ requires_ansible: ">=2.15.0" # AAP 2.4 or newer
action_groups:
hub:
- ah_namespace
- ah_collection
233 changes: 233 additions & 0 deletions plugins/modules/ah_collection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2020, Sean Sullivan <@sean-m-sullivan>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type


DOCUMENTATION = """
---
module: ah_collection
author:
- Sean Sullivan (@sean-m-sullivan)
- Tom Page (@Tompage1994)
short_description: Update, or destroy Automation Hub Collections
description:
- Upload, or destroy Automation Hub Collections.
options:
namespace:
description:
- Namespace name.
- Must be lower case containing only alphanumeric characters and underscores.
required: True
type: str
name:
description:
- Collection name.
- Must be lower case containing only alphanumeric characters and underscores.
required: True
type: str
version:
description:
- Collection Version.
- Must be lower case containing only alphanumeric characters and underscores.
type: str
path:
description:
- Collection artifact file path.
- If version is not specified, version will be derived from the file name.
type: str
repository:
description:
- Name of the destination collection for the repository (staging for uploads).
type: str
default: 'staging'
wait:
description:
- Waits for the collection to be uploaded.
type: bool
default: true
auto_approve:
description:
- Approves a collection.
- Requires version to be set.
type: bool
default: true
interval:
description:
- The interval to request an update from Automation Hub when waiting for the approval.
required: False
default: 10
type: float
timeout:
description:
- Waiting for the approval will abort after this amount of seconds.
type: int
overwrite_existing:
description:
- Overwrites an existing collection.
- Requires version to be set.
type: bool
default: false
state:
description:
- Desired state of the resource.
- If present with a path, will upload a collection artifact to Automation hub.
- If present will return data on a collection.
- If present with version, will return data on a collection version.
- If absent without version, will delete the collection and all versions.
- If absent with version, will delete only specified version.
choices: ["present", "absent"]
default: "present"
type: str

extends_documentation_fragment: ansible.hub.auth
"""


EXAMPLES = """
- name: Upload collection to Automation Hub
ansible.hub.ah_collection:
namespace: awx
name: awx
path: /var/tmp/collections/awx-awx-15.0.0.tar.gz

- name: Remove collection from Automation Hub
ansible.hub.ah_collection:
namespace: test_collection
name: test
version: 4.1.2
state: absent
"""

import pathlib

from ..module_utils.ah_module import AHModule


def main():
# Any additional arguments that are not fields of the item can be added here
argument_spec = dict(
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"),
auto_approve=dict(type="bool", default=True),
overwrite_existing=dict(type="bool", default=False),
version=dict(),
state=dict(choices=["present", "absent"], default="present"),
)

# Create a module for ourselves
module = AHModule(argument_spec=argument_spec)

# Extract our parameters
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")
overwrite_existing = module.params.get("overwrite_existing")
auto_approve = module.params.get("auto_approve")
version = module.params.get("version")
state = module.params.get("state")

# approval needs a version, if one is not defined find it from the filename.
if auto_approve and path:
version = "-".join(path.split("-")[2:]).replace('.tar.gz', '')

# Attempt to look up an existing item based on the provided data
collection_endpoint = "collections/{0}/{1}".format(namespace, name)
if version:
collection_endpoint = "{0}/versions/{1}".format(collection_endpoint, version)

existing_item = module.get_endpoint(collection_endpoint, **{"return_none_on_404": True})

# If state is absent, check if it exists, delete and exit.
if state == "absent":
if existing_item is None:
module.json_output["deleted"] = False
module.json_output["changed"] = False
else:
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
module.json_output["task"] = module.delete_endpoint(existing_item["json"]["href"])["json"]["task"]
module.json_output["deleted"] = True
module.json_output["changed"] = True
module.exit_json(**module.json_output)
else:
file = pathlib.Path(path)
if not file.exists():
module.fail_json(msg="Could not find Collection {0}.{1} in path {2}".format(namespace, name, path))

if path:
if existing_item is not None and overwrite_existing:
# Delete collection
module.json_output["task"] = module.delete_endpoint(existing_item["json"]["href"])["json"]["task"]
module.json_output["deleted"] = True
module.wait_for_complete(module.json_output["task"])
# Upload new collection
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})
if auto_approve:
module.approve(
endpoint=collection_endpoint,
timeout=timeout,
interval=interval,
namespace=namespace,
name=name,
version=version
)
elif existing_item is None:
module.upload(path, "artifacts/collections", wait, repository, item_type="collections")
module.json_output["changed"] = True
if auto_approve:
module.approve(
endpoint=collection_endpoint,
timeout=timeout,
interval=interval,
namespace=namespace,
name=name,
version=version
)
else:
module.json_output["changed"] = False
else:
if existing_item is None and state == "absent":
module.json_output["deleted"] = False
module.json_output["changed"] = False
elif existing_item is None:
msg = "Could not find Collection {0}.{1}".format(namespace, name)
if version:
module.fail_json(msg="{0} with version {1}".format(msg, version))
else:
module.fail_json(msg=msg)
else:
module.json_output["collection"] = existing_item["json"]

# If state is absent, check if it exists, delete and exit.
if state == "absent":
if existing_item is None:
module.json_output["deleted"] = False
module.json_output["changed"] = False
else:
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
module.json_output["task"] = module.delete_endpoint(existing_item["json"]["href"])["json"]["task"]
module.json_output["deleted"] = True
module.json_output["changed"] = True

# If the state was present and we can Return information about the collection
module.exit_json(**module.json_output)


if __name__ == "__main__":
main()
Loading