diff --git a/shippable.yml b/shippable.yml index 50909015661..2b116d0cca7 100644 --- a/shippable.yml +++ b/shippable.yml @@ -139,7 +139,6 @@ matrix: - env: T=i/aws/2.7/1 - env: T=i/aws/3.6/1 - - env: T=i/tower//1 - env: T=i/cloud//1 branches: diff --git a/test/integration/targets/argspec/tasks/main.yml b/test/integration/targets/argspec/tasks/main.yml index 1fb855c6291..02b57e5e0c0 100644 --- a/test/integration/targets/argspec/tasks/main.yml +++ b/test/integration/targets/argspec/tasks/main.yml @@ -83,6 +83,12 @@ required_one_of_one: value register: argspec_good_mapping_json +- argspec: + mapping: !!str '{"foo": False}' + required: value + required_one_of_one: value + register: argspec_good_mapping_dict_repr + - argspec: mapping: foo required: value @@ -289,6 +295,9 @@ - argspec_good_mapping_json is successful - >- argspec_good_mapping_json.mapping == {'foo': 'bar'} + - argspec_good_mapping_dict_repr is successful + - >- + argspec_good_mapping_dict_repr.mapping == {'foo': False} - argspec_good_mapping_kv is successful - >- argspec_good_mapping_kv.mapping == {'foo': 'bar'} diff --git a/test/integration/targets/incidental_tower_credential_type/aliases b/test/integration/targets/incidental_tower_credential_type/aliases deleted file mode 100644 index 7e198b4a51f..00000000000 --- a/test/integration/targets/incidental_tower_credential_type/aliases +++ /dev/null @@ -1,2 +0,0 @@ -cloud/tower -shippable/tower/incidental diff --git a/test/integration/targets/incidental_tower_credential_type/tasks/main.yml b/test/integration/targets/incidental_tower_credential_type/tasks/main.yml deleted file mode 100644 index 9d7cc74e733..00000000000 --- a/test/integration/targets/incidental_tower_credential_type/tasks/main.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -- name: Add Tower credential type - tower_credential_type: - description: Credential type for Test - name: test-credential-type - kind: cloud - inputs: '{"fields": [{"type": "string", "id": "username", "label": "Username"}, {"secret": True, "type": "string", "id": "password", "label": "Password"}], "required": ["username", "password"]}' - injectors: '{"extra_vars": {"test": "foo"}}' - register: result - -- assert: - that: - - "result is changed" - -- name: Remove a Tower credential type - tower_credential_type: - name: test-credential-type - state: absent - register: result - -- assert: - that: - - "result is changed" diff --git a/test/integration/targets/incidental_tower_receive/aliases b/test/integration/targets/incidental_tower_receive/aliases deleted file mode 100644 index 7e198b4a51f..00000000000 --- a/test/integration/targets/incidental_tower_receive/aliases +++ /dev/null @@ -1,2 +0,0 @@ -cloud/tower -shippable/tower/incidental diff --git a/test/integration/targets/incidental_tower_receive/tasks/main.yml b/test/integration/targets/incidental_tower_receive/tasks/main.yml deleted file mode 100644 index 9c22e6f7a73..00000000000 --- a/test/integration/targets/incidental_tower_receive/tasks/main.yml +++ /dev/null @@ -1,17 +0,0 @@ -- name: Export all Tower assets - tower_receive: - all: True - register: result - -- assert: - that: - - "result is successful" - -- name: Extract names from output - set_fact: - object_names: "{{ result.assets | map(attribute='name') | list }}" - -- assert: - that: - - "result is successful" - - "'Default' in object_names" diff --git a/test/integration/targets/undefined/aliases b/test/integration/targets/undefined/aliases new file mode 100644 index 00000000000..70a7b7a9f32 --- /dev/null +++ b/test/integration/targets/undefined/aliases @@ -0,0 +1 @@ +shippable/posix/group5 diff --git a/test/integration/targets/undefined/tasks/main.yml b/test/integration/targets/undefined/tasks/main.yml new file mode 100644 index 00000000000..de6681a0879 --- /dev/null +++ b/test/integration/targets/undefined/tasks/main.yml @@ -0,0 +1,18 @@ +- when: lookup('pipe', ansible_playbook_python ~ ' -c "import jinja2; print(jinja2.__version__)"') is version('2.7', '>=') + block: + - set_fact: + names: '{{ things|map(attribute="name") }}' + vars: + things: + - name: one + - name: two + - notname: three + - name: four + + - assert: + that: + - '"%r"|format(undef) == "AnsibleUndefined"' + # The existence of AnsibleUndefined in a templating result + # prevents safe_eval from turning the value into a python object + - names is string + - '", AnsibleUndefined," in names' diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 0a831729e98..69b095653ba 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -198,8 +198,6 @@ test/lib/ansible_test/_data/requirements/sanity.ps1 pslint:PSCustomUseLiteralPat test/lib/ansible_test/_data/sanity/pylint/plugins/string_format.py use-compat-six test/lib/ansible_test/_data/setup/ConfigureRemotingForAnsible.ps1 pslint:PSCustomUseLiteralPath test/lib/ansible_test/_data/setup/windows-httptester.ps1 pslint:PSCustomUseLiteralPath -test/support/integration/plugins/module_utils/ansible_tower.py future-import-boilerplate -test/support/integration/plugins/module_utils/ansible_tower.py metaclass-boilerplate test/support/integration/plugins/module_utils/cloud.py future-import-boilerplate test/support/integration/plugins/module_utils/cloud.py metaclass-boilerplate test/support/integration/plugins/module_utils/compat/ipaddress.py future-import-boilerplate diff --git a/test/support/integration/plugins/module_utils/ansible_tower.py b/test/support/integration/plugins/module_utils/ansible_tower.py deleted file mode 100644 index ef687a669c6..00000000000 --- a/test/support/integration/plugins/module_utils/ansible_tower.py +++ /dev/null @@ -1,113 +0,0 @@ -# This code is part of Ansible, but is an independent component. -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# Copyright (c), Wayne Witzel III -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import traceback - -TOWER_CLI_IMP_ERR = None -try: - import tower_cli.utils.exceptions as exc - from tower_cli.utils import parser - from tower_cli.api import client - - HAS_TOWER_CLI = True -except ImportError: - TOWER_CLI_IMP_ERR = traceback.format_exc() - HAS_TOWER_CLI = False - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib - - -def tower_auth_config(module): - '''tower_auth_config attempts to load the tower-cli.cfg file - specified from the `tower_config_file` parameter. If found, - if returns the contents of the file as a dictionary, else - it will attempt to fetch values from the module params and - only pass those values that have been set. - ''' - config_file = module.params.pop('tower_config_file', None) - if config_file: - if not os.path.exists(config_file): - module.fail_json(msg='file not found: %s' % config_file) - if os.path.isdir(config_file): - module.fail_json(msg='directory can not be used as config file: %s' % config_file) - - with open(config_file, 'rb') as f: - return parser.string_to_dict(f.read()) - else: - auth_config = {} - host = module.params.pop('tower_host', None) - if host: - auth_config['host'] = host - username = module.params.pop('tower_username', None) - if username: - auth_config['username'] = username - password = module.params.pop('tower_password', None) - if password: - auth_config['password'] = password - module.params.pop('tower_verify_ssl', None) # pop alias if used - verify_ssl = module.params.pop('validate_certs', None) - if verify_ssl is not None: - auth_config['verify_ssl'] = verify_ssl - return auth_config - - -def tower_check_mode(module): - '''Execute check mode logic for Ansible Tower modules''' - if module.check_mode: - try: - result = client.get('/ping').json() - module.exit_json(changed=True, tower_version='{0}'.format(result['version'])) - except (exc.ServerError, exc.ConnectionError, exc.BadRequest) as excinfo: - module.fail_json(changed=False, msg='Failed check mode: {0}'.format(excinfo)) - - -class TowerModule(AnsibleModule): - def __init__(self, argument_spec, **kwargs): - args = dict( - tower_host=dict(), - tower_username=dict(), - tower_password=dict(no_log=True), - validate_certs=dict(type='bool', aliases=['tower_verify_ssl']), - tower_config_file=dict(type='path'), - ) - args.update(argument_spec) - - mutually_exclusive = kwargs.get('mutually_exclusive', []) - kwargs['mutually_exclusive'] = mutually_exclusive.extend(( - ('tower_config_file', 'tower_host'), - ('tower_config_file', 'tower_username'), - ('tower_config_file', 'tower_password'), - ('tower_config_file', 'validate_certs'), - )) - - super(TowerModule, self).__init__(argument_spec=args, **kwargs) - - if not HAS_TOWER_CLI: - self.fail_json(msg=missing_required_lib('ansible-tower-cli'), - exception=TOWER_CLI_IMP_ERR) diff --git a/test/support/integration/plugins/modules/tower_credential_type.py b/test/support/integration/plugins/modules/tower_credential_type.py deleted file mode 100644 index 831a35ad3f9..00000000000 --- a/test/support/integration/plugins/modules/tower_credential_type.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- -# -# (c) 2018, Adrien Fleury -# 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 = {'status': ['preview'], - 'supported_by': 'community', - 'metadata_version': '1.1'} - - -DOCUMENTATION = ''' ---- -module: tower_credential_type -author: "Adrien Fleury (@fleu42)" -version_added: "2.7" -short_description: Create, update, or destroy custom Ansible Tower credential type. -description: - - Create, update, or destroy Ansible Tower credential type. See - U(https://www.ansible.com/tower) for an overview. -options: - name: - description: - - The name of the credential type. - required: True - description: - description: - - The description of the credential type to give more detail about it. - required: False - kind: - description: - - >- - The type of credential type being added. Note that only cloud and - net can be used for creating credential types. Refer to the Ansible - for more information. - choices: [ 'ssh', 'vault', 'net', 'scm', 'cloud', 'insights' ] - required: False - inputs: - description: - - >- - Enter inputs using either JSON or YAML syntax. Refer to the Ansible - Tower documentation for example syntax. - required: False - injectors: - description: - - >- - Enter injectors using either JSON or YAML syntax. Refer to the - Ansible Tower documentation for example syntax. - required: False - state: - description: - - Desired state of the resource. - required: False - default: "present" - choices: ["present", "absent"] - validate_certs: - description: - - Tower option to avoid certificates check. - required: False - type: bool - aliases: [ tower_verify_ssl ] -extends_documentation_fragment: tower -''' - - -EXAMPLES = ''' -- tower_credential_type: - name: Nexus - description: Credentials type for Nexus - kind: cloud - inputs: "{{ lookup('file', 'tower_credential_inputs_nexus.json') }}" - injectors: {'extra_vars': {'nexus_credential': 'test' }} - state: present - validate_certs: false - -- tower_credential_type: - name: Nexus - state: absent -''' - - -RETURN = ''' # ''' - - -from ansible.module_utils.ansible_tower import ( - TowerModule, - tower_auth_config, - tower_check_mode -) - -try: - import tower_cli - import tower_cli.exceptions as exc - from tower_cli.conf import settings -except ImportError: - pass - - -KIND_CHOICES = { - 'ssh': 'Machine', - 'vault': 'Ansible Vault', - 'net': 'Network', - 'scm': 'Source Control', - 'cloud': 'Lots of others', - 'insights': 'Insights' -} - - -def main(): - argument_spec = dict( - name=dict(required=True), - description=dict(required=False), - kind=dict(required=False, choices=KIND_CHOICES.keys()), - inputs=dict(type='dict', required=False), - injectors=dict(type='dict', required=False), - state=dict(choices=['present', 'absent'], default='present'), - ) - - module = TowerModule( - argument_spec=argument_spec, - supports_check_mode=False - ) - - name = module.params.get('name') - kind = module.params.get('kind') - state = module.params.get('state') - - json_output = {'credential_type': name, 'state': state} - - tower_auth = tower_auth_config(module) - with settings.runtime_values(**tower_auth): - tower_check_mode(module) - credential_type_res = tower_cli.get_resource('credential_type') - - params = {} - params['name'] = name - params['kind'] = kind - params['managed_by_tower'] = False - - if module.params.get('description'): - params['description'] = module.params.get('description') - - if module.params.get('inputs'): - params['inputs'] = module.params.get('inputs') - - if module.params.get('injectors'): - params['injectors'] = module.params.get('injectors') - - try: - if state == 'present': - params['create_on_missing'] = True - result = credential_type_res.modify(**params) - json_output['id'] = result['id'] - elif state == 'absent': - params['fail_on_missing'] = False - result = credential_type_res.delete(**params) - - except (exc.ConnectionError, exc.BadRequest, exc.AuthError) as excinfo: - module.fail_json( - msg='Failed to update credential type: {0}'.format(excinfo), - changed=False - ) - - json_output['changed'] = result['changed'] - module.exit_json(**json_output) - - -if __name__ == '__main__': - main() diff --git a/test/support/integration/plugins/modules/tower_receive.py b/test/support/integration/plugins/modules/tower_receive.py deleted file mode 100644 index 57fdd16df43..00000000000 --- a/test/support/integration/plugins/modules/tower_receive.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2017, John Westcott IV -# 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: tower_receive -author: "John Westcott IV (@john-westcott-iv)" -version_added: "2.8" -short_description: Receive assets from Ansible Tower. -description: - - Receive assets from Ansible Tower. See - U(https://www.ansible.com/tower) for an overview. -options: - all: - description: - - Export all assets - type: bool - default: 'False' - organization: - description: - - List of organization names to export - default: [] - user: - description: - - List of user names to export - default: [] - team: - description: - - List of team names to export - default: [] - credential_type: - description: - - List of credential type names to export - default: [] - credential: - description: - - List of credential names to export - default: [] - notification_template: - description: - - List of notification template names to export - default: [] - inventory_script: - description: - - List of inventory script names to export - default: [] - inventory: - description: - - List of inventory names to export - default: [] - project: - description: - - List of project names to export - default: [] - job_template: - description: - - List of job template names to export - default: [] - workflow: - description: - - List of workflow names to export - default: [] - -requirements: - - "ansible-tower-cli >= 3.3.0" - -notes: - - Specifying a name of "all" for any asset type will export all items of that asset type. - -extends_documentation_fragment: tower -''' - -EXAMPLES = ''' -- name: Export all tower assets - tower_receive: - all: True - tower_config_file: "~/tower_cli.cfg" - -- name: Export all inventories - tower_receive: - inventory: - - all - -- name: Export a job template named "My Template" and all Credentials - tower_receive: - job_template: - - "My Template" - credential: - - all -''' - -RETURN = ''' -assets: - description: The exported assets - returned: success - type: dict - sample: [ {}, {} ] -''' - -from ansible.module_utils.ansible_tower import TowerModule, tower_auth_config, HAS_TOWER_CLI - -try: - from tower_cli.cli.transfer.receive import Receiver - from tower_cli.cli.transfer.common import SEND_ORDER - from tower_cli.utils.exceptions import TowerCLIError - - from tower_cli.conf import settings - TOWER_CLI_HAS_EXPORT = True -except ImportError: - TOWER_CLI_HAS_EXPORT = False - - -def main(): - argument_spec = dict( - all=dict(type='bool', default=False), - credential=dict(type='list', default=[]), - credential_type=dict(type='list', default=[]), - inventory=dict(type='list', default=[]), - inventory_script=dict(type='list', default=[]), - job_template=dict(type='list', default=[]), - notification_template=dict(type='list', default=[]), - organization=dict(type='list', default=[]), - project=dict(type='list', default=[]), - team=dict(type='list', default=[]), - user=dict(type='list', default=[]), - workflow=dict(type='list', default=[]), - ) - - module = TowerModule(argument_spec=argument_spec, supports_check_mode=False) - - if not HAS_TOWER_CLI: - module.fail_json(msg='ansible-tower-cli required for this module') - - if not TOWER_CLI_HAS_EXPORT: - module.fail_json(msg='ansible-tower-cli version does not support export') - - export_all = module.params.get('all') - assets_to_export = {} - for asset_type in SEND_ORDER: - assets_to_export[asset_type] = module.params.get(asset_type) - - result = dict( - assets=None, - changed=False, - message='', - ) - - tower_auth = tower_auth_config(module) - with settings.runtime_values(**tower_auth): - try: - receiver = Receiver() - result['assets'] = receiver.export_assets(all=export_all, asset_input=assets_to_export) - module.exit_json(**result) - except TowerCLIError as e: - result['message'] = e.message - module.fail_json(msg='Receive Failed', **result) - - -if __name__ == '__main__': - main()