diff --git a/CHANGELOG.md b/CHANGELOG.md index 44dd359fef..63597da808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,10 @@ Ansible Changes By Release https://github.com/ansible/ansible/pull/36124 * fix debug output https://github.com/ansible/ansible/pull/36307 +* Fix credentials for Ansible Tower modules to work with v1 and v2 of the API + (https://github.com/ansible/ansible/pull/36587) + (https://github.com/ansible/ansible/pull/36662) + diff --git a/lib/ansible/modules/web_infrastructure/ansible_tower/tower_credential.py b/lib/ansible/modules/web_infrastructure/ansible_tower/tower_credential.py index eb2734ffc6..64f77c9af9 100644 --- a/lib/ansible/modules/web_infrastructure/ansible_tower/tower_credential.py +++ b/lib/ansible/modules/web_infrastructure/ansible_tower/tower_credential.py @@ -54,7 +54,7 @@ options: description: - Type of credential being added. required: True - choices: ["ssh", "net", "scm", "aws", "rax", "vmware", "satellite6", "cloudforms", "gce", "azure", "azure_rm", "openstack"] + choices: ["ssh", "vault", "net", "scm", "aws", "vmware", "satellite6", "cloudforms", "gce", "azure_rm", "openstack", "rhv", "insights", "tower"] host: description: - Host for this credential. @@ -190,56 +190,89 @@ EXAMPLES = ''' tower_config_file: "~/tower_cli.cfg" ''' +import os + +from ansible.module_utils.ansible_tower import tower_argument_spec, tower_auth_config, tower_check_mode + try: - import os import tower_cli import tower_cli.utils.exceptions as exc from tower_cli.conf import settings - from ansible.module_utils.ansible_tower import tower_auth_config, tower_check_mode - HAS_TOWER_CLI = True except ImportError: HAS_TOWER_CLI = False +KIND_CHOICES = { + 'ssh': 'Machine', + 'vault': 'Ansible Vault', + 'net': 'Network', + 'scm': 'Source Control', + 'aws': 'Amazon Web Services', + 'vmware': 'VMware vCenter', + 'satellite6': 'Red Hat Satellite 6', + 'cloudforms': 'Red Hat CloudForms', + 'gce': 'Google Compute Engine', + 'azure_rm': 'Microsoft Azure Resource Manager', + 'openstack': 'OpenStack', + 'rhv': 'Red Hat Virtualization', + 'insights': 'Insights', + 'tower': 'Ansible Tower', +} + + +def credential_type_for_v1_kind(params, module): + credential_type_res = tower_cli.get_resource('credential_type') + kind = params.pop('kind') + arguments = {'managed_by_tower': True} + if kind == 'ssh': + if params.get('vault_password'): + arguments['kind'] = 'vault' + else: + arguments['kind'] = 'ssh' + elif kind in ('net', 'scm', 'insights', 'vault'): + arguments['kind'] = kind + elif kind in KIND_CHOICES: + arguments.update(dict( + kind='cloud', + name=KIND_CHOICES[kind] + )) + return credential_type_res.get(**arguments) + + def main(): - module = AnsibleModule( - argument_spec=dict( - name=dict(required=True), - user=dict(), - team=dict(), - kind=dict(required=True, - choices=["ssh", "net", "scm", "aws", "rax", "vmware", "satellite6", - "cloudforms", "gce", "azure", "azure_rm", "openstack"]), - host=dict(), - username=dict(), - password=dict(no_log=True), - ssh_key_data=dict(no_log=True), - ssh_key_unlock=dict(no_log=True), - authorize=dict(type='bool', default=False), - authorize_password=dict(no_log=True), - client=dict(), - secret=dict(), - tenant=dict(), - subscription=dict(), - domain=dict(), - become_method=dict(), - become_username=dict(), - become_password=dict(no_log=True), - vault_password=dict(no_log=True), - description=dict(), - organization=dict(required=True), - project=dict(), - tower_host=dict(), - tower_username=dict(), - tower_password=dict(no_log=True), - tower_verify_ssl=dict(type='bool', default=True), - tower_config_file=dict(type='path'), - state=dict(choices=['present', 'absent'], default='present'), - ), - supports_check_mode=True - ) + + argument_spec = tower_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + user=dict(), + team=dict(), + kind=dict(required=True, + choices=KIND_CHOICES.keys()), + host=dict(), + username=dict(), + password=dict(no_log=True), + ssh_key_data=dict(no_log=True, type='path'), + ssh_key_unlock=dict(no_log=True), + authorize=dict(type='bool', default=False), + authorize_password=dict(no_log=True), + client=dict(), + secret=dict(), + tenant=dict(), + subscription=dict(), + domain=dict(), + become_method=dict(), + become_username=dict(), + become_password=dict(no_log=True), + vault_password=dict(no_log=True), + description=dict(), + organization=dict(required=True), + project=dict(), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') @@ -255,23 +288,57 @@ def main(): tower_check_mode(module) credential = tower_cli.get_resource('credential') try: - params = module.params.copy() + params = {} params['create_on_missing'] = True + params['name'] = name if organization: org_res = tower_cli.get_resource('organization') org = org_res.get(name=organization) params['organization'] = org['id'] - if params['ssh_key_data']: - filename = params['ssh_key_data'] - filename = os.path.expanduser(filename) + try: + tower_cli.get_resource('credential_type') + except (ImportError, AttributeError): + # /api/v1/ backwards compat + # older versions of tower-cli don't *have* a credential_type + # resource + params['kind'] = module.params['kind'] + else: + credential_type = credential_type_for_v1_kind(module.params, module) + params['credential_type'] = credential_type['id'] + + if module.params.get('description'): + params['description'] = module.params.get('description') + + if module.params.get('user'): + user_res = tower_cli.get_resource('user') + user = user_res.get(username=module.params.get('user')) + params['user'] = user['id'] + + if module.params.get('team'): + team_res = tower_cli.get_resource('team') + team = team_res.get(name=module.params.get('team')) + params['team'] = team['id'] + + if module.params.get('ssh_key_data'): + filename = module.params.get('ssh_key_data') if not os.path.exists(filename): module.fail_json(msg='file not found: %s' % filename) if os.path.isdir(filename): module.fail_json(msg='attempted to read contents of directory: %s' % filename) with open(filename, 'rb') as f: - params['ssh_key_data'] = f.read() + module.params['ssh_key_data'] = f.read() + + for key in ('authorize', 'authorize_password', 'client', 'secret', + 'tenant', 'subscription', 'domain', 'become_method', + 'become_username', 'become_password', 'vault_password', + 'project', 'host', 'username', 'password', + 'ssh_key_data', 'ssh_key_unlock'): + if 'kind' in params: + params[key] = module.params.get(key) + elif module.params.get(key): + params.setdefault('inputs', {})[key] = module.params.get(key) if state == 'present': result = credential.modify(**params)