From 2f0f692f4a2758a2d3dc8c2b6c21c5affd39906a Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Fri, 30 Aug 2019 17:11:01 -0400 Subject: [PATCH] Integrate Ansible core tower modules content into AWX This commit includes all the changes involved in converting the old Ansible Tower modules from commits in Ansible core into the AWX collection that replaces it. Also includes work needed to integrate it into the AWX processes like tests, docs, and the Makefile. Apply changes from content_collector tool Add integrated module tests operate via run_module fixture add makefile target for them Add flake8 target and fix flake8 errors Update README Make consolidated target for testing modules --- .gitignore | 4 + Makefile | 24 ++++ awx_modules/README.md | 52 ++++++++ awx_modules/galaxy.yml | 16 +++ .../plugins/modules/tower_credential.py | 2 +- .../plugins/modules/tower_credential_type.py | 2 +- awx_modules/plugins/modules/tower_group.py | 2 +- awx_modules/plugins/modules/tower_host.py | 2 +- .../plugins/modules/tower_inventory.py | 2 +- .../plugins/modules/tower_inventory_source.py | 2 +- .../plugins/modules/tower_job_cancel.py | 2 +- .../plugins/modules/tower_job_launch.py | 2 +- awx_modules/plugins/modules/tower_job_list.py | 2 +- .../plugins/modules/tower_job_template.py | 2 +- awx_modules/plugins/modules/tower_job_wait.py | 4 +- awx_modules/plugins/modules/tower_label.py | 2 +- .../plugins/modules/tower_notification.py | 2 +- .../plugins/modules/tower_organization.py | 2 +- awx_modules/plugins/modules/tower_project.py | 8 +- awx_modules/plugins/modules/tower_receive.py | 2 +- awx_modules/plugins/modules/tower_role.py | 2 +- awx_modules/plugins/modules/tower_send.py | 4 +- awx_modules/plugins/modules/tower_settings.py | 2 +- awx_modules/plugins/modules/tower_team.py | 2 +- awx_modules/plugins/modules/tower_user.py | 2 +- .../plugins/modules/tower_workflow_launch.py | 2 +- .../modules/tower_workflow_template.py | 3 +- awx_modules/setup.cfg | 3 + awx_modules/test/awx/conftest.py | 121 ++++++++++++++++++ awx_modules/test/awx/test_job_template.py | 59 +++++++++ awx_modules/test/awx/test_organization.py | 25 ++++ setup.cfg | 2 +- 32 files changed, 333 insertions(+), 30 deletions(-) create mode 100644 awx_modules/README.md create mode 100644 awx_modules/galaxy.yml create mode 100644 awx_modules/setup.cfg create mode 100644 awx_modules/test/awx/conftest.py create mode 100644 awx_modules/test/awx/test_job_template.py create mode 100644 awx_modules/test/awx/test_organization.py diff --git a/.gitignore b/.gitignore index 778ea02004..2352b56baf 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,7 @@ venv/* use_dev_supervisor.txt .idea/* + +# Ansible module tests +awx_modules_test_venv/ +awx-awx-*.tar.gz diff --git a/Makefile b/Makefile index 7e8c6362df..01b42653b9 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ COMPOSE_TAG ?= $(GIT_BRANCH) COMPOSE_HOST ?= $(shell hostname) VENV_BASE ?= /venv +MODULES_VENV ?= /awx_devel/awx_modules_test_venv SCL_PREFIX ?= CELERY_SCHEDULE_FILE ?= /var/lib/awx/beat.db @@ -373,8 +374,31 @@ test: fi; \ PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS) cd awxkit && $(VENV_BASE)/awx/bin/tox -re py2,py3 + make test_modules_all awx-manage check_migrations --dry-run --check -n 'vNNN_missing_migration_file' +prepare_modules_venv: + cd /awx_devel + rm -rf $(MODULES_VENV) + mkdir $(MODULES_VENV) + ln -s /usr/lib/python2.7/site-packages/ansible $(MODULES_VENV)/ansible + $(VENV_BASE)/awx/bin/pip install --target=$(MODULES_VENV) git+https://github.com/ansible/tower-cli.git + +MODULES_TEST_DIRS ?= awx_modules/test/awx + +test_modules: + @if [ "$(VENV_BASE)" ]; then \ + . $(VENV_BASE)/awx/bin/activate; \ + fi; \ + PYTHONPATH=$(MODULES_VENV):/awx_devel/awx_modules:$PYTHONPATH py.test $(MODULES_TEST_DIRS) + +flake8_modules: + flake8 awx_modules/ # Different settings, in main exclude list + +prepare_test_modules: prepare_modules_venv test_modules # deprecated + +test_modules_all: prepare_modules_venv test_modules flake8_modules + test_unit: @if [ "$(VENV_BASE)" ]; then \ . $(VENV_BASE)/awx/bin/activate; \ diff --git a/awx_modules/README.md b/awx_modules/README.md new file mode 100644 index 0000000000..f3118c3a1c --- /dev/null +++ b/awx_modules/README.md @@ -0,0 +1,52 @@ +# AWX Ansible Modules + +These modules allow for easy interaction with an AWX or Ansible Tower server +in Ansible playbooks. + +The previous home for these modules was in https://github.com/ansible/ansible +inside the folder `lib/ansible/modules/web_infrastructure/ansible_tower`. + +## Running + +To use these modules, the "old" tower-cli needs to be installed +in the virtual environment where the modules run. +You can install it from either: + + - https://github.com/ansible/tower-cli/ + - https://pypi.org/project/ansible-tower-cli/ + +To use these modules in AWX, you should create a custom virtual environment +to install the requirement into. NOTE: you will also probably still need +to set the job template extra_vars to include `ansible_python_interpreter` +to be the python in that virtual environment. + +## Running Tests + +Tests to verify compatibility with the most recent AWX code exist +in `awx_modules/test/awx`. These tests require that python packages +are available for all of `awx`, `ansible`, `tower_cli`, and the modules +themselves. + +The target `make prepare_modules_venv` will prepare some requirements +in the `awx_modules_test_venv` folder so that `make test_modules` can +be ran to actually run the tests. A single test can be ran via: + +``` +make test_modules MODULE_TEST_DIRS=awx_modules/test/awx/test_organization.py +``` + +## Building + +To build, you should not be in the AWX virtual environment. +This should work on any machine that has a sufficiently recent version +of Ansible installed. + +``` +cd awx_modules +ansible-galaxy build +``` + +This will leave a tar file in the awx_modules directory. + +This process may be amended in the future to template components of `galaxy.yml` +from values (such as version) taken from AWX. diff --git a/awx_modules/galaxy.yml b/awx_modules/galaxy.yml new file mode 100644 index 0000000000..257e9168d4 --- /dev/null +++ b/awx_modules/galaxy.yml @@ -0,0 +1,16 @@ +authors: +- Wayne Witzel III (@wwitzel3) +- Chris Meyers +dependencies: {} +description: Ansible modules that interact with the AWX API. +documentation: https://docs.ansible.com/ansible/latest/modules/list_of_web_infrastructure_modules.html#ansible-tower +homepage: https://ansible.com +issues: https://github.com/ansible/awx/issues +license: +- GPL-3.0-only +name: awx +namespace: awx +readme: README.md +repository: https://github.com/ansible/awx +tags: [] +version: 0.0.1 diff --git a/awx_modules/plugins/modules/tower_credential.py b/awx_modules/plugins/modules/tower_credential.py index 8f8b41badf..aac3d9406a 100644 --- a/awx_modules/plugins/modules/tower_credential.py +++ b/awx_modules/plugins/modules/tower_credential.py @@ -190,7 +190,7 @@ EXAMPLES = ''' import os from ansible.module_utils._text import to_text -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_credential_type.py b/awx_modules/plugins/modules/tower_credential_type.py index 831a35ad3f..d8b97ccc08 100644 --- a/awx_modules/plugins/modules/tower_credential_type.py +++ b/awx_modules/plugins/modules/tower_credential_type.py @@ -87,7 +87,7 @@ EXAMPLES = ''' RETURN = ''' # ''' -from ansible.module_utils.ansible_tower import ( +from ..module_utils.ansible_tower import ( TowerModule, tower_auth_config, tower_check_mode diff --git a/awx_modules/plugins/modules/tower_group.py b/awx_modules/plugins/modules/tower_group.py index 666b7386b8..8df1a73221 100644 --- a/awx_modules/plugins/modules/tower_group.py +++ b/awx_modules/plugins/modules/tower_group.py @@ -93,7 +93,7 @@ EXAMPLES = ''' import os -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_host.py b/awx_modules/plugins/modules/tower_host.py index 6fd411a636..c6011ab27b 100644 --- a/awx_modules/plugins/modules/tower_host.py +++ b/awx_modules/plugins/modules/tower_host.py @@ -66,7 +66,7 @@ EXAMPLES = ''' import os -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode, HAS_TOWER_CLI +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_inventory.py b/awx_modules/plugins/modules/tower_inventory.py index c709ab7c8a..20eaa19b0f 100644 --- a/awx_modules/plugins/modules/tower_inventory.py +++ b/awx_modules/plugins/modules/tower_inventory.py @@ -67,7 +67,7 @@ EXAMPLES = ''' ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_inventory_source.py b/awx_modules/plugins/modules/tower_inventory_source.py index 9aec7a8b95..063eeeea81 100644 --- a/awx_modules/plugins/modules/tower_inventory_source.py +++ b/awx_modules/plugins/modules/tower_inventory_source.py @@ -166,7 +166,7 @@ EXAMPLES = ''' RETURN = ''' # ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_job_cancel.py b/awx_modules/plugins/modules/tower_job_cancel.py index 02fa3b7b19..1a658f02f5 100644 --- a/awx_modules/plugins/modules/tower_job_cancel.py +++ b/awx_modules/plugins/modules/tower_job_cancel.py @@ -55,7 +55,7 @@ status: ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_job_launch.py b/awx_modules/plugins/modules/tower_job_launch.py index dbae9e9399..e790603ec9 100644 --- a/awx_modules/plugins/modules/tower_job_launch.py +++ b/awx_modules/plugins/modules/tower_job_launch.py @@ -96,7 +96,7 @@ status: ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_job_list.py b/awx_modules/plugins/modules/tower_job_list.py index 5665f8d935..e89589b498 100644 --- a/awx_modules/plugins/modules/tower_job_list.py +++ b/awx_modules/plugins/modules/tower_job_list.py @@ -78,7 +78,7 @@ results: ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_job_template.py b/awx_modules/plugins/modules/tower_job_template.py index c52fb3e772..f1ee9e5775 100644 --- a/awx_modules/plugins/modules/tower_job_template.py +++ b/awx_modules/plugins/modules/tower_job_template.py @@ -199,7 +199,7 @@ EXAMPLES = ''' survey_spec: "{{ lookup('file', 'my_survey.json') }}" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_job_wait.py b/awx_modules/plugins/modules/tower_job_wait.py index d512a07565..bc6aa89b3f 100644 --- a/awx_modules/plugins/modules/tower_job_wait.py +++ b/awx_modules/plugins/modules/tower_job_wait.py @@ -82,7 +82,7 @@ status: ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode from ansible.module_utils.six.moves import cStringIO as StringIO @@ -125,7 +125,7 @@ def main(): job_id = params.get('job_id') try: result = job.monitor(job_id, **params) - except exc.Timeout as excinfo: + except exc.Timeout: result = job.status(job_id) result['id'] = job_id json_output['msg'] = 'Timeout waiting for job to finish.' diff --git a/awx_modules/plugins/modules/tower_label.py b/awx_modules/plugins/modules/tower_label.py index eca8ea1b55..b29a001a02 100644 --- a/awx_modules/plugins/modules/tower_label.py +++ b/awx_modules/plugins/modules/tower_label.py @@ -49,7 +49,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_notification.py b/awx_modules/plugins/modules/tower_notification.py index 3a3d5084ee..96833ce1dd 100644 --- a/awx_modules/plugins/modules/tower_notification.py +++ b/awx_modules/plugins/modules/tower_notification.py @@ -268,7 +268,7 @@ EXAMPLES = ''' RETURN = ''' # ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_organization.py b/awx_modules/plugins/modules/tower_organization.py index bba58d8894..d38d47b8b3 100644 --- a/awx_modules/plugins/modules/tower_organization.py +++ b/awx_modules/plugins/modules/tower_organization.py @@ -48,7 +48,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_project.py b/awx_modules/plugins/modules/tower_project.py index f8c380ce79..9216eb59f3 100644 --- a/awx_modules/plugins/modules/tower_project.py +++ b/awx_modules/plugins/modules/tower_project.py @@ -110,7 +110,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli @@ -171,7 +171,7 @@ def main(): try: org_res = tower_cli.get_resource('organization') org = org_res.get(name=organization) - except (exc.NotFound) as excinfo: + except exc.NotFound: module.fail_json(msg='Failed to update project, organization not found: {0}'.format(organization), changed=False) if scm_credential: @@ -179,11 +179,11 @@ def main(): cred_res = tower_cli.get_resource('credential') try: cred = cred_res.get(name=scm_credential) - except (tower_cli.exceptions.MultipleResults) as multi_res_excinfo: + except tower_cli.exceptions.MultipleResults: module.warn('Multiple credentials found for {0}, falling back looking in project organization'.format(scm_credential)) cred = cred_res.get(name=scm_credential, organization=org['id']) scm_credential = cred['id'] - except (exc.NotFound) as excinfo: + except exc.NotFound: module.fail_json(msg='Failed to update project, credential not found: {0}'.format(scm_credential), changed=False) if (scm_update_cache_timeout is not None) and (scm_update_on_launch is not True): diff --git a/awx_modules/plugins/modules/tower_receive.py b/awx_modules/plugins/modules/tower_receive.py index 57fdd16df4..6c61d927d7 100644 --- a/awx_modules/plugins/modules/tower_receive.py +++ b/awx_modules/plugins/modules/tower_receive.py @@ -109,7 +109,7 @@ assets: sample: [ {}, {} ] ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, HAS_TOWER_CLI +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, HAS_TOWER_CLI try: from tower_cli.cli.transfer.receive import Receiver diff --git a/awx_modules/plugins/modules/tower_role.py b/awx_modules/plugins/modules/tower_role.py index 9e6d6941fd..92b806e8f2 100644 --- a/awx_modules/plugins/modules/tower_role.py +++ b/awx_modules/plugins/modules/tower_role.py @@ -72,7 +72,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_send.py b/awx_modules/plugins/modules/tower_send.py index d8011806fe..3cd46ff613 100644 --- a/awx_modules/plugins/modules/tower_send.py +++ b/awx_modules/plugins/modules/tower_send.py @@ -76,7 +76,7 @@ import os import sys from ansible.module_utils.six.moves import StringIO -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, HAS_TOWER_CLI +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, HAS_TOWER_CLI from tempfile import mkstemp @@ -138,7 +138,7 @@ def main(): sys.stdout = captured_stdout = StringIO() try: sender.send(files, prevent, password_management) - except TypeError as e: + except TypeError: # Newer versions of TowerCLI require 4 parameters sender.send(files, prevent, [], password_management) diff --git a/awx_modules/plugins/modules/tower_settings.py b/awx_modules/plugins/modules/tower_settings.py index c5f572f38b..c429463450 100644 --- a/awx_modules/plugins/modules/tower_settings.py +++ b/awx_modules/plugins/modules/tower_settings.py @@ -56,7 +56,7 @@ EXAMPLES = ''' no_log: true ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_team.py b/awx_modules/plugins/modules/tower_team.py index 5174d39ba7..554e730382 100644 --- a/awx_modules/plugins/modules/tower_team.py +++ b/awx_modules/plugins/modules/tower_team.py @@ -50,7 +50,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_user.py b/awx_modules/plugins/modules/tower_user.py index d9224308d1..e361412eb3 100644 --- a/awx_modules/plugins/modules/tower_user.py +++ b/awx_modules/plugins/modules/tower_user.py @@ -100,7 +100,7 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode +from ..module_utils.ansible_tower import TowerModule, tower_auth_config, tower_check_mode try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_workflow_launch.py b/awx_modules/plugins/modules/tower_workflow_launch.py index 6f2c577d29..8df65e8919 100644 --- a/awx_modules/plugins/modules/tower_workflow_launch.py +++ b/awx_modules/plugins/modules/tower_workflow_launch.py @@ -75,7 +75,7 @@ EXAMPLES = ''' register: workflow_task_info ''' -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config +from ..module_utils.ansible_tower import TowerModule, tower_auth_config try: import tower_cli diff --git a/awx_modules/plugins/modules/tower_workflow_template.py b/awx_modules/plugins/modules/tower_workflow_template.py index e8b2e5b354..b3fc6e14d3 100644 --- a/awx_modules/plugins/modules/tower_workflow_template.py +++ b/awx_modules/plugins/modules/tower_workflow_template.py @@ -93,8 +93,7 @@ EXAMPLES = ''' RETURN = ''' # ''' -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.ansible_tower import ( +from ..module_utils.ansible_tower import ( TowerModule, tower_auth_config, tower_check_mode diff --git a/awx_modules/setup.cfg b/awx_modules/setup.cfg new file mode 100644 index 0000000000..fdfea44c7e --- /dev/null +++ b/awx_modules/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +max-line-length=160 +ignore=E402 \ No newline at end of file diff --git a/awx_modules/test/awx/conftest.py b/awx_modules/test/awx/conftest.py new file mode 100644 index 0000000000..bdaa0db3bf --- /dev/null +++ b/awx_modules/test/awx/conftest.py @@ -0,0 +1,121 @@ +import io +import json +import datetime +import importlib +from contextlib import redirect_stdout +from unittest import mock + +from requests.models import Response + +import pytest + +from awx.main.tests.functional.conftest import _request +from awx.main.models import Organization, Project, Inventory, Credential, CredentialType + + +def sanitize_dict(din): + '''Sanitize Django response data to purge it of internal types + so it may be used to cast a requests response object + ''' + if isinstance(din, (int, str, type(None), bool)): + return din # native JSON types, no problem + elif isinstance(din, datetime.datetime): + return din.isoformat() + elif isinstance(din, list): + for i in range(len(din)): + din[i] = sanitize_dict(din[i]) + return din + elif isinstance(din, dict): + for k in din.copy().keys(): + din[k] = sanitize_dict(din[k]) + return din + else: + return str(din) # translation proxies often not string but stringlike + + +@pytest.fixture +def run_module(): + def rf(module_name, module_params, request_user): + + def new_request(self, method, url, **kwargs): + kwargs_copy = kwargs.copy() + if 'data' in kwargs: + kwargs_copy['data'] = json.loads(kwargs['data']) + + # make request + rf = _request(method.lower()) + django_response = rf(url, user=request_user, expect=None, **kwargs_copy) + + # requests library response object is different from the Django response, but they are the same concept + # this converts the Django response object into a requests response object for consumption + resp = Response() + py_data = django_response.data + sanitize_dict(py_data) + resp._content = bytes(json.dumps(django_response.data), encoding='utf8') + resp.status_code = django_response.status_code + return resp + + stdout_buffer = io.StringIO() + # Requies specific PYTHONPATH, see docs + # Note that a proper Ansiballz explosion of the modules will have an import path like: + # ansible_collections.awx.awx.plugins.modules.{} + # We should consider supporting that in the future + resource_module = importlib.import_module('plugins.modules.{}'.format(module_name)) + + # Ansible params can be passed as an invocation argument or over stdin + # this short circuits within the AnsibleModule interface + def mock_load_params(self): + self.params = module_params + + with mock.patch.object(resource_module.TowerModule, '_load_params', new=mock_load_params): + # Call the test utility (like a mock server) instead of issuing HTTP requests + with mock.patch('tower_cli.api.Session.request', new=new_request): + # Ansible modules return data to the mothership over stdout + with redirect_stdout(stdout_buffer): + try: + resource_module.main() + except SystemExit: + pass # A system exit indicates successful execution + + module_stdout = stdout_buffer.getvalue().strip() + result = json.loads(module_stdout) + return result + + return rf + + +@pytest.fixture +def organization(): + return Organization.objects.create(name='Default') + + +@pytest.fixture +def project(organization): + return Project.objects.create( + name="test-proj", + description="test-proj-desc", + organization=organization, + playbook_files=['helloworld.yml'], + local_path='_92__test_proj', + scm_revision='1234567890123456789012345678901234567890', + scm_url='localhost', + scm_type='git' + ) + + +@pytest.fixture +def inventory(organization): + return Inventory.objects.create( + name='test-inv', + organization=organization + ) + + +@pytest.fixture +def machine_credential(organization): + ssh_type = CredentialType.defaults['ssh']() + ssh_type.save() + return Credential.objects.create( + credential_type=ssh_type, name='machine-cred', + inputs={'username': 'test_user', 'password': 'pas4word'} + ) diff --git a/awx_modules/test/awx/test_job_template.py b/awx_modules/test/awx/test_job_template.py new file mode 100644 index 0000000000..e5ecfeb793 --- /dev/null +++ b/awx_modules/test/awx/test_job_template.py @@ -0,0 +1,59 @@ +import pytest + +from awx.main.models import JobTemplate + + +@pytest.mark.django_db +def test_create_job_template(run_module, admin_user, project, inventory): + + module_args = { + 'name': 'foo', 'playbook': 'helloworld.yml', + 'project': project.name, 'inventory': inventory.name, + 'job_type': 'run', + 'state': 'present' + } + + result = run_module('tower_job_template', module_args, admin_user) + + jt = JobTemplate.objects.get(name='foo') + + assert result == { + "job_template": "foo", + "state": "present", + "id": jt.id, + "changed": True, + "invocation": { + "module_args": module_args + } + } + + assert jt.project_id == project.id + assert jt.inventory_id == inventory.id + + +@pytest.mark.django_db +@pytest.mark.xfail(reason='Known limitation and needs to be fixed.') +def test_create_job_template_with_old_machine_cred(run_module, admin_user, project, inventory, machine_credential): + + module_args = { + 'name': 'foo', 'playbook': 'helloworld.yml', + 'project': project.name, 'inventory': inventory.name, 'credential': machine_credential.name, + 'job_type': 'run', + 'state': 'present' + } + + result = run_module('tower_job_template', module_args, admin_user) + + jt = JobTemplate.objects.get(name='foo') + + assert result == { + "job_template": "foo", + "state": "present", + "id": jt.id, + "changed": True, + "invocation": { + "module_args": module_args + } + } + + assert machine_credential.id in [cred.pk for cred in jt.credentials.all()] diff --git a/awx_modules/test/awx/test_organization.py b/awx_modules/test/awx/test_organization.py new file mode 100644 index 0000000000..ea76940fd4 --- /dev/null +++ b/awx_modules/test/awx/test_organization.py @@ -0,0 +1,25 @@ +import pytest + +from awx.main.models import Organization + + +@pytest.mark.django_db +def test_create_organization(run_module, admin_user): + + module_args = {'name': 'foo', 'description': 'barfoo', 'state': 'present'} + + result = run_module('tower_organization', module_args, admin_user) + + org = Organization.objects.get(name='foo') + + assert result == { + "organization": "foo", + "state": "present", + "id": org.id, + "changed": True, + "invocation": { + "module_args": module_args + } + } + + assert org.description == 'barfoo' diff --git a/setup.cfg b/setup.cfg index e99856b7b1..227322dace 100755 --- a/setup.cfg +++ b/setup.cfg @@ -18,4 +18,4 @@ exclude=.tox,venv,awx/lib/site-packages,awx/plugins/inventory/ec2.py,awx/plugins [flake8] max-line-length=160 ignore=E201,E203,E221,E225,E231,E241,E251,E261,E265,E303,W291,W391,W293,E731,W504 -exclude=.tox,venv,awx/lib/site-packages,awx/plugins/inventory,awx/ui,awx/api/urls.py,awx/main/migrations,awx/main/tests/data,node_modules/,awx/projects/,tools/docker,awx/settings/local_*.py,installer/openshift/settings.py,build/,installer/,awxkit/test +exclude=.tox,venv,awx/lib/site-packages,awx/plugins/inventory,awx/ui,awx/api/urls.py,awx/main/migrations,awx/main/tests/data,node_modules/,awx/projects/,tools/docker,awx/settings/local_*.py,installer/openshift/settings.py,build/,installer/,awxkit/test,awx_modules/