diff --git a/changelogs/fragments/14532-remove-deprecations.yml b/changelogs/fragments/14532-remove-deprecations.yml new file mode 100644 index 00000000000..29ef3621ad8 --- /dev/null +++ b/changelogs/fragments/14532-remove-deprecations.yml @@ -0,0 +1,3 @@ +breaking_changes: +- iam - Removed deprecated ``community.aws.iam`` module. Please use ``community.aws.iam_user``, ``community.aws.iam_access_key`` or ``community.aws.iam_group`` (https://github.com/ansible-collections/community.aws/pull/839). +- rds - Removed deprecated ``community.aws.rds`` module. Please use ``community.aws.rds_instance`` (https://github.com/ansible-collections/community.aws/pull/839). \ No newline at end of file diff --git a/meta/runtime.yml b/meta/runtime.yml index 41cb96e652d..2e7578e50b5 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -124,7 +124,6 @@ action_groups: - elb_target_group_info - elb_target_info - execute_lambda - - iam - iam_access_key - iam_access_key_info - iam_cert @@ -148,7 +147,6 @@ action_groups: - lambda_info - lambda_policy - lightsail - - rds - rds_instance - rds_instance_info - rds_instance_snapshot diff --git a/plugins/modules/iam.py b/plugins/modules/iam.py deleted file mode 100644 index 52aca2650ab..00000000000 --- a/plugins/modules/iam.py +++ /dev/null @@ -1,880 +0,0 @@ -#!/usr/bin/python -# Copyright: Ansible Project -# 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 - - -DOCUMENTATION = r''' ---- -module: iam -version_added: 1.0.0 -deprecated: - removed_in: 3.0.0 - why: The iam module is based upon a deprecated version of the AWS SDK. - alternative: >- - Use M(community.aws.iam_user), M(community.aws.iam_group), M(community.aws.iam_role), M(community.aws.iam_policy) - and M(community.aws.iam_managed_policy) modules. - -short_description: Manage IAM users, groups, roles and keys -description: - - Allows for the management of IAM users, user API keys, groups, roles. -options: - iam_type: - description: - - Type of IAM resource. - choices: ["user", "group", "role"] - type: str - required: true - name: - description: - - Name of IAM resource to create or identify. - required: true - type: str - new_name: - description: - - When I(state=update), will replace I(name) with I(new_name) on IAM resource. - type: str - new_path: - description: - - When I(state=update), will replace the path with new_path on the IAM resource. - type: str - state: - description: - - Whether to create, delete or update the IAM resource. Note, roles cannot be updated. - required: true - choices: [ "present", "absent", "update" ] - type: str - path: - description: - - When creating or updating, specify the desired path of the resource. - - If I(state=present), it will replace the current path to match what is passed in when they do not match. - default: "/" - type: str - trust_policy: - description: - - The inline (JSON or YAML) trust policy document that grants an entity permission to assume the role. - - Mutually exclusive with I(trust_policy_filepath). - type: dict - trust_policy_filepath: - description: - - The path to the trust policy document that grants an entity permission to assume the role. - - Mutually exclusive with I(trust_policy). - type: str - access_key_state: - description: - - When type is user, it creates, removes, deactivates or activates a user's access key(s). Note that actions apply only to keys specified. - choices: [ "create", "remove", "active", "inactive", "Create", "Remove", "Active", "Inactive"] - type: str - key_count: - description: - - When I(access_key_state=create) it will ensure this quantity of keys are present. - default: 1 - type: int - access_key_ids: - description: - - A list of the keys that you want affected by the I(access_key_state) parameter. - type: list - elements: str - groups: - description: - - A list of groups the user should belong to. When I(state=update), will gracefully remove groups not listed. - type: list - elements: str - password: - description: - - When I(type=user) and either I(state=present) or I(state=update), define the users login password. - - Note that this will always return 'changed'. - type: str - update_password: - default: always - choices: ['always', 'on_create'] - description: - - When to update user passwords. - - I(update_password=always) will ensure the password is set to I(password). - - I(update_password=on_create) will only set the password for newly created users. - type: str -notes: - - 'Currently boto does not support the removal of Managed Policies, the module will error out if your - user/group/role has managed policies when you try to do state=absent. They will need to be removed manually.' -author: - - "Jonathan I. Davila (@defionscode)" - - "Paul Seiffert (@seiffert)" -extends_documentation_fragment: -- amazon.aws.aws -- amazon.aws.ec2 -requirements: -- boto >= 2.49.0 -''' - -EXAMPLES = r''' -# Basic user creation example -- name: Create two new IAM users with API keys - community.aws.iam: - iam_type: user - name: "{{ item }}" - state: present - password: "{{ temp_pass }}" - access_key_state: create - loop: - - jcleese - - mpython - -# Advanced example, create two new groups and add the pre-existing user -# jdavila to both groups. -- name: Create Two Groups, Mario and Luigi - community.aws.iam: - iam_type: group - name: "{{ item }}" - state: present - loop: - - Mario - - Luigi - register: new_groups - -- name: Update user - community.aws.iam: - iam_type: user - name: jdavila - state: update - groups: "{{ item.created_group.group_name }}" - loop: "{{ new_groups.results }}" - -# Example of role with custom trust policy for Lambda service -- name: Create IAM role with custom trust relationship - community.aws.iam: - iam_type: role - name: AAALambdaTestRole - state: present - trust_policy: - Version: '2012-10-17' - Statement: - - Action: sts:AssumeRole - Effect: Allow - Principal: - Service: lambda.amazonaws.com - -''' -RETURN = r''' -role_result: - description: the IAM.role dict returned by Boto - type: str - returned: if iam_type=role and state=present - sample: { - "arn": "arn:aws:iam::A1B2C3D4E5F6:role/my-new-role", - "assume_role_policy_document": "...truncated...", - "create_date": "2017-09-02T14:32:23Z", - "path": "/", - "role_id": "AROAA1B2C3D4E5F6G7H8I", - "role_name": "my-new-role" - } -roles: - description: a list containing the name of the currently defined roles - type: list - returned: if iam_type=role and state=present - sample: [ - "my-new-role", - "my-existing-role-1", - "my-existing-role-2", - "my-existing-role-3", - "my-existing-role-...", - ] -''' - -import json -import traceback - -try: - import boto.exception - import boto.iam - import boto.iam.connection -except ImportError: - pass # Taken care of by ec2.HAS_BOTO - -from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto_exception -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info - - -def _paginate(func, attr): - ''' - paginates the results from func by continuously passing in - the returned marker if the results were truncated. this returns - an iterator over the items in the returned response. `attr` is - the name of the attribute to iterate over in the response. - ''' - finished, marker = False, None - while not finished: - res = func(marker=marker) - for item in getattr(res, attr): - yield item - - finished = res.is_truncated == 'false' - if not finished: - marker = res.marker - - -def list_all_groups(iam): - return [item['group_name'] for item in _paginate(iam.get_all_groups, 'groups')] - - -def list_all_users(iam): - return [item['user_name'] for item in _paginate(iam.get_all_users, 'users')] - - -def list_all_roles(iam): - return [item['role_name'] for item in _paginate(iam.list_roles, 'roles')] - - -def list_all_instance_profiles(iam): - return [item['instance_profile_name'] for item in _paginate(iam.list_instance_profiles, 'instance_profiles')] - - -def create_user(module, iam, name, pwd, path, key_state, key_count): - key_qty = 0 - keys = [] - try: - user_meta = iam.create_user( - name, path).create_user_response.create_user_result.user - changed = True - if pwd is not None: - pwd = iam.create_login_profile(name, pwd) - if key_state in ['create']: - if key_count: - while key_count > key_qty: - keys.append(iam.create_access_key( - user_name=name).create_access_key_response. - create_access_key_result. - access_key) - key_qty += 1 - else: - keys = None - except boto.exception.BotoServerError as err: - module.fail_json(changed=False, msg=str(err)) - else: - user_info = dict(created_user=user_meta, password=pwd, access_keys=keys) - return (user_info, changed) - - -def delete_dependencies_first(module, iam, name): - changed = False - # try to delete any keys - try: - current_keys = [ck['access_key_id'] for ck in - iam.get_all_access_keys(name).list_access_keys_result.access_key_metadata] - for key in current_keys: - iam.delete_access_key(key, name) - changed = True - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg="Failed to delete keys: %s" % err, exception=traceback.format_exc()) - - # try to delete login profiles - try: - login_profile = iam.get_login_profiles(name).get_login_profile_response - iam.delete_login_profile(name) - changed = True - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if 'Login Profile for User ' + name + ' cannot be found.' not in error_msg: - module.fail_json(changed=changed, msg="Failed to delete login profile: %s" % err, exception=traceback.format_exc()) - - # try to detach policies - try: - for policy in iam.get_all_user_policies(name).list_user_policies_result.policy_names: - iam.delete_user_policy(name, policy) - changed = True - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if 'must detach all policies first' in error_msg: - module.fail_json(changed=changed, msg="All inline policies have been removed. Though it appears" - "that %s has Managed Polices. This is not " - "currently supported by boto. Please detach the policies " - "through the console and try again." % name) - module.fail_json(changed=changed, msg="Failed to delete policies: %s" % err, exception=traceback.format_exc()) - - # try to deactivate associated MFA devices - try: - mfa_devices = iam.get_all_mfa_devices(name).get('list_mfa_devices_response', {}).get('list_mfa_devices_result', {}).get('mfa_devices', []) - for device in mfa_devices: - iam.deactivate_mfa_device(name, device['serial_number']) - changed = True - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg="Failed to deactivate associated MFA devices: %s" % err, exception=traceback.format_exc()) - - return changed - - -def delete_user(module, iam, name): - changed = delete_dependencies_first(module, iam, name) - try: - iam.delete_user(name) - except boto.exception.BotoServerError as ex: - module.fail_json(changed=changed, msg="Failed to delete user %s: %s" % (name, ex), exception=traceback.format_exc()) - else: - changed = True - return name, changed - - -def update_user(module, iam, name, new_name, new_path, key_state, key_count, keys, pwd, updated): - changed = False - name_change = False - if updated and new_name: - name = new_name - try: - current_keys = [ck['access_key_id'] for ck in - iam.get_all_access_keys(name).list_access_keys_result.access_key_metadata] - status = [ck['status'] for ck in - iam.get_all_access_keys(name).list_access_keys_result.access_key_metadata] - key_qty = len(current_keys) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if 'cannot be found' in error_msg and updated: - current_keys = [ck['access_key_id'] for ck in - iam.get_all_access_keys(new_name).list_access_keys_result.access_key_metadata] - status = [ck['status'] for ck in - iam.get_all_access_keys(new_name).list_access_keys_result.access_key_metadata] - name = new_name - else: - module.fail_json(changed=False, msg=str(err)) - - updated_key_list = {} - - if new_name or new_path: - c_path = iam.get_user(name).get_user_result.user['path'] - if (name != new_name) or (c_path != new_path): - changed = True - try: - if not updated: - user = iam.update_user( - name, new_user_name=new_name, new_path=new_path).update_user_response.response_metadata - else: - user = iam.update_user( - name, new_path=new_path).update_user_response.response_metadata - user['updates'] = dict( - old_username=name, new_username=new_name, old_path=c_path, new_path=new_path) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - module.fail_json(changed=False, msg=str(err)) - else: - if not updated: - name_change = True - - if pwd: - try: - iam.update_login_profile(name, pwd) - changed = True - except boto.exception.BotoServerError: - try: - iam.create_login_profile(name, pwd) - changed = True - except boto.exception.BotoServerError as err: - error_msg = boto_exception(str(err)) - if 'Password does not conform to the account password policy' in error_msg: - module.fail_json(changed=False, msg="Password doesn't conform to policy") - else: - module.fail_json(msg=error_msg) - - try: - current_keys = [ck['access_key_id'] for ck in - iam.get_all_access_keys(name).list_access_keys_result.access_key_metadata] - status = [ck['status'] for ck in - iam.get_all_access_keys(name).list_access_keys_result.access_key_metadata] - key_qty = len(current_keys) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if 'cannot be found' in error_msg and updated: - current_keys = [ck['access_key_id'] for ck in - iam.get_all_access_keys(new_name).list_access_keys_result.access_key_metadata] - status = [ck['status'] for ck in - iam.get_all_access_keys(new_name).list_access_keys_result.access_key_metadata] - name = new_name - else: - module.fail_json(changed=False, msg=str(err)) - - new_keys = [] - if key_state == 'create': - try: - while key_count > key_qty: - new_keys.append(iam.create_access_key( - user_name=name).create_access_key_response.create_access_key_result.access_key) - key_qty += 1 - changed = True - - except boto.exception.BotoServerError as err: - module.fail_json(changed=False, msg=str(err)) - - if keys and key_state: - for access_key in keys: - if key_state in ('active', 'inactive'): - if access_key in current_keys: - for current_key, current_key_state in zip(current_keys, status): - if key_state != current_key_state.lower(): - try: - iam.update_access_key(access_key, key_state.capitalize(), user_name=name) - changed = True - except boto.exception.BotoServerError as err: - module.fail_json(changed=False, msg=str(err)) - else: - module.fail_json(msg="Supplied keys not found for %s. " - "Current keys: %s. " - "Supplied key(s): %s" % - (name, current_keys, keys) - ) - - if key_state == 'remove': - if access_key in current_keys: - try: - iam.delete_access_key(access_key, user_name=name) - except boto.exception.BotoServerError as err: - module.fail_json(changed=False, msg=str(err)) - else: - changed = True - - try: - final_keys, final_key_status = \ - [ck['access_key_id'] for ck in - iam.get_all_access_keys(name). - list_access_keys_result. - access_key_metadata],\ - [ck['status'] for ck in - iam.get_all_access_keys(name). - list_access_keys_result. - access_key_metadata] - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - - for fk, fks in zip(final_keys, final_key_status): - updated_key_list.update({fk: fks}) - - return name_change, updated_key_list, changed, new_keys - - -def set_users_groups(module, iam, name, groups, updated=None, - new_name=None): - """ Sets groups for a user, will purge groups not explicitly passed, while - retaining pre-existing groups that also are in the new list. - """ - changed = False - - if updated: - name = new_name - - try: - orig_users_groups = [og['group_name'] for og in iam.get_groups_for_user( - name).list_groups_for_user_result.groups] - remove_groups = [ - rg for rg in frozenset(orig_users_groups).difference(groups)] - new_groups = [ - ng for ng in frozenset(groups).difference(orig_users_groups)] - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - else: - if len(orig_users_groups) > 0: - for new in new_groups: - iam.add_user_to_group(new, name) - for rm in remove_groups: - iam.remove_user_from_group(rm, name) - else: - for group in groups: - try: - iam.add_user_to_group(group, name) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if ('The group with name %s cannot be found.' % group) in error_msg: - module.fail_json(changed=False, msg="Group %s doesn't exist" % group) - - if len(remove_groups) > 0 or len(new_groups) > 0: - changed = True - - return (groups, changed) - - -def create_group(module=None, iam=None, name=None, path=None): - changed = False - try: - iam.create_group( - name, path).create_group_response.create_group_result.group - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - else: - changed = True - return name, changed - - -def delete_group(module=None, iam=None, name=None): - changed = False - try: - iam.delete_group(name) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if ('must delete policies first') in error_msg: - for policy in iam.get_all_group_policies(name).list_group_policies_result.policy_names: - iam.delete_group_policy(name, policy) - try: - iam.delete_group(name) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if ('must delete policies first') in error_msg: - module.fail_json(changed=changed, msg="All inline policies have been removed. Though it appears" - "that %s has Managed Polices. This is not " - "currently supported by boto. Please detach the policies " - "through the console and try again." % name) - else: - module.fail_json(changed=changed, msg=str(error_msg)) - else: - changed = True - else: - module.fail_json(changed=changed, msg=str(error_msg)) - else: - changed = True - return changed, name - - -def update_group(module=None, iam=None, name=None, new_name=None, new_path=None): - changed = False - try: - current_group_path = iam.get_group( - name).get_group_response.get_group_result.group['path'] - if new_path: - if current_group_path != new_path: - iam.update_group(name, new_path=new_path) - changed = True - if new_name: - if name != new_name: - iam.update_group(name, new_group_name=new_name, new_path=new_path) - changed = True - name = new_name - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - - return changed, name, new_path, current_group_path - - -def create_role(module, iam, name, path, role_list, prof_list, trust_policy_doc): - changed = False - iam_role_result = None - instance_profile_result = None - try: - if name not in role_list: - changed = True - iam_role_result = iam.create_role(name, - assume_role_policy_document=trust_policy_doc, - path=path).create_role_response.create_role_result.role - - if name not in prof_list: - instance_profile_result = iam.create_instance_profile(name, path=path) \ - .create_instance_profile_response.create_instance_profile_result.instance_profile - iam.add_role_to_instance_profile(name, name) - else: - instance_profile_result = iam.get_instance_profile(name).get_instance_profile_response.get_instance_profile_result.instance_profile - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - else: - updated_role_list = list_all_roles(iam) - iam_role_result = iam.get_role(name).get_role_response.get_role_result.role - return changed, updated_role_list, iam_role_result, instance_profile_result - - -def delete_role(module, iam, name, role_list, prof_list): - changed = False - iam_role_result = None - instance_profile_result = None - try: - if name in role_list: - cur_ins_prof = [rp['instance_profile_name'] for rp in - iam.list_instance_profiles_for_role(name). - list_instance_profiles_for_role_result. - instance_profiles] - for profile in cur_ins_prof: - iam.remove_role_from_instance_profile(profile, name) - try: - iam.delete_role(name) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if ('must detach all policies first') in error_msg: - for policy in iam.list_role_policies(name).list_role_policies_result.policy_names: - iam.delete_role_policy(name, policy) - try: - iam_role_result = iam.delete_role(name) - except boto.exception.BotoServerError as err: - error_msg = boto_exception(err) - if ('must detach all policies first') in error_msg: - module.fail_json(changed=changed, msg="All inline policies have been removed. Though it appears" - "that %s has Managed Polices. This is not " - "currently supported by boto. Please detach the policies " - "through the console and try again." % name) - else: - module.fail_json(changed=changed, msg=str(err)) - else: - changed = True - - else: - changed = True - - for prof in prof_list: - if name == prof: - instance_profile_result = iam.delete_instance_profile(name) - except boto.exception.BotoServerError as err: - module.fail_json(changed=changed, msg=str(err)) - else: - updated_role_list = list_all_roles(iam) - return changed, updated_role_list, iam_role_result, instance_profile_result - - -def main(): - argument_spec = dict( - iam_type=dict(required=True, choices=['user', 'group', 'role']), - groups=dict(type='list', default=None, required=False, elements='str'), - state=dict(required=True, choices=['present', 'absent', 'update']), - password=dict(default=None, required=False, no_log=True), - # setting no_log=False on update_password avoids a false positive warning about not setting no_log - update_password=dict(default='always', required=False, choices=['always', 'on_create'], no_log=False), - access_key_state=dict(default=None, required=False, choices=[ - 'active', 'inactive', 'create', 'remove', - 'Active', 'Inactive', 'Create', 'Remove']), - access_key_ids=dict(type='list', default=None, required=False, elements='str', no_log=False), - key_count=dict(type='int', default=1, required=False), - name=dict(required=True), - trust_policy_filepath=dict(default=None, required=False), - trust_policy=dict(type='dict', default=None, required=False), - new_name=dict(default=None, required=False), - path=dict(default='/', required=False), - new_path=dict(default=None, required=False), - ) - - module = AnsibleAWSModule( - argument_spec=argument_spec, - mutually_exclusive=[['trust_policy', 'trust_policy_filepath']], - check_boto3=False, - ) - - module.deprecate("The 'iam' module has been deprecated and replaced by the 'iam_user', 'iam_group'" - " and 'iam_role' modules'", version='3.0.0', collection_name='community.aws') - - if not HAS_BOTO: - module.fail_json(msg='This module requires boto, please install it') - - state = module.params.get('state').lower() - iam_type = module.params.get('iam_type').lower() - groups = module.params.get('groups') - name = module.params.get('name') - new_name = module.params.get('new_name') - password = module.params.get('password') - update_pw = module.params.get('update_password') - path = module.params.get('path') - new_path = module.params.get('new_path') - key_count = module.params.get('key_count') - key_state = module.params.get('access_key_state') - trust_policy = module.params.get('trust_policy') - trust_policy_filepath = module.params.get('trust_policy_filepath') - key_ids = module.params.get('access_key_ids') - - if key_state: - key_state = key_state.lower() - if any(n in key_state for n in ['active', 'inactive']) and not key_ids: - module.fail_json(changed=False, msg="At least one access key has to be defined in order" - " to use 'active' or 'inactive'") - - if iam_type == 'user' and module.params.get('password') is not None: - pwd = module.params.get('password') - elif iam_type != 'user' and module.params.get('password') is not None: - module.fail_json(msg="a password is being specified when the iam_type " - "is not user. Check parameters") - else: - pwd = None - - if iam_type != 'user' and (module.params.get('access_key_state') is not None or - module.params.get('access_key_id') is not None): - module.fail_json(msg="the IAM type must be user, when IAM access keys " - "are being modified. Check parameters") - - if iam_type == 'role' and state == 'update': - module.fail_json(changed=False, msg="iam_type: role, cannot currently be updated, " - "please specify present or absent") - - # check if trust_policy is present -- it can be inline JSON or a file path to a JSON file - if trust_policy_filepath: - try: - with open(trust_policy_filepath, 'r') as json_data: - trust_policy_doc = json.dumps(json.load(json_data)) - except Exception as e: - module.fail_json(msg=str(e) + ': ' + trust_policy_filepath) - elif trust_policy: - try: - trust_policy_doc = json.dumps(trust_policy) - except Exception as e: - module.fail_json(msg=str(e) + ': ' + trust_policy) - else: - trust_policy_doc = None - - region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module) - - try: - if region: - iam = connect_to_aws(boto.iam, region, **aws_connect_kwargs) - else: - iam = boto.iam.connection.IAMConnection(**aws_connect_kwargs) - except boto.exception.NoAuthHandlerFound as e: - module.fail_json(msg=str(e)) - - result = {} - changed = False - - try: - orig_group_list = list_all_groups(iam) - - orig_user_list = list_all_users(iam) - - orig_role_list = list_all_roles(iam) - - orig_prof_list = list_all_instance_profiles(iam) - except boto.exception.BotoServerError as err: - module.fail_json(msg=err.message) - - if iam_type == 'user': - been_updated = False - user_groups = None - user_exists = any(n in [name, new_name] for n in orig_user_list) - if user_exists: - current_path = iam.get_user(name).get_user_result.user['path'] - if not new_path and current_path != path: - new_path = path - path = current_path - - if state == 'present' and not user_exists and not new_name: - (meta, changed) = create_user( - module, iam, name, password, path, key_state, key_count) - keys = iam.get_all_access_keys(name).list_access_keys_result.\ - access_key_metadata - if groups: - (user_groups, changed) = set_users_groups( - module, iam, name, groups, been_updated, new_name) - module.exit_json( - user_meta=meta, groups=user_groups, user_name=meta['created_user']['user_name'], keys=keys, changed=changed) - - elif state in ['present', 'update'] and user_exists: - if update_pw == 'on_create': - password = None - if name not in orig_user_list and new_name in orig_user_list: - been_updated = True - name_change, key_list, user_changed, new_key = update_user( - module, iam, name, new_name, new_path, key_state, key_count, key_ids, password, been_updated) - if new_key: - user_meta = {'access_keys': list(new_key)} - user_meta['access_keys'].extend( - [{'access_key_id': key, 'status': value} for key, value in key_list.items() if - key not in [it['access_key_id'] for it in new_key]]) - else: - user_meta = { - 'access_keys': [{'access_key_id': key, 'status': value} for key, value in key_list.items()]} - - if name_change and new_name: - orig_name = name - name = new_name - if isinstance(groups, list): - user_groups, groups_changed = set_users_groups( - module, iam, name, groups, been_updated, new_name) - if groups_changed == user_changed: - changed = groups_changed - else: - changed = True - else: - changed = user_changed - if new_name and new_path: - module.exit_json(changed=changed, groups=user_groups, old_user_name=orig_name, - new_user_name=new_name, old_path=path, new_path=new_path, keys=key_list, - created_keys=new_key, user_meta=user_meta) - elif new_name and not new_path and not been_updated: - module.exit_json( - changed=changed, groups=user_groups, old_user_name=orig_name, user_name=new_name, new_user_name=new_name, keys=key_list, - created_keys=new_key, user_meta=user_meta) - elif new_name and not new_path and been_updated: - module.exit_json( - changed=changed, groups=user_groups, user_name=new_name, keys=key_list, key_state=key_state, - created_keys=new_key, user_meta=user_meta) - elif not new_name and new_path: - module.exit_json( - changed=changed, groups=user_groups, user_name=name, old_path=path, new_path=new_path, - keys=key_list, created_keys=new_key, user_meta=user_meta) - else: - module.exit_json( - changed=changed, groups=user_groups, user_name=name, keys=key_list, created_keys=new_key, - user_meta=user_meta) - - elif state == 'update' and not user_exists: - module.fail_json( - msg="The user %s does not exist. No update made." % name) - - elif state == 'absent': - if user_exists: - try: - set_users_groups(module, iam, name, '') - name, changed = delete_user(module, iam, name) - module.exit_json(deleted_user=name, user_name=name, changed=changed) - - except Exception as ex: - module.fail_json(changed=changed, msg=str(ex)) - else: - module.exit_json( - changed=False, msg="User %s is already absent from your AWS IAM users" % name) - - elif iam_type == 'group': - group_exists = name in orig_group_list - - if state == 'present' and not group_exists: - new_group, changed = create_group(module=module, iam=iam, name=name, path=path) - module.exit_json(changed=changed, group_name=new_group) - elif state in ['present', 'update'] and group_exists: - changed, updated_name, updated_path, cur_path = update_group( - module=module, iam=iam, name=name, new_name=new_name, - new_path=new_path) - - if new_path and new_name: - module.exit_json(changed=changed, old_group_name=name, - new_group_name=updated_name, old_path=cur_path, - new_group_path=updated_path) - - if new_path and not new_name: - module.exit_json(changed=changed, group_name=name, - old_path=cur_path, - new_group_path=updated_path) - - if not new_path and new_name: - module.exit_json(changed=changed, old_group_name=name, - new_group_name=updated_name, group_path=cur_path) - - if not new_path and not new_name: - module.exit_json( - changed=changed, group_name=name, group_path=cur_path) - - elif state == 'update' and not group_exists: - module.fail_json( - changed=changed, msg="Update Failed. Group %s doesn't seem to exist!" % name) - - elif state == 'absent': - if name in orig_group_list: - removed_group, changed = delete_group(module=module, iam=iam, name=name) - module.exit_json(changed=changed, delete_group=removed_group) - else: - module.exit_json(changed=changed, msg="Group already absent") - - elif iam_type == 'role': - role_list = [] - if state == 'present': - changed, role_list, role_result, instance_profile_result = create_role( - module, iam, name, path, orig_role_list, orig_prof_list, trust_policy_doc) - elif state == 'absent': - changed, role_list, role_result, instance_profile_result = delete_role( - module, iam, name, orig_role_list, orig_prof_list) - elif state == 'update': - module.fail_json( - changed=False, msg='Role update not currently supported by boto.') - module.exit_json(changed=changed, roles=role_list, role_result=role_result, - instance_profile_result=instance_profile_result) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/rds.py b/plugins/modules/rds.py deleted file mode 100644 index 08e158c9395..00000000000 --- a/plugins/modules/rds.py +++ /dev/null @@ -1,1400 +0,0 @@ -#!/usr/bin/python -# Copyright: Ansible Project -# 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 - - -DOCUMENTATION = r''' ---- -module: rds -version_added: 1.0.0 -deprecated: - removed_in: 3.0.0 - why: The rds module is based upon a deprecated version of the AWS SDK. - alternative: Use M(community.aws.rds_instance), M(community.aws.rds_instance_info), and M(community.aws.rds_instance_snapshot). -short_description: create, delete, or modify Amazon rds instances, rds snapshots, and related facts -description: - - Creates, deletes, or modifies rds resources. - - When creating an instance it can be either a new instance or a read-only replica of an existing instance. - - The 'promote' command requires boto >= 2.18.0. Certain features such as tags rely on boto.rds2 (boto >= 2.26.0). - - Please use the boto3 based M(community.aws.rds_instance) instead. -options: - command: - description: - - Specifies the action to take. The 'reboot' option is available starting at version 2.0. - required: true - choices: [ 'create', 'replicate', 'delete', 'facts', 'modify' , 'promote', 'snapshot', 'reboot', 'restore' ] - type: str - instance_name: - description: - - Database instance identifier. - - Required except when using I(command=facts) or I(command=delete) on just a snapshot. - type: str - source_instance: - description: - - Name of the database to replicate. - - Used only when I(command=replicate). - type: str - db_engine: - description: - - The type of database. - - Used only when I(command=create). - - mariadb was added in version 2.2. - choices: ['mariadb', 'MySQL', 'oracle-se1', 'oracle-se2', 'oracle-se', 'oracle-ee', - 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', 'sqlserver-web', 'postgres', 'aurora'] - type: str - size: - description: - - Size in gigabytes of the initial storage for the DB instance. - - Used only when I(command=create) or I(command=modify). - type: str - instance_type: - description: - - The instance type of the database. - - If not specified then the replica inherits the same instance type as the source instance. - - Required when I(command=create). - - Optional when I(command=replicate), I(command=modify) or I(command=restore). - aliases: ['type'] - type: str - username: - description: - - Master database username. - - Used only when I(command=create). - type: str - password: - description: - - Password for the master database username. - - Used only when I(command=create) or I(command=modify). - type: str - db_name: - description: - - Name of a database to create within the instance. - - If not specified then no database is created. - - Used only when I(command=create). - type: str - engine_version: - description: - - Version number of the database engine to use. - - If not specified then the current Amazon RDS default engine version is used - - Used only when I(command=create). - type: str - parameter_group: - description: - - Name of the DB parameter group to associate with this instance. - - If omitted then the RDS default DBParameterGroup will be used. - - Used only when I(command=create) or I(command=modify). - type: str - license_model: - description: - - The license model for this DB instance. - - Used only when I(command=create) or I(command=restore). - choices: [ 'license-included', 'bring-your-own-license', 'general-public-license', 'postgresql-license' ] - type: str - multi_zone: - description: - - Specifies if this is a Multi-availability-zone deployment. - - Can not be used in conjunction with I(zone) parameter. - - Used only when I(command=create) or I(command=modify). - type: bool - iops: - description: - - Specifies the number of IOPS for the instance. - - Used only when I(command=create) or I(command=modify). - - Must be an integer greater than 1000. - type: str - security_groups: - description: - - Comma separated list of one or more security groups. - - Used only when I(command=create) or I(command=modify). - type: str - vpc_security_groups: - description: - - Comma separated list of one or more vpc security group ids. - - Also requires I(subnet) to be specified. - - Used only when I(command=create) or I(command=modify). - type: list - elements: str - port: - description: - - Port number that the DB instance uses for connections. - - Used only when I(command=create) or I(command=replicate). - - 'Defaults to the standard ports for each I(db_engine): C(3306) for MySQL and MariaDB, C(1521) for Oracle - C(1433) for SQL Server, C(5432) for PostgreSQL.' - type: int - upgrade: - description: - - Indicates that minor version upgrades should be applied automatically. - - Used only when I(command=create) or I(command=modify) or I(command=restore) or I(command=replicate). - type: bool - default: false - option_group: - description: - - The name of the option group to use. - - If not specified then the default option group is used. - - Used only when I(command=create). - type: str - maint_window: - description: - - 'Maintenance window in format of C(ddd:hh24:mi-ddd:hh24:mi). (Example: C(Mon:22:00-Mon:23:15))' - - Times are specified in UTC. - - If not specified then a random maintenance window is assigned. - - Used only when I(command=create) or I(command=modify). - type: str - backup_window: - description: - - 'Backup window in format of C(hh24:mi-hh24:mi). (Example: C(18:00-20:30))' - - Times are specified in UTC. - - If not specified then a random backup window is assigned. - - Used only when command=create or command=modify. - type: str - backup_retention: - description: - - Number of days backups are retained. - - Set to 0 to disable backups. - - Default is 1 day. - - 'Valid range: 0-35.' - - Used only when I(command=create) or I(command=modify). - type: str - zone: - description: - - availability zone in which to launch the instance. - - Used only when I(command=create), I(command=replicate) or I(command=restore). - - Can not be used in conjunction with I(multi_zone) parameter. - aliases: ['aws_zone', 'ec2_zone'] - type: str - subnet: - description: - - VPC subnet group. - - If specified then a VPC instance is created. - - Used only when I(command=create). - type: str - snapshot: - description: - - Name of snapshot to take. - - When I(command=delete), if no I(snapshot) name is provided then no snapshot is taken. - - When I(command=delete), if no I(instance_name) is provided the snapshot is deleted. - - Used with I(command=facts), I(command=delete) or I(command=snapshot). - type: str - wait: - description: - - When I(command=create), replicate, modify or restore then wait for the database to enter the 'available' state. - - When I(command=delete), wait for the database to be terminated. - type: bool - default: false - wait_timeout: - description: - - How long before wait gives up, in seconds. - - Used when I(wait=true). - default: 300 - type: int - apply_immediately: - description: - - When I(apply_immediately=true), the modifications will be applied as soon as possible rather than waiting for the - next preferred maintenance window. - - Used only when I(command=modify). - type: bool - default: false - force_failover: - description: - - If enabled, the reboot is done using a MultiAZ failover. - - Used only when I(command=reboot). - type: bool - default: false - new_instance_name: - description: - - Name to rename an instance to. - - Used only when I(command=modify). - type: str - character_set_name: - description: - - Associate the DB instance with a specified character set. - - Used with I(command=create). - type: str - publicly_accessible: - description: - - Explicitly set whether the resource should be publicly accessible or not. - - Used with I(command=create), I(command=replicate). - - Requires boto >= 2.26.0 - type: str - tags: - description: - - tags dict to apply to a resource. - - Used with I(command=create), I(command=replicate), I(command=restore). - - Requires boto >= 2.26.0 - type: dict -author: - - "Bruce Pennypacker (@bpennypacker)" - - "Will Thames (@willthames)" -extends_documentation_fragment: -- amazon.aws.aws -- amazon.aws.ec2 -requirements: -- boto >= 2.49.0 -''' - -# FIXME: the command stuff needs a 'state' like alias to make things consistent -- MPD - -EXAMPLES = r''' -- name: Basic mysql provisioning example - community.aws.rds: - command: create - instance_name: new-database - db_engine: MySQL - size: 10 - instance_type: db.m1.small - username: mysql_admin - password: 1nsecure - tags: - Environment: testing - Application: cms - -- name: Create a read-only replica and wait for it to become available - community.aws.rds: - command: replicate - instance_name: new-database-replica - source_instance: new_database - wait: yes - wait_timeout: 600 - -- name: Delete an instance, but create a snapshot before doing so - community.aws.rds: - command: delete - instance_name: new-database - snapshot: new_database_snapshot - -- name: Get facts about an instance - community.aws.rds: - command: facts - instance_name: new-database - register: new_database_facts - -- name: Rename an instance and wait for the change to take effect - community.aws.rds: - command: modify - instance_name: new-database - new_instance_name: renamed-database - wait: yes - -- name: Reboot an instance and wait for it to become available again - community.aws.rds: - command: reboot - instance_name: database - wait: yes - -# Restore a Postgres db instance from a snapshot, wait for it to become available again, and -# then modify it to add your security group. Also, display the new endpoint. -# Note that the "publicly_accessible" option is allowed here just as it is in the AWS CLI -- community.aws.rds: - command: restore - snapshot: mypostgres-snapshot - instance_name: MyNewInstanceName - region: us-west-2 - zone: us-west-2b - subnet: default-vpc-xx441xxx - publicly_accessible: yes - wait: yes - wait_timeout: 600 - tags: - Name: pg1_test_name_tag - register: rds - -- community.aws.rds: - command: modify - instance_name: MyNewInstanceName - region: us-west-2 - vpc_security_groups: sg-xxx945xx - -- ansible.builtin.debug: - msg: "The new db endpoint is {{ rds.instance.endpoint }}" -''' - -RETURN = r''' -instance: - description: the rds instance - returned: always - type: complex - contains: - engine: - description: the name of the database engine - returned: when RDS instance exists - type: str - sample: "oracle-se" - engine_version: - description: the version of the database engine - returned: when RDS instance exists - type: str - sample: "11.2.0.4.v6" - license_model: - description: the license model information - returned: when RDS instance exists - type: str - sample: "bring-your-own-license" - character_set_name: - description: the name of the character set that this instance is associated with - returned: when RDS instance exists - type: str - sample: "AL32UTF8" - allocated_storage: - description: the allocated storage size in gigabytes (GB) - returned: when RDS instance exists - type: str - sample: "100" - publicly_accessible: - description: the accessibility options for the DB instance - returned: when RDS instance exists - type: bool - sample: "true" - latest_restorable_time: - description: the latest time to which a database can be restored with point-in-time restore - returned: when RDS instance exists - type: str - sample: "1489707802.0" - secondary_availability_zone: - description: the name of the secondary AZ for a DB instance with multi-AZ support - returned: when RDS instance exists and is multi-AZ - type: str - sample: "eu-west-1b" - backup_window: - description: the daily time range during which automated backups are created if automated backups are enabled - returned: when RDS instance exists and automated backups are enabled - type: str - sample: "03:00-03:30" - auto_minor_version_upgrade: - description: indicates that minor engine upgrades will be applied automatically to the DB instance during the maintenance window - returned: when RDS instance exists - type: bool - sample: "true" - read_replica_source_dbinstance_identifier: - description: the identifier of the source DB instance if this RDS instance is a read replica - returned: when read replica RDS instance exists - type: str - sample: "null" - db_name: - description: the name of the database to create when the DB instance is created - returned: when RDS instance exists - type: str - sample: "ASERTG" - endpoint: - description: the endpoint uri of the database instance - returned: when RDS instance exists - type: str - sample: "my-ansible-database.asdfaosdgih.us-east-1.rds.amazonaws.com" - port: - description: the listening port of the database instance - returned: when RDS instance exists - type: int - sample: 3306 - parameter_groups: - description: the list of DB parameter groups applied to this RDS instance - returned: when RDS instance exists and parameter groups are defined - type: complex - contains: - parameter_apply_status: - description: the status of parameter updates - returned: when RDS instance exists - type: str - sample: "in-sync" - parameter_group_name: - description: the name of the DP parameter group - returned: when RDS instance exists - type: str - sample: "testawsrpprodb01spfile-1ujg7nrs7sgyz" - option_groups: - description: the list of option group memberships for this RDS instance - returned: when RDS instance exists - type: complex - contains: - option_group_name: - description: the option group name for this RDS instance - returned: when RDS instance exists - type: str - sample: "default:oracle-se-11-2" - status: - description: the status of the RDS instance's option group membership - returned: when RDS instance exists - type: str - sample: "in-sync" - pending_modified_values: - description: a dictionary of changes to the RDS instance that are pending - returned: when RDS instance exists - type: complex - contains: - db_instance_class: - description: the new DB instance class for this RDS instance that will be applied or is in progress - returned: when RDS instance exists - type: str - sample: "null" - db_instance_identifier: - description: the new DB instance identifier this RDS instance that will be applied or is in progress - returned: when RDS instance exists - type: str - sample: "null" - allocated_storage: - description: the new allocated storage size for this RDS instance that will be applied or is in progress - returned: when RDS instance exists - type: str - sample: "null" - backup_retention_period: - description: the pending number of days for which automated backups are retained - returned: when RDS instance exists - type: str - sample: "null" - engine_version: - description: indicates the database engine version - returned: when RDS instance exists - type: str - sample: "null" - iops: - description: the new provisioned IOPS value for this RDS instance that will be applied or is being applied - returned: when RDS instance exists - type: str - sample: "null" - master_user_password: - description: the pending or in-progress change of the master credentials for this RDS instance - returned: when RDS instance exists - type: str - sample: "null" - multi_az: - description: indicates that the single-AZ RDS instance is to change to a multi-AZ deployment - returned: when RDS instance exists - type: str - sample: "null" - port: - description: specifies the pending port for this RDS instance - returned: when RDS instance exists - type: str - sample: "null" - db_subnet_groups: - description: information on the subnet group associated with this RDS instance - returned: when RDS instance exists - type: complex - contains: - description: - description: the subnet group associated with the DB instance - returned: when RDS instance exists - type: str - sample: "Subnets for the UAT RDS SQL DB Instance" - name: - description: the name of the DB subnet group - returned: when RDS instance exists - type: str - sample: "samplesubnetgrouprds-j6paiqkxqp4z" - status: - description: the status of the DB subnet group - returned: when RDS instance exists - type: str - sample: "complete" - subnets: - description: the description of the DB subnet group - returned: when RDS instance exists - type: complex - contains: - availability_zone: - description: subnet availability zone information - returned: when RDS instance exists - type: complex - contains: - name: - description: availability zone - returned: when RDS instance exists - type: str - sample: "eu-west-1b" - provisioned_iops_capable: - description: whether provisioned iops are available in AZ subnet - returned: when RDS instance exists - type: bool - sample: "false" - identifier: - description: the identifier of the subnet - returned: when RDS instance exists - type: str - sample: "subnet-3fdba63e" - status: - description: the status of the subnet - returned: when RDS instance exists - type: str - sample: "active" -''' - -import time - -try: - import boto.rds - import boto.exception -except ImportError: - pass # Taken care of by ec2.HAS_BOTO - -try: - import boto.rds2 - import boto.rds2.exceptions - HAS_RDS2 = True -except ImportError: - HAS_RDS2 = False - -from ansible.module_utils._text import to_native -from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info - - -DEFAULT_PORTS = { - 'aurora': 3306, - 'mariadb': 3306, - 'mysql': 3306, - 'oracle': 1521, - 'sqlserver': 1433, - 'postgres': 5432, -} - - -class RDSException(Exception): - def __init__(self, exc): - if hasattr(exc, 'error_message') and exc.error_message: - self.message = exc.error_message - self.code = exc.error_code - elif hasattr(exc, 'body') and 'Error' in exc.body: - self.message = exc.body['Error']['Message'] - self.code = exc.body['Error']['Code'] - else: - self.message = str(exc) - self.code = 'Unknown Error' - - -class RDSConnection: - def __init__(self, module, region, **aws_connect_params): - try: - self.connection = connect_to_aws(boto.rds, region, **aws_connect_params) - except boto.exception.BotoServerError as e: - module.fail_json(msg=e.error_message) - - def get_db_instance(self, instancename): - try: - return RDSDBInstance(self.connection.get_all_dbinstances(instancename)[0]) - except boto.exception.BotoServerError: - return None - - def get_db_snapshot(self, snapshotid): - try: - return RDSSnapshot(self.connection.get_all_dbsnapshots(snapshot_id=snapshotid)[0]) - except boto.exception.BotoServerError: - return None - - def create_db_instance(self, instance_name, size, instance_class, db_engine, - username, password, **params): - params['engine'] = db_engine - try: - result = self.connection.create_dbinstance(instance_name, size, instance_class, - username, password, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def create_db_instance_read_replica(self, instance_name, source_instance, **params): - try: - result = self.connection.createdb_instance_read_replica(instance_name, source_instance, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def delete_db_instance(self, instance_name, **params): - try: - result = self.connection.delete_dbinstance(instance_name, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def delete_db_snapshot(self, snapshot): - try: - result = self.connection.delete_dbsnapshot(snapshot) - return RDSSnapshot(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def modify_db_instance(self, instance_name, **params): - try: - result = self.connection.modify_dbinstance(instance_name, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def reboot_db_instance(self, instance_name, **params): - try: - result = self.connection.reboot_dbinstance(instance_name) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def restore_db_instance_from_db_snapshot(self, instance_name, snapshot, instance_type, **params): - try: - result = self.connection.restore_dbinstance_from_dbsnapshot(snapshot, instance_name, instance_type, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def create_db_snapshot(self, snapshot, instance_name, **params): - try: - result = self.connection.create_dbsnapshot(snapshot, instance_name) - return RDSSnapshot(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def promote_read_replica(self, instance_name, **params): - try: - result = self.connection.promote_read_replica(instance_name, **params) - return RDSDBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - -class RDS2Connection: - def __init__(self, module, region, **aws_connect_params): - try: - self.connection = connect_to_aws(boto.rds2, region, **aws_connect_params) - except boto.exception.BotoServerError as e: - module.fail_json(msg=e.error_message) - - def get_db_instance(self, instancename): - try: - dbinstances = self.connection.describe_db_instances( - db_instance_identifier=instancename - )['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'] - result = RDS2DBInstance(dbinstances[0]) - return result - except boto.rds2.exceptions.DBInstanceNotFound as e: - return None - except Exception as e: - raise e - - def get_db_snapshot(self, snapshotid): - try: - snapshots = self.connection.describe_db_snapshots( - db_snapshot_identifier=snapshotid, - snapshot_type='manual' - )['DescribeDBSnapshotsResponse']['DescribeDBSnapshotsResult']['DBSnapshots'] - result = RDS2Snapshot(snapshots[0]) - return result - except boto.rds2.exceptions.DBSnapshotNotFound: - return None - - def create_db_instance(self, instance_name, size, instance_class, db_engine, - username, password, **params): - try: - result = self.connection.create_db_instance(instance_name, size, instance_class, db_engine, username, password, - **params)['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def create_db_instance_read_replica(self, instance_name, source_instance, **params): - try: - result = self.connection.create_db_instance_read_replica( - instance_name, - source_instance, - **params - )['CreateDBInstanceReadReplicaResponse']['CreateDBInstanceReadReplicaResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def delete_db_instance(self, instance_name, **params): - try: - result = self.connection.delete_db_instance(instance_name, **params)['DeleteDBInstanceResponse']['DeleteDBInstanceResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def delete_db_snapshot(self, snapshot): - try: - result = self.connection.delete_db_snapshot(snapshot)['DeleteDBSnapshotResponse']['DeleteDBSnapshotResult']['DBSnapshot'] - return RDS2Snapshot(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def modify_db_instance(self, instance_name, **params): - try: - result = self.connection.modify_db_instance(instance_name, **params)['ModifyDBInstanceResponse']['ModifyDBInstanceResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def reboot_db_instance(self, instance_name, **params): - try: - result = self.connection.reboot_db_instance(instance_name, **params)['RebootDBInstanceResponse']['RebootDBInstanceResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def restore_db_instance_from_db_snapshot(self, instance_name, snapshot, instance_type, **params): - try: - result = self.connection.restore_db_instance_from_db_snapshot( - instance_name, - snapshot, - **params - )['RestoreDBInstanceFromDBSnapshotResponse']['RestoreDBInstanceFromDBSnapshotResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def create_db_snapshot(self, snapshot, instance_name, **params): - try: - result = self.connection.create_db_snapshot(snapshot, instance_name, **params)['CreateDBSnapshotResponse']['CreateDBSnapshotResult']['DBSnapshot'] - return RDS2Snapshot(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - def promote_read_replica(self, instance_name, **params): - try: - result = self.connection.promote_read_replica(instance_name, **params)['PromoteReadReplicaResponse']['PromoteReadReplicaResult']['DBInstance'] - return RDS2DBInstance(result) - except boto.exception.BotoServerError as e: - raise RDSException(e) - - -class RDSDBInstance: - def __init__(self, dbinstance): - self.instance = dbinstance - self.name = dbinstance.id - self.status = dbinstance.status - - def get_data(self): - d = { - 'id': self.name, - 'create_time': self.instance.create_time, - 'status': self.status, - 'availability_zone': self.instance.availability_zone, - 'backup_retention': self.instance.backup_retention_period, - 'backup_window': self.instance.preferred_backup_window, - 'maintenance_window': self.instance.preferred_maintenance_window, - 'multi_zone': self.instance.multi_az, - 'instance_type': self.instance.instance_class, - 'username': self.instance.master_username, - 'iops': self.instance.iops - } - - # Only assign an Endpoint if one is available - if hasattr(self.instance, 'endpoint'): - d["endpoint"] = self.instance.endpoint[0] - d["port"] = self.instance.endpoint[1] - if self.instance.vpc_security_groups is not None: - d["vpc_security_groups"] = ','.join(x.vpc_group for x in self.instance.vpc_security_groups) - else: - d["vpc_security_groups"] = None - else: - d["endpoint"] = None - d["port"] = None - d["vpc_security_groups"] = None - d['DBName'] = self.instance.DBName if hasattr(self.instance, 'DBName') else None - # ReadReplicaSourceDBInstanceIdentifier may or may not exist - try: - d["replication_source"] = self.instance.ReadReplicaSourceDBInstanceIdentifier - except Exception: - d["replication_source"] = None - return d - - -class RDS2DBInstance: - def __init__(self, dbinstance): - self.instance = dbinstance - if 'DBInstanceIdentifier' not in dbinstance: - self.name = None - else: - self.name = self.instance.get('DBInstanceIdentifier') - self.status = self.instance.get('DBInstanceStatus') - - def get_data(self): - d = { - 'id': self.name, - 'create_time': self.instance['InstanceCreateTime'], - 'engine': self.instance['Engine'], - 'engine_version': self.instance['EngineVersion'], - 'license_model': self.instance['LicenseModel'], - 'character_set_name': self.instance['CharacterSetName'], - 'allocated_storage': self.instance['AllocatedStorage'], - 'publicly_accessible': self.instance['PubliclyAccessible'], - 'latest_restorable_time': self.instance['LatestRestorableTime'], - 'status': self.status, - 'availability_zone': self.instance['AvailabilityZone'], - 'secondary_availability_zone': self.instance['SecondaryAvailabilityZone'], - 'backup_retention': self.instance['BackupRetentionPeriod'], - 'backup_window': self.instance['PreferredBackupWindow'], - 'maintenance_window': self.instance['PreferredMaintenanceWindow'], - 'auto_minor_version_upgrade': self.instance['AutoMinorVersionUpgrade'], - 'read_replica_source_dbinstance_identifier': self.instance['ReadReplicaSourceDBInstanceIdentifier'], - 'multi_zone': self.instance['MultiAZ'], - 'instance_type': self.instance['DBInstanceClass'], - 'username': self.instance['MasterUsername'], - 'db_name': self.instance['DBName'], - 'iops': self.instance['Iops'], - 'replication_source': self.instance['ReadReplicaSourceDBInstanceIdentifier'] - } - if self.instance['DBParameterGroups'] is not None: - parameter_groups = [] - for x in self.instance['DBParameterGroups']: - parameter_groups.append({'parameter_group_name': x['DBParameterGroupName'], 'parameter_apply_status': x['ParameterApplyStatus']}) - d['parameter_groups'] = parameter_groups - if self.instance['OptionGroupMemberships'] is not None: - option_groups = [] - for x in self.instance['OptionGroupMemberships']: - option_groups.append({'status': x['Status'], 'option_group_name': x['OptionGroupName']}) - d['option_groups'] = option_groups - if self.instance['PendingModifiedValues'] is not None: - pdv = self.instance['PendingModifiedValues'] - d['pending_modified_values'] = { - 'multi_az': pdv['MultiAZ'], - 'master_user_password': pdv['MasterUserPassword'], - 'port': pdv['Port'], - 'iops': pdv['Iops'], - 'allocated_storage': pdv['AllocatedStorage'], - 'engine_version': pdv['EngineVersion'], - 'backup_retention_period': pdv['BackupRetentionPeriod'], - 'db_instance_class': pdv['DBInstanceClass'], - 'db_instance_identifier': pdv['DBInstanceIdentifier'] - } - if self.instance["DBSubnetGroup"] is not None: - dsg = self.instance["DBSubnetGroup"] - db_subnet_groups = {} - db_subnet_groups['vpc_id'] = dsg['VpcId'] - db_subnet_groups['name'] = dsg['DBSubnetGroupName'] - db_subnet_groups['status'] = dsg['SubnetGroupStatus'].lower() - db_subnet_groups['description'] = dsg['DBSubnetGroupDescription'] - db_subnet_groups['subnets'] = [] - for x in dsg["Subnets"]: - db_subnet_groups['subnets'].append({ - 'status': x['SubnetStatus'].lower(), - 'identifier': x['SubnetIdentifier'], - 'availability_zone': { - 'name': x['SubnetAvailabilityZone']['Name'], - 'provisioned_iops_capable': x['SubnetAvailabilityZone']['ProvisionedIopsCapable'] - } - }) - d['db_subnet_groups'] = db_subnet_groups - if self.instance["VpcSecurityGroups"] is not None: - d['vpc_security_groups'] = ','.join(x['VpcSecurityGroupId'] for x in self.instance['VpcSecurityGroups']) - if "Endpoint" in self.instance and self.instance["Endpoint"] is not None: - d['endpoint'] = self.instance["Endpoint"].get('Address', None) - d['port'] = self.instance["Endpoint"].get('Port', None) - else: - d['endpoint'] = None - d['port'] = None - d['DBName'] = self.instance['DBName'] if hasattr(self.instance, 'DBName') else None - return d - - -class RDSSnapshot: - def __init__(self, snapshot): - self.snapshot = snapshot - self.name = snapshot.id - self.status = snapshot.status - - def get_data(self): - d = { - 'id': self.name, - 'create_time': self.snapshot.snapshot_create_time, - 'status': self.status, - 'availability_zone': self.snapshot.availability_zone, - 'instance_id': self.snapshot.instance_id, - 'instance_created': self.snapshot.instance_create_time, - } - # needs boto >= 2.21.0 - if hasattr(self.snapshot, 'snapshot_type'): - d["snapshot_type"] = self.snapshot.snapshot_type - if hasattr(self.snapshot, 'iops'): - d["iops"] = self.snapshot.iops - return d - - -class RDS2Snapshot: - def __init__(self, snapshot): - if 'DeleteDBSnapshotResponse' in snapshot: - self.snapshot = snapshot['DeleteDBSnapshotResponse']['DeleteDBSnapshotResult']['DBSnapshot'] - else: - self.snapshot = snapshot - self.name = self.snapshot.get('DBSnapshotIdentifier') - self.status = self.snapshot.get('Status') - - def get_data(self): - d = { - 'id': self.name, - 'create_time': self.snapshot['SnapshotCreateTime'], - 'status': self.status, - 'availability_zone': self.snapshot['AvailabilityZone'], - 'instance_id': self.snapshot['DBInstanceIdentifier'], - 'instance_created': self.snapshot['InstanceCreateTime'], - 'snapshot_type': self.snapshot['SnapshotType'], - 'iops': self.snapshot['Iops'], - } - return d - - -def await_resource(conn, resource, status, module): - start_time = time.time() - wait_timeout = module.params.get('wait_timeout') + start_time - check_interval = 5 - while wait_timeout > time.time() and resource.status != status: - time.sleep(check_interval) - if wait_timeout <= time.time(): - module.fail_json(msg="Timeout waiting for RDS resource %s" % resource.name) - if module.params.get('command') == 'snapshot': - # Temporary until all the rds2 commands have their responses parsed - if resource.name is None: - module.fail_json(msg="There was a problem waiting for RDS snapshot %s" % resource.snapshot) - # Back off if we're getting throttled, since we're just waiting anyway - resource = AWSRetry.jittered_backoff(retries=5, delay=20, backoff=1.5)(conn.get_db_snapshot)(resource.name) - else: - # Temporary until all the rds2 commands have their responses parsed - if resource.name is None: - module.fail_json(msg="There was a problem waiting for RDS instance %s" % resource.instance) - # Back off if we're getting throttled, since we're just waiting anyway - resource = AWSRetry.jittered_backoff(retries=5, delay=20, backoff=1.5)(conn.get_db_instance)(resource.name) - if resource is None: - break - # Some RDS resources take much longer than others to be ready. Check - # less aggressively for slow ones to avoid throttling. - if time.time() > start_time + 90: - check_interval = 20 - return resource - - -def create_db_instance(module, conn): - required_vars = ['instance_name', 'db_engine', 'size', 'instance_type', 'username', 'password'] - valid_vars = ['backup_retention', 'backup_window', - 'character_set_name', 'db_name', 'engine_version', - 'instance_type', 'iops', 'license_model', 'maint_window', - 'multi_zone', 'option_group', 'parameter_group', 'port', - 'subnet', 'upgrade', 'zone'] - if module.params.get('subnet'): - valid_vars.append('vpc_security_groups') - else: - valid_vars.append('security_groups') - if HAS_RDS2: - valid_vars.extend(['publicly_accessible', 'tags']) - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - - result = conn.get_db_instance(instance_name) - if result: - changed = False - else: - try: - result = conn.create_db_instance(instance_name, module.params.get('size'), - module.params.get('instance_type'), module.params.get('db_engine'), - module.params.get('username'), module.params.get('password'), **params) - changed = True - except RDSException as e: - module.fail_json(msg="Failed to create instance: %s" % to_native(e)) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - module.exit_json(changed=changed, instance=resource.get_data()) - - -def replicate_db_instance(module, conn): - required_vars = ['instance_name', 'source_instance'] - valid_vars = ['instance_type', 'port', 'upgrade', 'zone'] - if HAS_RDS2: - valid_vars.extend(['iops', 'option_group', 'publicly_accessible', 'tags']) - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - source_instance = module.params.get('source_instance') - - result = conn.get_db_instance(instance_name) - if result: - changed = False - else: - try: - result = conn.create_db_instance_read_replica(instance_name, source_instance, **params) - changed = True - except RDSException as e: - module.fail_json(msg="Failed to create replica instance: %s " % to_native(e)) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - module.exit_json(changed=changed, instance=resource.get_data()) - - -def delete_db_instance_or_snapshot(module, conn): - required_vars = [] - valid_vars = ['instance_name', 'snapshot', 'skip_final_snapshot'] - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - snapshot = module.params.get('snapshot') - - if not instance_name: - result = conn.get_db_snapshot(snapshot) - else: - result = conn.get_db_instance(instance_name) - if not result: - module.exit_json(changed=False) - if result.status == 'deleting': - module.exit_json(changed=False) - try: - if instance_name: - if snapshot: - params["skip_final_snapshot"] = False - if HAS_RDS2: - params["final_db_snapshot_identifier"] = snapshot - else: - params["final_snapshot_id"] = snapshot - else: - params["skip_final_snapshot"] = True - result = conn.delete_db_instance(instance_name, **params) - else: - result = conn.delete_db_snapshot(snapshot) - except RDSException as e: - module.fail_json(msg="Failed to delete instance: %s" % to_native(e)) - - # If we're not waiting for a delete to complete then we're all done - # so just return - if not module.params.get('wait'): - module.exit_json(changed=True) - try: - await_resource(conn, result, 'deleted', module) - module.exit_json(changed=True) - except RDSException as e: - if e.code == 'DBInstanceNotFound': - module.exit_json(changed=True) - else: - module.fail_json(msg=to_native(e)) - except Exception as e: - module.fail_json(msg=str(e)) - - -def facts_db_instance_or_snapshot(module, conn): - instance_name = module.params.get('instance_name') - snapshot = module.params.get('snapshot') - - if instance_name and snapshot: - module.fail_json(msg="Facts must be called with either instance_name or snapshot, not both") - if instance_name: - resource = conn.get_db_instance(instance_name) - if not resource: - module.fail_json(msg="DB instance %s does not exist" % instance_name) - if snapshot: - resource = conn.get_db_snapshot(snapshot) - if not resource: - module.fail_json(msg="DB snapshot %s does not exist" % snapshot) - - module.exit_json(changed=False, instance=resource.get_data()) - - -def modify_db_instance(module, conn): - required_vars = ['instance_name'] - valid_vars = ['apply_immediately', 'backup_retention', 'backup_window', - 'db_name', 'engine_version', 'instance_type', 'iops', 'license_model', - 'maint_window', 'multi_zone', 'new_instance_name', - 'option_group', 'parameter_group', 'password', 'size', 'upgrade'] - - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - new_instance_name = module.params.get('new_instance_name') - - try: - result = conn.modify_db_instance(instance_name, **params) - except RDSException as e: - module.fail_json(msg=to_native(e)) - if params.get('apply_immediately'): - if new_instance_name: - # Wait until the new instance name is valid - new_instance = None - while not new_instance: - new_instance = conn.get_db_instance(new_instance_name) - time.sleep(5) - - # Found instance but it briefly flicks to available - # before rebooting so let's wait until we see it rebooting - # before we check whether to 'wait' - result = await_resource(conn, new_instance, 'rebooting', module) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - # guess that this changed the DB, need a way to check - module.exit_json(changed=True, instance=resource.get_data()) - - -def promote_db_instance(module, conn): - required_vars = ['instance_name'] - valid_vars = ['backup_retention', 'backup_window'] - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - - result = conn.get_db_instance(instance_name) - if not result: - module.fail_json(msg="DB Instance %s does not exist" % instance_name) - - if result.get_data().get('replication_source'): - try: - result = conn.promote_read_replica(instance_name, **params) - changed = True - except RDSException as e: - module.fail_json(msg=to_native(e)) - else: - changed = False - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - module.exit_json(changed=changed, instance=resource.get_data()) - - -def snapshot_db_instance(module, conn): - required_vars = ['instance_name', 'snapshot'] - valid_vars = ['tags'] - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - snapshot = module.params.get('snapshot') - changed = False - result = conn.get_db_snapshot(snapshot) - if not result: - try: - result = conn.create_db_snapshot(snapshot, instance_name, **params) - changed = True - except RDSException as e: - module.fail_json(msg=to_native(e)) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_snapshot(snapshot) - - module.exit_json(changed=changed, snapshot=resource.get_data()) - - -def reboot_db_instance(module, conn): - required_vars = ['instance_name'] - valid_vars = [] - - if HAS_RDS2: - valid_vars.append('force_failover') - - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - result = conn.get_db_instance(instance_name) - changed = False - try: - result = conn.reboot_db_instance(instance_name, **params) - changed = True - except RDSException as e: - module.fail_json(msg=to_native(e)) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - module.exit_json(changed=changed, instance=resource.get_data()) - - -def restore_db_instance(module, conn): - required_vars = ['instance_name', 'snapshot'] - valid_vars = ['db_name', 'iops', 'license_model', 'multi_zone', - 'option_group', 'port', 'publicly_accessible', - 'subnet', 'tags', 'upgrade', 'zone'] - if HAS_RDS2: - valid_vars.append('instance_type') - else: - required_vars.append('instance_type') - params = validate_parameters(required_vars, valid_vars, module) - instance_name = module.params.get('instance_name') - instance_type = module.params.get('instance_type') - snapshot = module.params.get('snapshot') - - changed = False - result = conn.get_db_instance(instance_name) - if not result: - try: - result = conn.restore_db_instance_from_db_snapshot(instance_name, snapshot, instance_type, **params) - changed = True - except RDSException as e: - module.fail_json(msg=to_native(e)) - - if module.params.get('wait'): - resource = await_resource(conn, result, 'available', module) - else: - resource = conn.get_db_instance(instance_name) - - module.exit_json(changed=changed, instance=resource.get_data()) - - -def validate_parameters(required_vars, valid_vars, module): - command = module.params.get('command') - for v in required_vars: - if not module.params.get(v): - module.fail_json(msg="Parameter %s required for %s command" % (v, command)) - - # map to convert rds module options to boto rds and rds2 options - optional_params = { - 'port': 'port', - 'db_name': 'db_name', - 'zone': 'availability_zone', - 'maint_window': 'preferred_maintenance_window', - 'backup_window': 'preferred_backup_window', - 'backup_retention': 'backup_retention_period', - 'multi_zone': 'multi_az', - 'engine_version': 'engine_version', - 'upgrade': 'auto_minor_version_upgrade', - 'subnet': 'db_subnet_group_name', - 'license_model': 'license_model', - 'option_group': 'option_group_name', - 'size': 'allocated_storage', - 'iops': 'iops', - 'new_instance_name': 'new_instance_id', - 'apply_immediately': 'apply_immediately', - } - # map to convert rds module options to boto rds options - optional_params_rds = { - 'db_engine': 'engine', - 'password': 'master_password', - 'parameter_group': 'param_group', - 'instance_type': 'instance_class', - } - # map to convert rds module options to boto rds2 options - optional_params_rds2 = { - 'tags': 'tags', - 'publicly_accessible': 'publicly_accessible', - 'parameter_group': 'db_parameter_group_name', - 'character_set_name': 'character_set_name', - 'instance_type': 'db_instance_class', - 'password': 'master_user_password', - 'new_instance_name': 'new_db_instance_identifier', - 'force_failover': 'force_failover', - } - if HAS_RDS2: - optional_params.update(optional_params_rds2) - sec_group = 'db_security_groups' - else: - optional_params.update(optional_params_rds) - sec_group = 'security_groups' - # Check for options only supported with rds2 - for k in set(optional_params_rds2.keys()) - set(optional_params_rds.keys()): - if module.params.get(k): - module.fail_json(msg="Parameter %s requires boto.rds (boto >= 2.26.0)" % k) - - params = {} - for (k, v) in optional_params.items(): - if module.params.get(k) is not None and k not in required_vars: - if k in valid_vars: - params[v] = module.params[k] - else: - if module.params.get(k) is False: - pass - else: - module.fail_json(msg="Parameter %s is not valid for %s command" % (k, command)) - - if module.params.get('security_groups'): - params[sec_group] = module.params.get('security_groups').split(',') - - vpc_groups = module.params.get('vpc_security_groups') - if vpc_groups: - if HAS_RDS2: - params['vpc_security_group_ids'] = vpc_groups - else: - groups_list = [] - for x in vpc_groups: - groups_list.append(boto.rds.VPCSecurityGroupMembership(vpc_group=x)) - params['vpc_security_groups'] = groups_list - - # Convert tags dict to list of tuples that rds2 expects - if 'tags' in params: - params['tags'] = module.params['tags'].items() - return params - - -def main(): - argument_spec = dict( - command=dict(choices=['create', 'replicate', 'delete', 'facts', 'modify', 'promote', 'snapshot', 'reboot', 'restore'], required=True), - instance_name=dict(required=False), - source_instance=dict(required=False), - db_engine=dict(choices=['mariadb', 'MySQL', 'oracle-se1', 'oracle-se2', 'oracle-se', 'oracle-ee', 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', - 'sqlserver-web', 'postgres', 'aurora'], required=False), - size=dict(required=False), - instance_type=dict(aliases=['type'], required=False), - username=dict(required=False), - password=dict(no_log=True, required=False), - db_name=dict(required=False), - engine_version=dict(required=False), - parameter_group=dict(required=False), - license_model=dict(choices=['license-included', 'bring-your-own-license', 'general-public-license', 'postgresql-license'], required=False), - multi_zone=dict(type='bool', required=False), - iops=dict(required=False), - security_groups=dict(required=False), - vpc_security_groups=dict(type='list', required=False, elements='str'), - port=dict(required=False, type='int'), - upgrade=dict(type='bool', default=False), - option_group=dict(required=False), - maint_window=dict(required=False), - backup_window=dict(required=False), - backup_retention=dict(required=False), - zone=dict(aliases=['aws_zone', 'ec2_zone'], required=False), - subnet=dict(required=False), - wait=dict(type='bool', default=False), - wait_timeout=dict(type='int', default=300), - snapshot=dict(required=False), - apply_immediately=dict(type='bool', default=False), - new_instance_name=dict(required=False), - tags=dict(type='dict', required=False), - publicly_accessible=dict(required=False), - character_set_name=dict(required=False), - force_failover=dict(type='bool', required=False, default=False), - ) - - module = AnsibleAWSModule( - argument_spec=argument_spec, - check_boto3=False, - ) - - module.deprecate("The 'rds' module has been deprecated and replaced by the 'rds_instance' module'", - version='3.0.0', collection_name='community.aws') - - if not HAS_BOTO: - module.fail_json(msg='boto required for this module') - - invocations = { - 'create': create_db_instance, - 'replicate': replicate_db_instance, - 'delete': delete_db_instance_or_snapshot, - 'facts': facts_db_instance_or_snapshot, - 'modify': modify_db_instance, - 'promote': promote_db_instance, - 'snapshot': snapshot_db_instance, - 'reboot': reboot_db_instance, - 'restore': restore_db_instance, - } - - region, ec2_url, aws_connect_params = get_aws_connection_info(module) - if not region: - module.fail_json(msg="Region must be specified as a parameter, in EC2_REGION or AWS_REGION environment variables or in boto configuration file") - - # set port to per db defaults if not specified - if module.params['port'] is None and module.params['db_engine'] is not None and module.params['command'] == 'create': - if '-' in module.params['db_engine']: - engine = module.params['db_engine'].split('-')[0] - else: - engine = module.params['db_engine'] - module.params['port'] = DEFAULT_PORTS[engine.lower()] - - # connect to the rds endpoint - if HAS_RDS2: - conn = RDS2Connection(module, region, **aws_connect_params) - else: - conn = RDSConnection(module, region, **aws_connect_params) - - invocations[module.params.get('command')](module, conn) - - -if __name__ == '__main__': - main() diff --git a/tests/integration/targets/rds_instance/aliases b/tests/integration/targets/rds_instance/aliases index e30a1801b1e..67aa5c052e2 100644 --- a/tests/integration/targets/rds_instance/aliases +++ b/tests/integration/targets/rds_instance/aliases @@ -1,3 +1,4 @@ +disabled # something is broken slow cloud/aws diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml index e32df5478cd..35d5dd7bdac 100644 --- a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml +++ b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml @@ -1,6 +1,6 @@ --- -instance_id: "{{ resource_prefix }}-{{ inventory_hostname | replace('_','-') }}" -modified_instance_id: "{{ resource_prefix }}-updated" +instance_id: "ansible-test-{{ tiny_prefix }}" +modified_instance_id: "{{ instance_id }}-updated" username: test password: test12345678 db_instance_class: db.t3.micro @@ -12,7 +12,7 @@ monitoring_interval: 60 preferred_maintenance_window: "mon:06:20-mon:06:50" # For aurora tests -cluster_id: "{{ resource_prefix }}-cluster" +cluster_id: "{{ instance_id }}-cluster" aurora_db_instance_class: db.t3.medium # For oracle tests diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index e5bade76474..bde4215eb20 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -1,3 +1,2 @@ plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM -plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt index e5bade76474..bde4215eb20 100644 --- a/tests/sanity/ignore-2.12.txt +++ b/tests/sanity/ignore-2.12.txt @@ -1,3 +1,2 @@ plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM -plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt index e5bade76474..bde4215eb20 100644 --- a/tests/sanity/ignore-2.13.txt +++ b/tests/sanity/ignore-2.13.txt @@ -1,3 +1,2 @@ plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM -plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index e910dea6a74..c9c875d60e5 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -1,9 +1,5 @@ plugins/modules/aws_kms.py pylint:ansible-deprecated-no-version plugins/modules/ec2_metric_alarm.py pylint:ansible-deprecated-no-version plugins/modules/elb_network_lb.py pylint:ansible-deprecated-no-version -plugins/modules/iam.py validate-modules:deprecation-mismatch # Ansible 2.9 docs don't support deprecation properly -plugins/modules/iam.py validate-modules:invalid-documentation # Ansible 2.9 docs don't support deprecation properly plugins/modules/iam_policy.py pylint:ansible-deprecated-no-version plugins/modules/iam_role.py pylint:ansible-deprecated-no-version -plugins/modules/rds.py validate-modules:deprecation-mismatch # Ansible 2.9 docs don't support deprecation properly -plugins/modules/rds.py validate-modules:invalid-documentation # Ansible 2.9 docs don't support deprecation properly