Skip to content

Commit

Permalink
feat: add sync to project module
Browse files Browse the repository at this point in the history
Signed-off-by: Alex <[email protected]>
  • Loading branch information
Alex-Izquierdo committed Oct 3, 2024
1 parent a219695 commit 1299d3a
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 28 deletions.
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace: ansible
name: eda

# The version of the collection. Must be compatible with semantic versioning
version: 2.1.0
version: 2.2.0

# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md
Expand Down
2 changes: 1 addition & 1 deletion plugins/module_utils/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def get(self, path: str, **kwargs: str) -> Response:

def post(self, path: str, **kwargs: Any) -> Response:
resp = self.request("POST", path, **kwargs)
if resp.status == 201:
if resp.status in [201, 202]:
return resp
raise EDAHTTPError(f"HTTP error {resp.json}")

Expand Down
25 changes: 21 additions & 4 deletions plugins/module_utils/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ def get_exactly_one(
return {}
if len(result) > 1:
if name:
# Since we did a name or ID search and got > 1 return
# something if the id matches
# Since we did a name search and got > 1 return
# something if the name matches
for asset in result:
if str(asset["id"]) == name:
if str(asset["name"]) == name:
return asset
# We got > 1 and either didn't find something by ID (which means
# We got > 1 and either didn't find something by name (which means
# multiple names)
# Or we weren't running with a or search and just got back too
# many to begin with.
Expand Down Expand Up @@ -184,6 +184,23 @@ def create_if_needed(
msg = f"Unable to create {item_type} {item_name}: {response.status}"
raise EDAError(msg)

def create(
self, new_item: dict[str, Any], endpoint: str, item_type: str = "unknown"
) -> dict[str, bool]:
"""Run a create (post) operation unconditionally and return the result."""

response = self.post_endpoint(endpoint, data=new_item)

Check warning on line 192 in plugins/module_utils/controller.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/controller.py#L192

Added line #L192 was not covered by tests

if response.status in [201, 202]:
self.result["changed"] = True
return self.result

Check warning on line 196 in plugins/module_utils/controller.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/controller.py#L195-L196

Added lines #L195 - L196 were not covered by tests

error_msg = f"Unable to create {item_type} {new_item}: {response.status} {response.data}"

Check warning on line 198 in plugins/module_utils/controller.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/controller.py#L198

Added line #L198 was not covered by tests
if response.json:
error_msg = f"Unable to create {item_type} {new_item}: {response.json}"

Check warning on line 200 in plugins/module_utils/controller.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/controller.py#L200

Added line #L200 was not covered by tests

raise EDAError(error_msg)

Check warning on line 202 in plugins/module_utils/controller.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/controller.py#L202

Added line #L202 was not covered by tests

def _encrypted_changed_warning(
self, field: str, old: dict[str, Any], warning: bool = False
) -> None:
Expand Down
54 changes: 40 additions & 14 deletions plugins/modules/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
default: "present"
choices: ["present", "absent"]
type: str
sync:
description:
- Triggers the synchronization of the project.
- This only takes effect when the project already exists.
type: bool
default: False
version_added: 2.2.0
extends_documentation_fragment:
- ansible.eda.eda_controller.auths
"""
Expand Down Expand Up @@ -110,15 +117,12 @@ def main() -> None:
credential=dict(),
organization_name=dict(type="str", aliases=["organization"]),
state=dict(choices=["present", "absent"], default="present"),
sync=dict(type="bool", default=False),
)

argument_spec.update(AUTH_ARGSPEC)

required_if = [("state", "present", ("name", "url"))]

module = AnsibleModule(
argument_spec=argument_spec, required_if=required_if, supports_check_mode=True
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

client = Client(
host=module.params.get("controller_host"),
Expand All @@ -136,24 +140,35 @@ def main() -> None:
)
state = module.params.get("state")
organization_name = module.params.get("organization_name")
project_name = module.params.get("name")
url = module.params.get("url")
sync_enabled = module.params.get("sync")
project_type = {}

try:
project_type = controller.get_exactly_one(project_endpoint, name=project_name)
except EDAError as eda_err:
module.fail_json(msg=str(eda_err))

if state == "present":
if config_endpoint_avail.status not in (404,) and organization_name is None:
if not project_type and not url:
module.fail_json(
msg="Parameter url is required when state is present and project does not exist"
)
if (
config_endpoint_avail.status not in (404,)
and organization_name is None
and not project_type
):
module.fail_json(
msg="Parameter organization_name is required when state is present"
msg="Parameter organization_name is required when state is present and project does not exist"
)

project_name = module.params.get("name")
new_name = module.params.get("new_name")
description = module.params.get("description")
url = module.params.get("url")
credential = module.params.get("credential")
ret = {}

try:
project_type = controller.get_exactly_one(project_endpoint, name=project_name)
except EDAError as eda_err:
module.fail_json(msg=str(eda_err))

if state == "absent":
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
try:
Expand Down Expand Up @@ -208,6 +223,17 @@ def main() -> None:
except EDAError as eda_err:
module.fail_json(msg=str(eda_err))

if sync_enabled and project_type:
sync_endpoint = f"{project_endpoint}/{ret['id']}/sync"
try:
controller.create(
{"name": project_type_params["name"]},
endpoint=sync_endpoint,
item_type="sync",
)
except EDAError as eda_err:
module.fail_json(msg=str(eda_err))

module.exit_json(**ret)


Expand Down
34 changes: 34 additions & 0 deletions tests/integration/targets/project/tasks/create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,37 @@
assert:
that:
- r.changed

- name: Check create project with partial name match
loop:
- "{{ project_name }}_test_partial"
- "{{ project_name }}"
ansible.eda.project:
name: "{{ item }}"
url: "{{ url }}"
description: "Example project description"
organization_name: Default
state: present

- name: Delete project with partial name match
loop:
- "{{ project_name }}"
- "{{ project_name }}_test_partial"
ansible.eda.project:
name: "{{ item }}"
state: absent

- name: Check create project with missing url
ansible.eda.project:
name: "{{ project_name }}"
description: "Example project description"
organization_name: Default
state: present
register: r
ignore_errors: true

- name: Check if missing url is required
assert:
that:
- r.failed
- "'Parameter url is required' in r.msg"
7 changes: 0 additions & 7 deletions tests/integration/targets/project/tasks/delete.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

- name: Delete operation without required name parameter
ansible.eda.project:
controller_host: "{{ controller_host }}"
controller_username: "{{ controller_username }}"
controller_password: "{{ controller_password }}"
state: absent
ignore_errors: true
register: r
Expand All @@ -19,10 +16,6 @@

- name: Delete non-existing project in check mode
ansible.eda.project:
controller_host: "{{ controller_host }}"
controller_username: "{{ controller_username }}"
controller_password: "{{ controller_password }}"
validate_certs: "{{ controller_verify_ssl }}"
name: "{{ project_name }}"
state: absent
check_mode: true
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/targets/project/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
- name: Define variables for credential and decision environment
set_fact:
project_name: "test_project_{{ test_id }}"
url: "https://example.com/ansible/eda-server"
url: "https://github.com/ansible/eda-sample-project"

- include_tasks: create.yml
- include_tasks: delete.yml
- include_tasks: update.yml
- include_tasks: sync.yml
always:
- name: Clean up - project
ansible.eda.project:
Expand Down
86 changes: 86 additions & 0 deletions tests/integration/targets/project/tasks/sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
# Copyright: Contributors to the Ansible project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

- name: Create non existing project with sync
block:
- name: Create non existing project with sync
ansible.eda.project:
name: "{{ project_name }}_test_sync"
url: "{{ url }}"
description: "Example project description"
organization_name: Default
state: present
sync: true
register: r

- name: Check project creation
assert:
that:
- r.changed
always:
- name: Clean up - project
ansible.eda.project:
name: "{{ project_name }}_test_sync"
state: absent
ignore_errors: true

- name: Sync existing project
block:
- name: Create project before sync
ansible.eda.project:
name: "{{ project_name }}_test_sync"
url: "{{ url }}"
description: "Example project description"
organization_name: Default
state: present
register: r

# need to wait for project creation otherwise sync can fail
- name: Wait for project creation
pause:
seconds: 5

- name: Sync project
ansible.eda.project:
name: "{{ project_name }}_test_sync"
sync: true
register: r

- name: Get info project after sync
ansible.eda.project_info:
name: "{{ project_name }}_test_sync"
register: r_info

- name: Check project sync
assert:
that:
- r.changed
- r_info.projects[0].modified_at != r_info.projects[0].created_at
always:
- name: Clean up - project
ansible.eda.project:
name: "{{ project_name }}_test_sync"
state: absent
ignore_errors: true

- name: Check wrong parameters with sync enabled
block:
- name: Try to sync non existing project without url
ansible.eda.project:
name: "{{ project_name }}_test_sync"
sync: true
register: r
ignore_errors: true

- name: Check if sync non existing project without url
assert:
that:
- r.failed
- "'Parameter url is required' in r.msg"
always:
- name: Clean up - project
ansible.eda.project:
name: "{{ project_name }}_test_sync"
state: absent
ignore_errors: true

0 comments on commit 1299d3a

Please sign in to comment.