Skip to content

Commit 1f53e24

Browse files
committed
Convert pulp-container-content into an Ansible module
This should execute more quickly than Ansible tasks.
1 parent 1fe546e commit 1f53e24

File tree

6 files changed

+217
-81
lines changed

6 files changed

+217
-81
lines changed

ansible/dev-pulp-container-promote.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@
4848
{%- if image not in kolla_unbuildable_images[base_distro]-%}
4949
{%- set src_image_repo = "stackhpc-dev/" ~ base_distro ~ "-source-" ~ image -%}
5050
{%- set dest_image_repo = "stackhpc/" ~ base_distro ~ "-source-" ~ image -%}
51-
{%- set content = {"src_repo": src_image_repo, "src_is_push": true, "dest_repo": dest_image_repo, "tags": [dev_pulp_repository_container_promotion_tag]} -%}
51+
{%- set content = {
52+
"allow_missing": True,
53+
"src_repo": src_image_repo,
54+
"src_is_push": true,
55+
"repository": dest_image_repo,
56+
"tags": [dev_pulp_repository_container_promotion_tag],
57+
} -%}
5258
{%- set _ = contents.append(content) -%}
5359
{%- endif -%}
5460
{%- endfor -%}

ansible/roles/pulp-container-content/README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ Role variables
1111
* `pulp_url`: URL of Pulp server. Default is `https://localhost:8080`
1212
* `pulp_username`: Username used to access Pulp server. Default is `admin`
1313
* `pulp_password`: Password used to access Pulp server. Default is unset
14+
* `pulp_validate_certs`: Whether to validate certificates. Default is `true`.
1415
* `pulp_container_content`: List of content to add or remove. Each item is a dict with the following keys:
1516

16-
* `src_repo`: Name of the repository to copy from when `state` is `present`,
17+
* `allow_missing`: Whether to ignore missing tags in the source repository
18+
when `state` is `present`.
19+
* `repository`: Name of the repository to copy to when `state is `present`
1720
or the repository to remove from when `state` is `absent`.
21+
* `src_repo`: Name of the repository to copy from when `state` is `present`.
1822
* `src_is_push`: Whether `src_repo` is a push repository. Default is `false`.
19-
* `dest_repo`: Name of the repository to copy to when `state is `present`.
20-
* `tags`: List of names of tags to add or remove.
2123
* `state`: Whether to add (`present`) or remove (`absent`) content.
24+
* `tags`: List of names of tags to add or remove.
2225

2326
Example playbook
2427
----------------
@@ -37,12 +40,12 @@ Example playbook
3740
# Copy tag1 and tag2 from repo1 to repo2
3841
- src_repo: repo1
3942
src_is_push: true
40-
dest_repo: repo2
43+
repository: repo2
4144
tags:
4245
- tag1
4346
- tag2
4447
# Remove tag3 from repo3
45-
- src_repo: repo3
48+
- repository: repo3
4649
tags:
4750
- tag3
4851
state: absent

ansible/roles/pulp-container-content/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
pulp_url: https://localhost:8080
33
pulp_username: admin
44
pulp_password:
5+
pulp_validate_certs: true
56

