diff options
author | Seth Foster <fosterbseth@gmail.com> | 2024-04-02 21:26:07 +0200 |
---|---|---|
committer | Alan Rominger <arominge@redhat.com> | 2024-04-11 20:59:09 +0200 |
commit | 3bb559dd09642277aef5d610878ba9de6b17c7ac (patch) | |
tree | 35f064e805946c988530e8ef734246a3c9be6023 /awx_collection | |
parent | [RBAC] Fix known issues with backward compatible access_list (#15052) (diff) | |
download | awx-3bb559dd09642277aef5d610878ba9de6b17c7ac.tar.xz awx-3bb559dd09642277aef5d610878ba9de6b17c7ac.zip |
AWX Collections for DAB RBAC
Adds new modules for CRUD operations on the
following endpoints:
- api/v2/role_definitions
- api/v2/role_user_assignments
- api/v2/role_team_assignments
Note: assignment is Create or Delete only
Additional changes:
- Currently DAB endpoints do not have "type"
field on the resource list items. So this modifies
the create_or_update_if_needed to allow manually
specifying item type.
Signed-off-by: Seth Foster <fosterbseth@gmail.com>
Diffstat (limited to 'awx_collection')
-rw-r--r-- | awx_collection/README.md | 3 | ||||
-rw-r--r-- | awx_collection/meta/runtime.yml | 3 | ||||
-rw-r--r-- | awx_collection/plugins/module_utils/controller_api.py | 12 | ||||
-rw-r--r-- | awx_collection/plugins/modules/role_definition.py | 114 | ||||
-rw-r--r-- | awx_collection/plugins/modules/role_team_assignment.py | 123 | ||||
-rw-r--r-- | awx_collection/plugins/modules/role_user_assignment.py | 124 | ||||
-rw-r--r-- | awx_collection/test/awx/conftest.py | 17 | ||||
-rw-r--r-- | awx_collection/test/awx/test_role_definition.py | 122 | ||||
-rw-r--r-- | awx_collection/test/awx/test_role_team_assignment.py | 70 | ||||
-rw-r--r-- | awx_collection/test/awx/test_role_user_assignment.py | 70 | ||||
-rw-r--r-- | awx_collection/tests/integration/targets/role_definition/tasks/main.yml | 30 | ||||
-rw-r--r-- | awx_collection/tests/integration/targets/role_team_assignment/tasks/main.yml | 62 | ||||
-rw-r--r-- | awx_collection/tests/integration/targets/role_user_assignment/tasks/main.yml | 63 |
13 files changed, 807 insertions, 6 deletions
diff --git a/awx_collection/README.md b/awx_collection/README.md index 179ee2b9ea..c3b6f9d529 100644 --- a/awx_collection/README.md +++ b/awx_collection/README.md @@ -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. - 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 + - 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. @@ -112,7 +113,7 @@ Ansible source, set up a dedicated virtual environment: ``` mkvirtualenv my_new_venv -# may need to replace psycopg2 with psycopg2-binary in requirements/requirements.txt +# may need to replace psycopg3 with psycopg3-binary in requirements/requirements.txt pip install -r requirements/requirements.txt -r requirements/requirements_dev.txt -r requirements/requirements_git.txt make clean-api pip install -e <path to your Ansible> diff --git a/awx_collection/meta/runtime.yml b/awx_collection/meta/runtime.yml index 18fa4b592e..7ffdbce161 100644 --- a/awx_collection/meta/runtime.yml +++ b/awx_collection/meta/runtime.yml @@ -35,6 +35,9 @@ action_groups: - project - project_update - role + - role_definition + - role_team_assignment + - role_user_assignment - schedule - settings - subscriptions diff --git a/awx_collection/plugins/module_utils/controller_api.py b/awx_collection/plugins/module_utils/controller_api.py index 166d43c49e..37c784e0a2 100644 --- a/awx_collection/plugins/module_utils/controller_api.py +++ b/awx_collection/plugins/module_utils/controller_api.py @@ -652,7 +652,7 @@ class ControllerAPIModule(ControllerModule): # If we have neither of these, then we can try un-authenticated access self.authenticated = True - def delete_if_needed(self, existing_item, on_delete=None, auto_exit=True): + def delete_if_needed(self, existing_item, item_type=None, on_delete=None, auto_exit=True): # This will exit from the module on its own. # If the method successfully deletes an item and on_delete param is defined, # the on_delete parameter will be called as a method pasing in this object and the json from the response @@ -664,8 +664,9 @@ class ControllerAPIModule(ControllerModule): # If we have an item, we can try to delete it try: item_url = existing_item['url'] - item_type = existing_item['type'] item_id = existing_item['id'] + if not item_type: + item_type = existing_item['type'] item_name = self.get_item_name(existing_item, allow_unknown=True) except KeyError as ke: self.fail_json(msg="Unable to process delete of item due to missing data {0}".format(ke)) @@ -907,7 +908,7 @@ class ControllerAPIModule(ControllerModule): return True return False - def update_if_needed(self, existing_item, new_item, on_update=None, auto_exit=True, associations=None): + def update_if_needed(self, existing_item, new_item, item_type=None, on_update=None, auto_exit=True, associations=None): # This will exit from the module on its own # If the method successfully updates an item and on_update param is defined, # the on_update parameter will be called as a method pasing in this object and the json from the response @@ -921,7 +922,8 @@ class ControllerAPIModule(ControllerModule): # If we have an item, we can see if it needs an update try: item_url = existing_item['url'] - item_type = existing_item['type'] + if not item_type: + item_type = existing_item['type'] if item_type == 'user': item_name = existing_item['username'] elif item_type == 'workflow_job_template_node': @@ -990,7 +992,7 @@ class ControllerAPIModule(ControllerModule): new_item.pop(key) if existing_item: - return self.update_if_needed(existing_item, new_item, on_update=on_update, auto_exit=auto_exit, associations=associations) + return self.update_if_needed(existing_item, new_item, item_type=item_type, on_update=on_update, auto_exit=auto_exit, associations=associations) else: return self.create_if_needed( existing_item, new_item, endpoint, on_create=on_create, item_type=item_type, auto_exit=auto_exit, associations=associations diff --git a/awx_collection/plugins/modules/role_definition.py b/awx_collection/plugins/modules/role_definition.py new file mode 100644 index 0000000000..e226be99a5 --- /dev/null +++ b/awx_collection/plugins/modules/role_definition.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# 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 + + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: role_definition +author: "Seth Foster (@fosterseth)" +short_description: Add role definition to Automation Platform Controller +description: + - Contains a list of permissions and a resource type that can then be assigned to users or teams. +options: + name: + description: + - Name of this role definition. + required: True + type: str + permissions: + description: + - List of permissions to include in the role definition. + required: True + type: list + elements: str + content_type: + description: + - The type of resource this applies to. + required: True + type: str + description: + description: + - Optional description of this role definition. + type: str + state: + description: + - The desired state of the role definition. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: awx.awx.auth +''' + + +EXAMPLES = ''' +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to view and execute jt + state: present +''' + +from ..module_utils.controller_api import ControllerAPIModule + + +def main(): + # Any additional arguments that are not fields of the item can be added here + argument_spec = dict( + name=dict(required=True, type='str'), + permissions=dict(required=True, type='list', elements='str'), + content_type=dict(required=True, type='str'), + description=dict(required=False, type='str'), + state=dict(default='present', choices=['present', 'absent']), + ) + + module = ControllerAPIModule(argument_spec=argument_spec) + + name = module.params.get('name') + permissions = module.params.get('permissions') + content_type = module.params.get('content_type') + description = module.params.get('description') + state = module.params.get('state') + if description is None: + description = '' + + role_definition = module.get_one('role_definitions', name_or_id=name) + + if state == 'absent': + module.delete_if_needed( + role_definition, + item_type='role_definition', + ) + + post_kwargs = { + 'name': name, + 'permissions': permissions, + 'content_type': content_type, + 'description': description + } + + if state == 'present': + module.create_or_update_if_needed( + role_definition, + post_kwargs, + endpoint='role_definitions', + item_type='role_definition', + ) + + +if __name__ == '__main__': + main() diff --git a/awx_collection/plugins/modules/role_team_assignment.py b/awx_collection/plugins/modules/role_team_assignment.py new file mode 100644 index 0000000000..a9d8c62b66 --- /dev/null +++ b/awx_collection/plugins/modules/role_team_assignment.py @@ -0,0 +1,123 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# 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 + + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: role_team_assignment +author: "Seth Foster (@fosterseth)" +short_description: Gives a team permission to a resource or an organization. +description: + - Use this endpoint to give a team permission to a resource or an organization. + - After creation, the assignment cannot be edited, but can be deleted to remove those permissions. +options: + role_definition: + description: + - The name or id of the role definition to assign to the team. + required: True + type: str + object_id: + description: + - Primary key of the object this assignment applies to. + required: True + type: int + team: + description: + - The name or id of the team to assign to the object. + required: False + type: str + object_ansible_id: + description: + - Resource id of the object this role applies to. Alternative to the object_id field. + required: False + type: int + team_ansible_id: + description: + - Resource id of the team who will receive permissions from this assignment. Alternative to team field. + required: False + type: int + state: + description: + - The desired state of the role definition. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: awx.awx.auth +''' + + +EXAMPLES = ''' +- name: Give Team A JT permissions + role_team_assignment: + role_definition: launch JT + object_id: 1 + team: Team A + state: present +''' + +from ..module_utils.controller_api import ControllerAPIModule + + +def main(): + # Any additional arguments that are not fields of the item can be added here + argument_spec = dict( + team=dict(required=False, type='str'), + object_id=dict(required=True, type='int'), + role_definition=dict(required=True, type='str'), + object_ansible_id=dict(required=False, type='int'), + team_ansible_id=dict(required=False, type='int'), + state=dict(default='present', choices=['present', 'absent']), + ) + + module = ControllerAPIModule(argument_spec=argument_spec) + + team = module.params.get('team') + object_id = module.params.get('object_id') + role_definition_str = module.params.get('role_definition') + object_ansible_id = module.params.get('object_ansible_id') + team_ansible_id = module.params.get('team_ansible_id') + state = module.params.get('state') + + role_definition = module.get_one('role_definitions', allow_none=False, name_or_id=role_definition_str) + team = module.get_one('teams', allow_none=False, name_or_id=team) + + kwargs = { + 'role_definition': role_definition['id'], + 'object_id': object_id, + 'team': team['id'], + 'object_ansible_id': object_ansible_id, + 'team_ansible_id': team_ansible_id, + } + + # get rid of None type values + kwargs = {k: v for k, v in kwargs.items() if v is not None} + role_team_assignment = module.get_one('role_team_assignments', **{'data': kwargs}) + + if state == 'absent': + module.delete_if_needed( + role_team_assignment, + item_type='role_team_assignment', + ) + + if state == 'present': + module.create_if_needed( + role_team_assignment, + kwargs, + endpoint='role_team_assignments', + item_type='role_team_assignment', + ) + + +if __name__ == '__main__': + main() diff --git a/awx_collection/plugins/modules/role_user_assignment.py b/awx_collection/plugins/modules/role_user_assignment.py new file mode 100644 index 0000000000..222db14dfc --- /dev/null +++ b/awx_collection/plugins/modules/role_user_assignment.py @@ -0,0 +1,124 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# 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 + + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: role_user_assignment +author: "Seth Foster (@fosterseth)" +short_description: Gives a user permission to a resource or an organization. +description: + - Use this endpoint to give a user permission to a resource or an organization. + - After creation, the assignment cannot be edited, but can be deleted to remove those permissions. +options: + role_definition: + description: + - The name or id of the role definition to assign to the user. + required: True + type: str + object_id: + description: + - Primary key of the object this assignment applies to. + required: True + type: int + user: + description: + - The name or id of the user to assign to the object. + required: False + type: str + object_ansible_id: + description: + - Resource id of the object this role applies to. Alternative to the object_id field. + required: False + type: int + user_ansible_id: + description: + - Resource id of the user who will receive permissions from this assignment. Alternative to user field. + required: False + type: int + state: + description: + - The desired state of the role definition. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: awx.awx.auth +''' + + +EXAMPLES = ''' +- name: Give Bob JT permissions + role_user_assignment: + role_definition: launch JT + object_id: 1 + user: bob + state: present +''' + +from ..module_utils.controller_api import ControllerAPIModule + + +def main(): + # Any additional arguments that are not fields of the item can be added here + argument_spec = dict( + user=dict(required=False, type='str'), + object_id=dict(required=True, type='int'), + role_definition=dict(required=True, type='str'), + object_ansible_id=dict(required=False, type='int'), + user_ansible_id=dict(required=False, type='int'), + state=dict(default='present', choices=['present', 'absent']), + ) + + module = ControllerAPIModule(argument_spec=argument_spec) + + user = module.params.get('user') + object_id = module.params.get('object_id') + role_definition_str = module.params.get('role_definition') + object_ansible_id = module.params.get('object_ansible_id') + user_ansible_id = module.params.get('user_ansible_id') + state = module.params.get('state') + + role_definition = module.get_one('role_definitions', allow_none=False, name_or_id=role_definition_str) + user = module.get_one('users', allow_none=False, name_or_id=user) + + kwargs = { + 'role_definition': role_definition['id'], + 'object_id': object_id, + 'user': user['id'], + 'object_ansible_id': object_ansible_id, + 'user_ansible_id': user_ansible_id, + } + + # get rid of None type values + kwargs = {k: v for k, v in kwargs.items() if v is not None} + + role_user_assignment = module.get_one('role_user_assignments', **{'data': kwargs}) + + if state == 'absent': + module.delete_if_needed( + role_user_assignment, + item_type='role_user_assignment', + ) + + if state == 'present': + module.create_if_needed( + role_user_assignment, + kwargs, + endpoint='role_user_assignments', + item_type='role_user_assignment', + ) + + +if __name__ == '__main__': + main() diff --git a/awx_collection/test/awx/conftest.py b/awx_collection/test/awx/conftest.py index 5bf288ba69..b7fb6333dd 100644 --- a/awx_collection/test/awx/conftest.py +++ b/awx_collection/test/awx/conftest.py @@ -17,6 +17,7 @@ import pytest from ansible.module_utils.six import raise_from +from ansible_base.rbac.models import RoleDefinition, DABPermission from awx.main.tests.functional.conftest import _request from awx.main.tests.functional.conftest import credentialtype_scm, credentialtype_ssh # noqa: F401; pylint: disable=unused-variable from awx.main.models import ( @@ -31,9 +32,11 @@ from awx.main.models import ( WorkflowJobTemplate, NotificationTemplate, Schedule, + Team, ) from django.db import transaction +from django.contrib.contenttypes.models import ContentType HAS_TOWER_CLI = False @@ -259,6 +262,11 @@ def job_template(project, inventory): @pytest.fixture +def team(organization): + return Team.objects.create(name='test-team', organization=organization) + + +@pytest.fixture def machine_credential(credentialtype_ssh, organization): # noqa: F811 return Credential.objects.create(credential_type=credentialtype_ssh, name='machine-cred', inputs={'username': 'test_user', 'password': 'pas4word'}) @@ -332,6 +340,15 @@ def notification_template(organization): @pytest.fixture +def job_template_role_definition(): + rd = RoleDefinition.objects.create(name='test_view_jt', content_type=ContentType.objects.get_for_model(JobTemplate)) + permission_codenames = ['view_jobtemplate', 'execute_jobtemplate'] + permissions = DABPermission.objects.filter(codename__in=permission_codenames) + rd.permissions.add(*permissions) + return rd + + +@pytest.fixture def scm_credential(credentialtype_scm, organization): # noqa: F811 return Credential.objects.create( credential_type=credentialtype_scm, name='scm-cred', inputs={'username': 'optimus', 'password': 'prime'}, organization=organization diff --git a/awx_collection/test/awx/test_role_definition.py b/awx_collection/test/awx/test_role_definition.py new file mode 100644 index 0000000000..b65d0259b9 --- /dev/null +++ b/awx_collection/test/awx/test_role_definition.py @@ -0,0 +1,122 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest + +from ansible_base.rbac.models import RoleDefinition + + +@pytest.mark.django_db +def test_create_new(run_module, admin_user): + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + assert result['changed'] + + role_definition = RoleDefinition.objects.get(name='test_view_jt') + assert role_definition + permission_codenames = [p.codename for p in role_definition.permissions.all()] + assert set(permission_codenames) == set(['view_jobtemplate', 'execute_jobtemplate']) + assert role_definition.content_type.model == 'jobtemplate' + + +@pytest.mark.django_db +def test_update_existing(run_module, admin_user): + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + + assert result['changed'] + + role_definition = RoleDefinition.objects.get(name='test_view_jt') + permission_codenames = [p.codename for p in role_definition.permissions.all()] + assert set(permission_codenames) == set(['view_jobtemplate']) + assert role_definition.content_type.model == 'jobtemplate' + + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + + assert result['changed'] + + role_definition.refresh_from_db() + permission_codenames = [p.codename for p in role_definition.permissions.all()] + assert set(permission_codenames) == set(['view_jobtemplate', 'execute_jobtemplate']) + assert role_definition.content_type.model == 'jobtemplate' + + +@pytest.mark.django_db +def test_delete_existing(run_module, admin_user): + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + + assert result['changed'] + + role_definition = RoleDefinition.objects.get(name='test_view_jt') + assert role_definition + + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + 'state': 'absent', + }, + admin_user) + + assert result['changed'] + + with pytest.raises(RoleDefinition.DoesNotExist): + role_definition.refresh_from_db() + + +@pytest.mark.django_db +def test_idempotence(run_module, admin_user): + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + + assert result['changed'] + + result = run_module( + 'role_definition', + { + 'name': 'test_view_jt', + 'permissions': ['awx.view_jobtemplate', 'awx.execute_jobtemplate'], + 'content_type': 'awx.jobtemplate', + }, + admin_user) + + assert not result['changed'] + + role_definition = RoleDefinition.objects.get(name='test_view_jt') + permission_codenames = [p.codename for p in role_definition.permissions.all()] + assert set(permission_codenames) == set(['view_jobtemplate', 'execute_jobtemplate']) diff --git a/awx_collection/test/awx/test_role_team_assignment.py b/awx_collection/test/awx/test_role_team_assignment.py new file mode 100644 index 0000000000..a20e7261ef --- /dev/null +++ b/awx_collection/test/awx/test_role_team_assignment.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest + +from ansible_base.rbac.models import RoleTeamAssignment + + +@pytest.mark.django_db +def test_create_new(run_module, admin_user, team, job_template, job_template_role_definition): + result = run_module( + 'role_team_assignment', + { + 'team': team.name, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + assert RoleTeamAssignment.objects.filter(team=team, object_id=job_template.id, role_definition=job_template_role_definition).exists() + + +@pytest.mark.django_db +def test_idempotence(run_module, admin_user, team, job_template, job_template_role_definition): + result = run_module( + 'role_team_assignment', + { + 'team': team.name, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + + result = run_module( + 'role_team_assignment', + { + 'team': team.name, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert not result['changed'] + + +@pytest.mark.django_db +def test_delete_existing(run_module, admin_user, team, job_template, job_template_role_definition): + result = run_module( + 'role_team_assignment', + { + 'team': team.name, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + assert RoleTeamAssignment.objects.filter(team=team, object_id=job_template.id, role_definition=job_template_role_definition).exists() + + result = run_module( + 'role_team_assignment', + { + 'team': team.name, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + 'state': 'absent' + }, + admin_user) + assert result['changed'] + assert not RoleTeamAssignment.objects.filter(team=team, object_id=job_template.id, role_definition=job_template_role_definition).exists() diff --git a/awx_collection/test/awx/test_role_user_assignment.py b/awx_collection/test/awx/test_role_user_assignment.py new file mode 100644 index 0000000000..878aa0b587 --- /dev/null +++ b/awx_collection/test/awx/test_role_user_assignment.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest + +from ansible_base.rbac.models import RoleUserAssignment + + +@pytest.mark.django_db +def test_create_new(run_module, admin_user, job_template, job_template_role_definition): + result = run_module( + 'role_user_assignment', + { + 'user': admin_user.username, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + assert RoleUserAssignment.objects.filter(user=admin_user, object_id=job_template.id, role_definition=job_template_role_definition).exists() + + +@pytest.mark.django_db +def test_idempotence(run_module, admin_user, job_template, job_template_role_definition): + result = run_module( + 'role_user_assignment', + { + 'user': admin_user.username, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + + result = run_module( + 'role_user_assignment', + { + 'user': admin_user.username, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert not result['changed'] + + +@pytest.mark.django_db +def test_delete_existing(run_module, admin_user, job_template, job_template_role_definition): + result = run_module( + 'role_user_assignment', + { + 'user': admin_user.username, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + }, + admin_user) + assert result['changed'] + assert RoleUserAssignment.objects.filter(user=admin_user, object_id=job_template.id, role_definition=job_template_role_definition).exists() + + result = run_module( + 'role_user_assignment', + { + 'user': admin_user.username, + 'object_id': job_template.id, + 'role_definition': job_template_role_definition.name, + 'state': 'absent' + }, + admin_user) + assert result['changed'] + assert not RoleUserAssignment.objects.filter(user=admin_user, object_id=job_template.id, role_definition=job_template_role_definition).exists() diff --git a/awx_collection/tests/integration/targets/role_definition/tasks/main.yml b/awx_collection/tests/integration/targets/role_definition/tasks/main.yml new file mode 100644 index 0000000000..637566f20d --- /dev/null +++ b/awx_collection/tests/integration/targets/role_definition/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + state: present + register: result + +- assert: + that: + - result is changed + +- name: Delete Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + state: absent + register: result + +- assert: + that: + - result is changed diff --git a/awx_collection/tests/integration/targets/role_team_assignment/tasks/main.yml b/awx_collection/tests/integration/targets/role_team_assignment/tasks/main.yml new file mode 100644 index 0000000000..85ed76d8e4 --- /dev/null +++ b/awx_collection/tests/integration/targets/role_team_assignment/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: Create Team + team: + name: All Stars + organization: Default + +- name: Create Job Template + job_template: + name: Demo Job Template + job_type: run + inventory: Demo Inventory + project: Demo Project + playbook: hello_world.yml + register: job_template + +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + +- name: Create Role Team Assignment + role_team_assignment: + role_definition: test_view_jt + team: All Stars + object_id: "{{ job_template.id }}" + register: result + +- assert: + that: + - result is changed + +- name: Delete Role Team Assigment + role_team_assignment: + role_definition: test_view_jt + team: All Stars + object_id: "{{ job_template.id }}" + state: absent + register: result + +- assert: + that: + - result is changed + +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + state: absent + +- name: Delete Team + team: + name: All Stars + organization: Default + state: absent diff --git a/awx_collection/tests/integration/targets/role_user_assignment/tasks/main.yml b/awx_collection/tests/integration/targets/role_user_assignment/tasks/main.yml new file mode 100644 index 0000000000..897a0ce156 --- /dev/null +++ b/awx_collection/tests/integration/targets/role_user_assignment/tasks/main.yml @@ -0,0 +1,63 @@ +--- +- name: Create User + user: + username: testing_user + first_name: testing + last_name: user + password: password + +- name: Create Job Template + job_template: + name: Demo Job Template + job_type: run + inventory: Demo Inventory + project: Demo Project + playbook: hello_world.yml + register: job_template + +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + +- name: Create Role User Assignment + role_user_assignment: + role_definition: test_view_jt + user: testing_user + object_id: "{{ job_template.id }}" + register: result + +- assert: + that: + - result is changed + +- name: Delete Role User Assigment + role_user_assignment: + role_definition: test_view_jt + user: testing_user + object_id: "{{ job_template.id }}" + state: absent + register: result + +- assert: + that: + - result is changed + +- name: Create Role Definition + role_definition: + name: test_view_jt + permissions: + - awx.view_jobtemplate + - awx.execute_jobtemplate + content_type: awx.jobtemplate + description: role definition to launch job + state: absent + +- name: Delete User + user: + username: testing_user + state: absent |