67
pulp_container_content: []
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
from __future__ import absolute_import, division, print_function
5+
6+
__metaclass__ = type
7+
8+
9+
DOCUMENTATION = r"""
10+
---
11+
module: pulp_container_content
12+
short_description: Manage container content of a pulp api server instance
13+
description:
14+
- "This performs CRUD operations on container content in a pulp api server instance."
15+
options:
16+
allow_missing:
17+
description:
18+
- Whether to allow missing tags when state is present.
19+
type: bool
20+
default: false
21+
src_repo:
22+
description:
23+
- Name of the repository to copy content from when state is present.
24+
type: str
25+
src_is_push:
26+
description:
27+
- Whether src_repo is a container-push repository.
28+
type: bool
29+
default: false
30+
repository:
31+
description:
32+
- Name of the repository to add or remove content
33+
type: str
34+
required: true
35+
tags:
36+
description:
37+
- List of tags to add or remove
38+
type: list
39+
items: str
40+
required: true
41+
extends_documentation_fragment:
42+
- pulp.squeezer.pulp
43+
- pulp.squeezer.pulp.entity_state
44+
author:
45+
- Mark Goddard (@markgoddard)
46+
"""
47+
48+
EXAMPLES = r"""
49+
- name: Copy tag1 and tag2 from repo1 to repo2
50+
pulp_container_content:
51+
pulp_url: https://pulp.example.org
52+
username: admin
53+
password: password
54+
repository: repo2
55+
src_repo: repo1
56+
tags:
57+
- tag1
58+
- tag2
59+
60+
- name: Remove tag3 from repo3
61+
pulp_container_content:
62+
pulp_url: https://pulp.example.org
63+
username: admin
64+
password: password
65+
repository: repo3
66+
tags:
67+
- tag3
68+
state: absent
69+
"""
70+
71+
RETURN = r"""
72+
repository_version:
73+
description: Created container repository version
74+
type: dict
75+
returned: when content is added or removed
76+
"""
77+
78+
79+
from ansible_collections.pulp.squeezer.plugins.module_utils.pulp import (
80+
PAGE_LIMIT,
81+
PulpContainerRepository,
82+
PulpEntity,
83+
PulpEntityAnsibleModule,
84+
PulpTask,
85+
SqueezerException,
86+
)
87+
88+
89+
class PulpContainerRepositoryContent(PulpContainerRepository):
90+
_add_id = "repositories_container_container_add"
91+
_remove_id = "repositories_container_container_remove"
92+
_container_tags_list_id = "content_container_tags_list"
93+
94+
_name_singular = "repository_version"
95+
96+
def get_src_repo(self):
97+
# Query source repository.
98+
natural_key = {"name": self.module.params["src_repo"]}
99+
repo = PulpContainerRepository(self.module, natural_key)
100+
if self.module.params["state"] == "present" and self.module.params["src_is_push"]:
101+
repo._list_id = "repositories_container_container_push_list"
102+
# find populates repo.entity.
103+
repo.find(failsafe=False)
104+
return repo
105+
106+
def get_content_units(self, repo):
107+
# Query container tags with matching names in repo.
108+
# Pagination code adapted from PulpEntity.list().
109+
tags = []
110+
offset = 0
111+
search_result = {"next": True}
112+
while search_result["next"]:
113+
parameters = {
114+
"limit": PAGE_LIMIT,
115+
"offset": offset,
116+
"name__in": ",".join(self.module.params["tags"]),
117+
"repository_version": repo.entity["latest_version_href"]
118+
}
119+
search_result = self.module.pulp_api.call(
120+
self._container_tags_list_id, parameters=parameters
121+
)
122+
tags.extend(search_result["results"])
123+
offset += PAGE_LIMIT
124+
125+
if (self.module.params["state"] == "present" and
126+
not self.module.params["allow_missing"] and
127+
len(tags) != len(self.module.params["tags"])):
128+
missing = ", ".join(set(self.module.params["tags"]) - set(tags))
129+
raise SqueezerException(f"Some tags not found in source repository: {missing}")
130+
return [result["pulp_href"] for result in tags]
131+
132+
def add_or_remove(self, add_or_remove_id, content_units):
133+
body = {"content_units": content_units}
134+
if not self.module.check_mode:
135+
parameters = {"container_container_repository_href": self.entity["pulp_href"]}
136+
response = self.module.pulp_api.call(
137+
add_or_remove_id, body=body, uploads=self.uploads, parameters=parameters
138+
)
139+
if response and "task" in response:
140+
task = PulpTask(self.module, {"pulp_href": response["task"]}).wait_for()
141+
# Adding or removing content results in creation of a new repository version
142+
if task["created_resources"]:
143+
self.entity = {"pulp_href": task["created_resources"][0]}
144+
self.module.set_changed()
145+
else:
146+
self.entity = None
147+
else:
148+
self.entity = response
149+
else:
150+
# Assume changed in check mode
151+
self.module.set_changed()
152+
153+
def add(self):
154+
src_repo = self.get_src_repo()
155+
self.add_or_remove(self._add_id, self.get_content_units(src_repo))
156+
157+
def remove(self):
158+
self.add_or_remove(self._remove_id, self.get_content_units(self))
159+
160+
def process(self):
161+
# Populate self.entity.
162+
self.find(failsafe=False)
163+
if self.module.params["state"] == "present":
164+
response = self.add()
165+
elif self.module.params["state"] == "absent":
166+
response = self.remove()
167+
else:
168+
raise SqueezerException("Unexpected state")
169+
self.module.set_result(self._name_singular, self.presentation(self.entity))
170+
171+
172+
def main():
173+
with PulpEntityAnsibleModule(
174+
argument_spec=dict(
175+
allow_missing={"type": "bool", "default": False},
176+
repository={"required": True},
177+
src_repo={},
178+
src_is_push={"type": "bool", "default": False},
179+
state={"default": "present"},
180+
tags={"type": "list", "item": "str", "required": True},
181+
),
182+
required_if=[("state", "present", ["src_repo"])],
183+
) as module:
184+
natural_key = {"name": module.params["repository"]}
185+
PulpContainerRepositoryContent(module, natural_key).process()
186+
187+
188+
if __name__ == "__main__":
189+
main()

ansible/roles/pulp-container-content/tasks/content.yml

Lines changed: 0 additions & 73 deletions
This file was deleted.
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
---
2-
- name: Include content.yml
3-
include_tasks: content.yml
2+
- name: Add or remove content units
3+
pulp_container_content:
4+
pulp_url: "{{ pulp_url }}"
5+
username: "{{ pulp_username }}"
6+
password: "{{ pulp_password }}"
7+
validate_certs: "{{ pulp_validate_certs | bool }}"
8+
allow_missing: "{{ item.allow_missing | default(omit) }}"
9+
src_repo: "{{ item.src_repo | default(omit) }}"
10+
src_is_push: "{{ item.src_is_push | default(omit) }}"
11+
repository: "{{ item.repository }}"
12+
tags: "{{ item.tags }}"
13+
state: "{{ item.state | default(omit) }}"
414
loop: "{{ pulp_container_content }}"

0 commit comments

Comments
 (0)