Пример #1
0
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 polices have been removed. Though it appears"
                                                          "that %s has Managed Polices. This is not "
                                                          "currently supported by boto. Please detach the polices "
                                                          "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
Пример #2
0
def create_changeset(module, stack_params, cfn):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        module.fail_json(msg="Either 'template' or 'template_url' is required.")
    if module.params['changeset_name'] is not None:
        stack_params['ChangeSetName'] = module.params['changeset_name']

    # changesets don't accept ClientRequestToken parameters
    stack_params.pop('ClientRequestToken', None)

    try:
        changeset_name = build_changeset_name(stack_params)
        stack_params['ChangeSetName'] = changeset_name

        # Determine if this changeset already exists
        pending_changesets = list_changesets(cfn, stack_params['StackName'])
        if changeset_name in pending_changesets:
            warning = 'WARNING: %d pending changeset(s) exist(s) for this stack!' % len(pending_changesets)
            result = dict(changed=False, output='ChangeSet %s already exists.' % changeset_name, warnings=[warning])
        else:
            cs = cfn.create_change_set(**stack_params)
            # Make sure we don't enter an infinite loop
            time_end = time.time() + 600
            while time.time() < time_end:
                try:
                    newcs = cfn.describe_change_set(ChangeSetName=cs['Id'])
                except botocore.exceptions.BotoCoreError as err:
                    error_msg = boto_exception(err)
                    module.fail_json(msg=error_msg)
                if newcs['Status'] == 'CREATE_PENDING' or newcs['Status'] == 'CREATE_IN_PROGRESS':
                    time.sleep(1)
                elif newcs['Status'] == 'FAILED' and "The submitted information didn't contain changes" in newcs['StatusReason']:
                    cfn.delete_change_set(ChangeSetName=cs['Id'])
                    result = dict(changed=False,
                                  output='Stack is already up-to-date, Change Set refused to create due to lack of changes.')
                    module.exit_json(**result)
                else:
                    break
                # Lets not hog the cpu/spam the AWS API
                time.sleep(1)
            result = stack_operation(cfn, stack_params['StackName'], 'CREATE_CHANGESET')
            result['warnings'] = ['Created changeset named %s for stack %s' % (changeset_name, stack_params['StackName']),
                                  'You can execute it using: aws cloudformation execute-change-set --change-set-name %s' % cs['Id'],
                                  'NOTE that dependencies on this stack might fail due to pending changes!']
    except Exception as err:
        error_msg = boto_exception(err)
        if 'No updates are to be performed.' in error_msg:
            result = dict(changed=False, output='Stack is already up-to-date.')
        else:
            module.fail_json(msg="Failed to create change set: {0}".format(error_msg), exception=traceback.format_exc())

    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #3
0
def role_action(module, iam, name, policy_name, skip, pdoc, state):
    policy_match = False
    changed = False
    try:
        current_policies = [cp for cp in iam.list_role_policies(name).
                            list_role_policies_result.
                            policy_names]
    except boto.exception.BotoServerError as e:
        if e.error_code == "NoSuchEntity":
            # Role doesn't exist so it's safe to assume the policy doesn't either
            module.exit_json(changed=False, msg="No such role, policy will be skipped.")
        else:
            module.fail_json(msg=e.message)

    try:
        matching_policies = []
        for pol in current_policies:
            if urllib.parse.unquote(iam.get_role_policy(name, pol).
                                    get_role_policy_result.policy_document) == pdoc:
                policy_match = True
                matching_policies.append(pol)

        if state == 'present':
            # If policy document does not already exist (either it's changed
            # or the policy is not present) or if we're not skipping dupes then
            # make the put call.  Note that the put call does a create or update.
            if not policy_match or (not skip and policy_name not in matching_policies):
                changed = True
                iam.put_role_policy(name, policy_name, pdoc)
        elif state == 'absent':
            try:
                iam.delete_role_policy(name, policy_name)
                changed = True
            except boto.exception.BotoServerError as err:
                error_msg = boto_exception(err)
                if 'cannot be found.' in error_msg:
                    changed = False
                    module.exit_json(changed=changed,
                                     msg="%s policy is already absent" % policy_name)
                else:
                    module.fail_json(msg=err.message)

        updated_policies = [cp for cp in iam.list_role_policies(name).
                            list_role_policies_result.
                            policy_names]
    except boto.exception.BotoServerError as err:
        error_msg = boto_exception(err)
        module.fail_json(changed=changed, msg=error_msg)

    return changed, name, updated_policies
Пример #4
0
def create_changeset(module, stack_params, cfn):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        module.fail_json(msg="Either 'template' or 'template_url' is required.")

    try:
        changeset_name = build_changeset_name(stack_params)
        stack_params['ChangeSetName'] = changeset_name

        # Determine if this changeset already exists
        pending_changesets = list_changesets(cfn, stack_params['StackName'])
        if changeset_name in pending_changesets:
            warning = 'WARNING: %d pending changeset(s) exist(s) for this stack!' % len(pending_changesets)
            result = dict(changed=False, output='ChangeSet %s already exists.' % changeset_name, warnings=[warning])
        else:
            cs = cfn.create_change_set(**stack_params)
            result = stack_operation(cfn, stack_params['StackName'], 'CREATE_CHANGESET')
            result['warnings'] = ['Created changeset named %s for stack %s' % (changeset_name, stack_params['StackName']),
                'You can execute it using: aws cloudformation execute-change-set --change-set-name %s' % cs['Id'],
                'NOTE that dependencies on this stack might fail due to pending changes!']
    except Exception as err:
        error_msg = boto_exception(err)
        if 'No updates are to be performed.' in error_msg:
            result = dict(changed=False, output='Stack is already up-to-date.')
        else:
            module.fail_json(msg="Failed to create change set: {0}".format(error_msg), exception=traceback.format_exc())

    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #5
0
def check_mode_changeset(module, stack_params, cfn):
    """Create a change set, describe it and delete it before returning check mode outputs."""
    stack_params['ChangeSetName'] = build_changeset_name(stack_params)
    try:
        change_set = cfn.create_change_set(**stack_params)
        for i in range(60): # total time 5 min
            description = cfn.describe_change_set(ChangeSetName=change_set['Id'])
            if description['Status'] in ('CREATE_COMPLETE', 'FAILED'):
                break
            time.sleep(5)
        else:
            # if the changeset doesn't finish in 5 mins, this `else` will trigger and fail
            module.fail_json(msg="Failed to create change set %s" % stack_params['ChangeSetName'])

        cfn.delete_change_set(ChangeSetName=change_set['Id'])

        reason = description.get('StatusReason')

        if description['Status'] == 'FAILED' and "didn't contain changes" in description['StatusReason']:
            return {'changed': False, 'msg': reason, 'meta': description['StatusReason']}
        return {'changed': True, 'msg': reason, 'meta': description['Changes']}

    except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as err:
        error_msg = boto_exception(err)
        module.fail_json(msg=error_msg, exception=traceback.format_exc())
Пример #6
0
def get_stack_events(cfn, stack_name, token_filter=None):
    '''This event data was never correct, it worked as a side effect. So the v2.3 format is different.'''
    ret = {'events': [], 'log': []}

    try:
        pg = cfn.get_paginator(
            'describe_stack_events'
        ).paginate(
            StackName=stack_name
        )
        if token_filter is not None:
            events = list(pg.search(
                "StackEvents[?ClientRequestToken == '{0}']".format(token_filter)
            ))
        else:
            events = list(pg.search("StackEvents[*]"))
    except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as err:
        error_msg = boto_exception(err)
        if 'does not exist' in error_msg:
            # missing stack, don't bail.
            ret['log'].append('Stack does not exist.')
            return ret
        ret['log'].append('Unknown error: ' + str(error_msg))
        return ret

    for e in events:
        eventline = 'StackEvent {ResourceType} {LogicalResourceId} {ResourceStatus}'.format(**e)
        ret['events'].append(eventline)

        if e['ResourceStatus'].endswith('FAILED'):
            failline = '{ResourceType} {LogicalResourceId} {ResourceStatus}: {ResourceStatusReason}'.format(**e)
            ret['log'].append(failline)

    return ret
Пример #7
0
def main():
    argument_spec = ansible.module_utils.ec2.ec2_argument_spec()
    argument_spec.update(dict(
        mode = dict(choices=['grant', 'deny'], default='grant'),
        key_alias = dict(required=False, type='str'),
        key_arn = dict(required=False, type='str'),
        role_name = dict(required=False, type='str'),
        role_arn = dict(required=False, type='str'),
        grant_types = dict(required=False, type='list'),
        clean_invalid_entries = dict(type='bool', default=True),
    )
    )

    module = AnsibleModule(
        supports_check_mode=True,
        argument_spec=argument_spec,
        required_one_of=[['key_alias', 'key_arn'], ['role_name', 'role_arn']],
        required_if=[['mode', 'grant', ['grant_types']]]
    )
    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    result = {}
    mode = module.params['mode']


    try:
        region, ec2_url, aws_connect_kwargs = ansible.module_utils.ec2.get_aws_connection_info(module, boto3=True)
        kms = ansible.module_utils.ec2.boto3_conn(module, conn_type='client', resource='kms', region=region, endpoint=ec2_url, **aws_connect_kwargs)
        iam = ansible.module_utils.ec2.boto3_conn(module, conn_type='client', resource='iam', region=region, endpoint=ec2_url, **aws_connect_kwargs)
    except botocore.exceptions.NoCredentialsError as e:
        module.fail_json(msg='cannot connect to AWS', exception=traceback.format_exc())


    try:
        if module.params['key_alias'] and not module.params['key_arn']:
            module.params['key_arn'] = get_arn_from_kms_alias(kms, module.params['key_alias'])
        if not module.params['key_arn']:
            module.fail_json(msg='key_arn or key_alias is required to {}'.format(mode))

        if module.params['role_name'] and not module.params['role_arn']:
            module.params['role_arn'] = get_arn_from_role_name(iam, module.params['role_name'])
        if not module.params['role_arn']:
            module.fail_json(msg='role_arn or role_name is required to {}'.format(module.params['mode']))

        # check the grant types for 'grant' only.
        if mode == 'grant':
            for g in module.params['grant_types']:
                if not g in statement_label:
                    module.fail_json(msg='{} is an unknown grant type.'.format(g))

        ret = do_grant(kms, module.params['key_arn'], module.params['role_arn'], module.params['grant_types'], mode=mode, dry_run=module.check_mode,
                       clean_invalid_entries=module.params['clean_invalid_entries'])
        result.update(ret)

    except Exception as err:
        error_msg = boto_exception(err)
        module.fail_json(msg=error_msg, exception=traceback.format_exc())

    module.exit_json(**result)
Пример #8
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        mode=dict(choices=['push'], default='push'),
        file_change_strategy=dict(choices=['force', 'date_size', 'checksum'], default='date_size'),
        bucket=dict(required=True),
        key_prefix=dict(required=False, default=''),
        file_root=dict(required=True, type='path'),
        permission=dict(required=False, choices=['private', 'public-read', 'public-read-write', 'authenticated-read',
                                                 'aws-exec-read', 'bucket-owner-read', 'bucket-owner-full-control']),
        retries=dict(required=False),
        mime_map=dict(required=False, type='dict'),
        exclude=dict(required=False, default=".*"),
        include=dict(required=False, default="*"),
        cache_control=dict(required=False, default=''),
        delete=dict(required=False, type='bool', default=False),
        # future options: encoding, metadata, storage_class, retries
    )
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
    )

    if not HAS_DATEUTIL:
        module.fail_json(msg='dateutil required for this module')

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    result = {}
    mode = module.params['mode']

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    if not region:
        module.fail_json(msg="Region must be specified")
    s3 = boto3_conn(module, conn_type='client', resource='s3', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    if mode == 'push':
        try:
            result['filelist_initial'] = gather_files(module.params['file_root'], exclude=module.params['exclude'], include=module.params['include'])
            result['filelist_typed'] = determine_mimetypes(result['filelist_initial'], module.params.get('mime_map'))
            result['filelist_s3'] = calculate_s3_path(result['filelist_typed'], module.params['key_prefix'])
            result['filelist_local_etag'] = calculate_local_etag(result['filelist_s3'])
            result['filelist_actionable'] = filter_list(s3, module.params['bucket'], result['filelist_local_etag'], module.params['file_change_strategy'])
            result['uploads'] = upload_files(s3, module.params['bucket'], result['filelist_actionable'], module.params)

            if module.params['delete']:
                result['removed'] = remove_files(s3, result['filelist_local_etag'], module.params)

            # mark changed if we actually upload something.
            if result.get('uploads') or result.get('removed'):
                result['changed'] = True
            # result.update(filelist=actionable_filelist)
        except botocore.exceptions.ClientError as err:
            error_msg = boto_exception(err)
            module.fail_json(msg=error_msg, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response))

    module.exit_json(**result)
Пример #9
0
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 'Cannot find Login Profile' 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 polices have been removed. Though it appears"
                                                  "that %s has Managed Polices. This is not "
                                                  "currently supported by boto. Please detach the polices "
                                                  "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
Пример #10
0
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 polices have been removed. Though it appears"
                                                              "that %s has Managed Polices. This is not "
                                                              "currently supported by boto. Please detach the polices "
                                                              "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
Пример #11
0
def group_action(module, iam, name, policy_name, skip, pdoc, state):
    policy_match = False
    changed = False
    msg = ''
    try:
        current_policies = [cp for cp in iam.get_all_group_policies(name).
                            list_group_policies_result.
                            policy_names]
        matching_policies = []
        for pol in current_policies:
            if urllib.parse.unquote(iam.get_group_policy(name, pol).
                                    get_group_policy_result.policy_document) == pdoc:
                policy_match = True
                matching_policies.append(pol)
                msg = ("The policy document you specified already exists "
                       "under the name %s." % pol)
        if state == 'present':
            # If policy document does not already exist (either it's changed
            # or the policy is not present) or if we're not skipping dupes then
            # make the put call.  Note that the put call does a create or update.
            if not policy_match or (not skip and policy_name not in matching_policies):
                changed = True
                iam.put_group_policy(name, policy_name, pdoc)
        elif state == 'absent':
            try:
                iam.delete_group_policy(name, policy_name)
                changed = True
            except boto.exception.BotoServerError as err:
                error_msg = boto_exception(err)
                if 'cannot be found.' in error_msg:
                    changed = False
                    module.exit_json(changed=changed,
                                     msg="%s policy is already absent" % policy_name)

        updated_policies = [cp for cp in iam.get_all_group_policies(name).
                            list_group_policies_result.
                            policy_names]
    except boto.exception.BotoServerError as err:
        error_msg = boto_exception(err)
        module.fail_json(changed=changed, msg=error_msg)

    return changed, name, updated_policies, msg
Пример #12
0
def update_termination_protection(module, cfn, stack_name, desired_termination_protection_state):
    '''updates termination protection of a stack'''
    if not boto_supports_termination_protection(cfn):
        module.fail_json(msg="termination_protection parameter requires botocore >= 1.7.18")
    stack = get_stack_facts(cfn, stack_name)
    if stack:
        if stack['EnableTerminationProtection'] is not desired_termination_protection_state:
            try:
                cfn.update_termination_protection(
                    EnableTerminationProtection=desired_termination_protection_state,
                    StackName=stack_name)
            except botocore.exceptions.ClientError as e:
                module.fail_json(msg=boto_exception(e), exception=traceback.format_exc())
Пример #13
0
def create_stack(module, stack_params, cfn):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        module.fail_json(msg="Either 'template' or 'template_url' is required when the stack does not exist.")

    # 'disablerollback' only applies on creation, not update.
    stack_params['DisableRollback'] = module.params['disable_rollback']

    try:
        cfn.create_stack(**stack_params)
        result = stack_operation(cfn, stack_params['StackName'], 'CREATE')
    except Exception as err:
        error_msg = boto_exception(err)
        module.fail_json(msg="Failed to create stack {0}: {1}.".format(stack_params.get('StackName'), error_msg), exception=traceback.format_exc())
    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #14
0
def get_stack_facts(cfn, stack_name):
    try:
        stack_response = cfn.describe_stacks(StackName=stack_name)
        stack_info = stack_response['Stacks'][0]
    except (botocore.exceptions.ValidationError,botocore.exceptions.ClientError) as err:
        error_msg = boto_exception(err)
        if 'does not exist' in error_msg:
            # missing stack, don't bail.
            return None

        # other error, bail.
        raise err

    if stack_response and stack_response.get('Stacks', None):
        stacks = stack_response['Stacks']
        if len(stacks):
            stack_info = stacks[0]

    return stack_info
Пример #15
0
def update_stack(module, stack_params, cfn):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        stack_params['UsePreviousTemplate'] = True

    # if the state is present and the stack already exists, we try to update it.
    # AWS will tell us if the stack template and parameters are the same and
    # don't need to be updated.
    try:
        cfn.update_stack(**stack_params)
        result = stack_operation(cfn, stack_params['StackName'], 'UPDATE')
    except Exception as err:
        error_msg = boto_exception(err)
        if 'No updates are to be performed.' in error_msg:
            result = dict(changed=False, output='Stack is already up-to-date.')
        else:
            module.fail_json(msg="Failed to update stack {0}: {1}".format(stack_params.get('StackName'), error_msg), exception=traceback.format_exc())
    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #16
0
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)
Пример #17
0
def get_stack_events(cfn, stack_name):
    '''This event data was never correct, it worked as a side effect. So the v2.3 format is different.'''
    ret = {'events':[], 'log':[]}

    try:
        events = cfn.describe_stack_events(StackName=stack_name)
    except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as err:
        error_msg = boto_exception(err)
        if 'does not exist' in error_msg:
            # missing stack, don't bail.
            ret['log'].append('Stack does not exist.')
            return ret
        ret['log'].append('Unknown error: ' + str(error_msg))
        return ret

    for e in events.get('StackEvents', []):
        eventline = 'StackEvent {ResourceType} {LogicalResourceId} {ResourceStatus}'.format(**e)
        ret['events'].append(eventline)

        if e['ResourceStatus'].endswith('FAILED'):
            failline = '{ResourceType} {LogicalResourceId} {ResourceStatus}: {ResourceStatusReason}'.format(**e)
            ret['log'].append(failline)

    return ret
Пример #18
0
def create_stack(module, stack_params, cfn):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        module.fail_json(msg="Either 'template', 'template_body' or 'template_url' is required when the stack does not exist.")

    # 'DisableRollback', 'TimeoutInMinutes' and 'EnableTerminationProtection'
    # only apply on creation, not update.
    stack_params['DisableRollback'] = module.params['disable_rollback']
    if module.params.get('create_timeout') is not None:
        stack_params['TimeoutInMinutes'] = module.params['create_timeout']
    if module.params.get('termination_protection') is not None:
        if boto_supports_termination_protection(cfn):
            stack_params['EnableTerminationProtection'] = bool(module.params.get('termination_protection'))
        else:
            module.fail_json(msg="termination_protection parameter requires botocore >= 1.7.18")

    try:
        cfn.create_stack(**stack_params)
        result = stack_operation(cfn, stack_params['StackName'], 'CREATE', stack_params.get('ClientRequestToken', None))
    except Exception as err:
        error_msg = boto_exception(err)
        module.fail_json(msg="Failed to create stack {0}: {1}.".format(stack_params.get('StackName'), error_msg), exception=traceback.format_exc())
    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #19
0
def run(ecr, params, verbosity):
    # type: (EcsEcr, dict, int) -> Tuple[bool, dict]
    result = {}
    try:
        name = params['name']
        state = params['state']
        policy_text = params['policy']
        delete_policy = params['delete_policy']
        registry_id = params['registry_id']
        force_set_policy = params['force_set_policy']
        image_tag_mutability = params['image_tag_mutability'].upper()

        # If a policy was given, parse it
        policy = policy_text and json.loads(policy_text)

        result['state'] = state
        result['created'] = False

        repo = ecr.get_repository(registry_id, name)

        if state == 'present':
            result['created'] = False

            if not repo:
                repo = ecr.create_repository(registry_id, name,
                                             image_tag_mutability)
                result['changed'] = True
                result['created'] = True
            else:
                repo = ecr.put_image_tag_mutability(registry_id, name,
                                                    image_tag_mutability)
            result['repository'] = repo

            if delete_policy:
                original_policy = ecr.get_repository_policy(registry_id, name)

                if verbosity >= 2:
                    result['policy'] = None

                if verbosity >= 3:
                    result['original_policy'] = original_policy

                if original_policy:
                    ecr.delete_repository_policy(registry_id, name)
                    result['changed'] = True

            elif policy_text is not None:
                try:
                    # Sort any lists containing only string types
                    policy = sort_lists_of_strings(policy)

                    if verbosity >= 2:
                        result['policy'] = policy
                    original_policy = ecr.get_repository_policy(
                        registry_id, name)

                    if original_policy:
                        original_policy = sort_lists_of_strings(
                            original_policy)

                    if verbosity >= 3:
                        result['original_policy'] = original_policy

                    if compare_policies(original_policy, policy):
                        ecr.set_repository_policy(registry_id, name,
                                                  policy_text,
                                                  force_set_policy)
                        result['changed'] = True
                except Exception:
                    # Some failure w/ the policy. It's helpful to know what the
                    # policy is.
                    result['policy'] = policy_text
                    raise

        elif state == 'absent':
            result['name'] = name
            if repo:
                ecr.delete_repository(registry_id, name)
                result['changed'] = True

    except Exception as err:
        msg = str(err)
        if isinstance(err, ClientError):
            msg = boto_exception(err)
        result['msg'] = msg
        result['exception'] = traceback.format_exc()
        return False, result

    if ecr.skipped:
        result['skipped'] = True

    if ecr.changed:
        result['changed'] = True

    return True, result
Пример #20
0
def main():
    argument_spec = ansible.module_utils.ec2.ec2_argument_spec()
    argument_spec.update(
        dict(
            mode=dict(choices=['grant', 'deny'], default='grant'),
            key_alias=dict(required=False, type='str'),
            key_arn=dict(required=False, type='str'),
            role_name=dict(required=False, type='str'),
            role_arn=dict(required=False, type='str'),
            grant_types=dict(required=False, type='list'),
            clean_invalid_entries=dict(type='bool', default=True),
        ))

    module = AnsibleModule(supports_check_mode=True,
                           argument_spec=argument_spec,
                           required_one_of=[['key_alias', 'key_arn'],
                                            ['role_name', 'role_arn']],
                           required_if=[['mode', 'grant', ['grant_types']]])
    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    result = {}
    mode = module.params['mode']

    try:
        region, ec2_url, aws_connect_kwargs = ansible.module_utils.ec2.get_aws_connection_info(
            module, boto3=True)
        kms = ansible.module_utils.ec2.boto3_conn(module,
                                                  conn_type='client',
                                                  resource='kms',
                                                  region=region,
                                                  endpoint=ec2_url,
                                                  **aws_connect_kwargs)
        iam = ansible.module_utils.ec2.boto3_conn(module,
                                                  conn_type='client',
                                                  resource='iam',
                                                  region=region,
                                                  endpoint=ec2_url,
                                                  **aws_connect_kwargs)
    except botocore.exceptions.NoCredentialsError as e:
        module.fail_json(msg='cannot connect to AWS',
                         exception=traceback.format_exc())

    try:
        if module.params['key_alias'] and not module.params['key_arn']:
            module.params['key_arn'] = get_arn_from_kms_alias(
                kms, module.params['key_alias'])
        if not module.params['key_arn']:
            module.fail_json(
                msg='key_arn or key_alias is required to {}'.format(mode))

        if module.params['role_name'] and not module.params['role_arn']:
            module.params['role_arn'] = get_arn_from_role_name(
                iam, module.params['role_name'])
        if not module.params['role_arn']:
            module.fail_json(msg='role_arn or role_name is required to {}'.
                             format(module.params['mode']))

        # check the grant types for 'grant' only.
        if mode == 'grant':
            for g in module.params['grant_types']:
                if g not in statement_label:
                    module.fail_json(
                        msg='{} is an unknown grant type.'.format(g))

        ret = do_grant(
            kms,
            module.params['key_arn'],
            module.params['role_arn'],
            module.params['grant_types'],
            mode=mode,
            dry_run=module.check_mode,
            clean_invalid_entries=module.params['clean_invalid_entries'])
        result.update(ret)

    except Exception as err:
        error_msg = boto_exception(err)
        module.fail_json(msg=error_msg, exception=traceback.format_exc())

    module.exit_json(**result)
Пример #21
0
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
Пример #22
0
def main():
    argument_spec = ansible.module_utils.ec2.ec2_argument_spec()
    argument_spec.update(
        dict(stack_name=dict(required=True),
             template_parameters=dict(required=False, type='dict', default={}),
             state=dict(default='present', choices=['present', 'absent']),
             template=dict(default=None, required=False, type='path'),
             notification_arns=dict(default=None, required=False),
             stack_policy=dict(default=None, required=False),
             disable_rollback=dict(default=False, type='bool'),
             template_url=dict(default=None, required=False),
             template_body=dict(default=None, require=False),
             template_format=dict(default=None,
                                  choices=['json', 'yaml'],
                                  required=False),
             create_changeset=dict(default=False, type='bool'),
             changeset_name=dict(default=None, required=False),
             role_arn=dict(default=None, required=False),
             tags=dict(default=None, type='dict'),
             termination_protection=dict(default=None, type='bool')))

    module = AnsibleModule(
        argument_spec=argument_spec,
        mutually_exclusive=[['template_url', 'template', 'template_body']],
        supports_check_mode=True)
    if not HAS_BOTO3:
        module.fail_json(msg='boto3 and botocore are required for this module')

    # collect the parameters that are passed to boto3. Keeps us from having so many scalars floating around.
    stack_params = {
        'Capabilities': ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
        'ClientRequestToken': to_native(uuid.uuid4()),
    }
    state = module.params['state']
    stack_params['StackName'] = module.params['stack_name']

    if module.params['template'] is not None:
        stack_params['TemplateBody'] = open(module.params['template'],
                                            'r').read()
    elif module.params['template_body'] is not None:
        stack_params['TemplateBody'] = module.params['template_body']
    elif module.params['template_url'] is not None:
        stack_params['TemplateURL'] = module.params['template_url']

    if module.params.get('notification_arns'):
        stack_params['NotificationARNs'] = module.params[
            'notification_arns'].split(',')
    else:
        stack_params['NotificationARNs'] = []

    # can't check the policy when verifying.
    if module.params[
            'stack_policy'] is not None and not module.check_mode and not module.params[
                'create_changeset']:
        stack_params['StackPolicyBody'] = open(module.params['stack_policy'],
                                               'r').read()

    template_parameters = module.params['template_parameters']
    stack_params['Parameters'] = [{
        'ParameterKey': k,
        'ParameterValue': str(v)
    } for k, v in template_parameters.items()]

    if isinstance(module.params.get('tags'), dict):
        stack_params[
            'Tags'] = ansible.module_utils.ec2.ansible_dict_to_boto3_tag_list(
                module.params['tags'])

    if module.params.get('role_arn'):
        stack_params['RoleARN'] = module.params['role_arn']

    result = {}

    try:
        region, ec2_url, aws_connect_kwargs = ansible.module_utils.ec2.get_aws_connection_info(
            module, boto3=True)
        cfn = ansible.module_utils.ec2.boto3_conn(module,
                                                  conn_type='client',
                                                  resource='cloudformation',
                                                  region=region,
                                                  endpoint=ec2_url,
                                                  **aws_connect_kwargs)
    except botocore.exceptions.NoCredentialsError as e:
        module.fail_json(msg=boto_exception(e))

    # Wrap the cloudformation client methods that this module uses with
    # automatic backoff / retry for throttling error codes
    backoff_wrapper = AWSRetry.jittered_backoff(retries=10,
                                                delay=3,
                                                max_delay=30)
    cfn.describe_stack_events = backoff_wrapper(cfn.describe_stack_events)
    cfn.create_stack = backoff_wrapper(cfn.create_stack)
    cfn.list_change_sets = backoff_wrapper(cfn.list_change_sets)
    cfn.create_change_set = backoff_wrapper(cfn.create_change_set)
    cfn.update_stack = backoff_wrapper(cfn.update_stack)
    cfn.describe_stacks = backoff_wrapper(cfn.describe_stacks)
    cfn.list_stack_resources = backoff_wrapper(cfn.list_stack_resources)
    cfn.delete_stack = backoff_wrapper(cfn.delete_stack)
    if boto_supports_termination_protection(cfn):
        cfn.update_termination_protection = backoff_wrapper(
            cfn.update_termination_protection)

    stack_info = get_stack_facts(cfn, stack_params['StackName'])

    if module.check_mode:
        if state == 'absent' and stack_info:
            module.exit_json(changed=True,
                             msg='Stack would be deleted',
                             meta=[])
        elif state == 'absent' and not stack_info:
            module.exit_json(changed=False,
                             msg='Stack doesn\'t exist',
                             meta=[])
        elif state == 'present' and not stack_info:
            module.exit_json(changed=True,
                             msg='New stack would be created',
                             meta=[])
        else:
            module.exit_json(**check_mode_changeset(module, stack_params, cfn))

    if state == 'present':
        if not stack_info:
            result = create_stack(module, stack_params, cfn)
        elif module.params.get('create_changeset'):
            result = create_changeset(module, stack_params, cfn)
        else:
            if module.params.get('termination_protection') is not None:
                update_termination_protection(
                    module, cfn, stack_params['StackName'],
                    bool(module.params.get('termination_protection')))
            result = update_stack(module, stack_params, cfn)

        # format the stack output

        stack = get_stack_facts(cfn, stack_params['StackName'])
        if result.get('stack_outputs') is None:
            # always define stack_outputs, but it may be empty
            result['stack_outputs'] = {}
        for output in stack.get('Outputs', []):
            result['stack_outputs'][
                output['OutputKey']] = output['OutputValue']
        stack_resources = []
        reslist = cfn.list_stack_resources(StackName=stack_params['StackName'])
        for res in reslist.get('StackResourceSummaries', []):
            stack_resources.append({
                "logical_resource_id":
                res['LogicalResourceId'],
                "physical_resource_id":
                res.get('PhysicalResourceId', ''),
                "resource_type":
                res['ResourceType'],
                "last_updated_time":
                res['LastUpdatedTimestamp'],
                "status":
                res['ResourceStatus'],
                "status_reason":
                res.get('ResourceStatusReason')  # can be blank, apparently
            })
        result['stack_resources'] = stack_resources

    elif state == 'absent':
        # absent state is different because of the way delete_stack works.
        # problem is it it doesn't give an error if stack isn't found
        # so must describe the stack first

        try:
            stack = get_stack_facts(cfn, stack_params['StackName'])
            if not stack:
                result = {'changed': False, 'output': 'Stack not found.'}
            else:
                if stack_params.get('RoleARN') is None:
                    cfn.delete_stack(StackName=stack_params['StackName'])
                else:
                    cfn.delete_stack(StackName=stack_params['StackName'],
                                     RoleARN=stack_params['RoleARN'])
                result = stack_operation(
                    cfn, stack_params['StackName'], 'DELETE',
                    stack_params.get('ClientRequestToken', None))
        except Exception as err:
            module.fail_json(msg=boto_exception(err),
                             exception=traceback.format_exc())

    if module.params['template_format'] is not None:
        result['warnings'] = [
            ('Argument `template_format` is deprecated '
             'since Ansible 2.3, JSON and YAML templates are now passed '
             'directly to the CloudFormation API.')
        ]
    module.exit_json(**result)
Пример #23
0
def run(ecr, params, verbosity):
    # type: (EcsEcr, dict, int) -> Tuple[bool, dict]
    result = {}
    try:
        name = params['name']
        state = params['state']
        policy_text = params['policy']
        delete_policy = params['delete_policy']
        registry_id = params['registry_id']
        force_set_policy = params['force_set_policy']

        # If a policy was given, parse it
        policy = policy_text and json.loads(policy_text)

        result['state'] = state
        result['created'] = False

        repo = ecr.get_repository(registry_id, name)

        if state == 'present':
            result['created'] = False
            if not repo:
                repo = ecr.create_repository(registry_id, name)
                result['changed'] = True
                result['created'] = True
            result['repository'] = repo

            if delete_policy:
                original_policy = ecr.get_repository_policy(registry_id, name)

                if verbosity >= 2:
                    result['policy'] = None

                if verbosity >= 3:
                    result['original_policy'] = original_policy

                if original_policy:
                    ecr.delete_repository_policy(registry_id, name)
                    result['changed'] = True

            elif policy_text is not None:
                try:
                    policy = sort_json_policy_dict(policy)
                    if verbosity >= 2:
                        result['policy'] = policy
                    original_policy = ecr.get_repository_policy(
                        registry_id, name)

                    if original_policy:
                        original_policy = sort_json_policy_dict(original_policy)

                    if verbosity >= 3:
                        result['original_policy'] = original_policy

                    if original_policy != policy:
                        ecr.set_repository_policy(
                            registry_id, name, policy_text, force_set_policy)
                        result['changed'] = True
                except:
                    # Some failure w/ the policy. It's helpful to know what the
                    # policy is.
                    result['policy'] = policy_text
                    raise

        elif state == 'absent':
            result['name'] = name
            if repo:
                ecr.delete_repository(registry_id, name)
                result['changed'] = True

    except Exception as err:
        msg = str(err)
        if isinstance(err, ClientError):
            msg = boto_exception(err)
        result['msg'] = msg
        result['exception'] = traceback.format_exc()
        return False, result

    if ecr.skipped:
        result['skipped'] = True

    if ecr.changed:
        result['changed'] = True

    return True, result
Пример #24
0
def main():
    argument_spec = ansible.module_utils.ec2.ec2_argument_spec()
    argument_spec.update(dict(
        stack_name=dict(required=True),
        template_parameters=dict(required=False, type='dict', default={}),
        state=dict(default='present', choices=['present', 'absent']),
        template=dict(default=None, required=False, type='path'),
        notification_arns=dict(default=None, required=False),
        stack_policy=dict(default=None, required=False),
        disable_rollback=dict(default=False, type='bool'),
        template_url=dict(default=None, required=False),
        template_format=dict(default=None, choices=['json', 'yaml'], required=False),
        create_changeset=dict(default=False, type='bool'),
        changeset_name=dict(default=None, required=False),
        role_arn=dict(default=None, required=False),
        tags=dict(default=None, type='dict')
    )
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        mutually_exclusive=[['template_url', 'template']],
        supports_check_mode=True
    )
    if not HAS_BOTO3:
        module.fail_json(msg='boto3 and botocore are required for this module')

    # collect the parameters that are passed to boto3. Keeps us from having so many scalars floating around.
    stack_params = {
        'Capabilities': ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
    }
    state = module.params['state']
    stack_params['StackName'] = module.params['stack_name']

    if module.params['template'] is not None:
        stack_params['TemplateBody'] = open(module.params['template'], 'r').read()
    elif module.params['template_url'] is not None:
        stack_params['TemplateURL'] = module.params['template_url']

    if module.params.get('notification_arns'):
        stack_params['NotificationARNs'] = module.params['notification_arns'].split(',')
    else:
        stack_params['NotificationARNs'] = []

    if module.params['stack_policy'] is not None:
        stack_params['StackPolicyBody'] = open(module.params['stack_policy'], 'r').read()

    if module.params['changeset_name'] is not None:
        stack_params['ChangeSetName'] = module.params['changeset_name']

    template_parameters = module.params['template_parameters']
    stack_params['Parameters'] = [{'ParameterKey':k, 'ParameterValue':str(v)} for k, v in template_parameters.items()]

    if isinstance(module.params.get('tags'), dict):
        stack_params['Tags'] = ansible.module_utils.ec2.ansible_dict_to_boto3_tag_list(module.params['tags'])

    if module.params.get('role_arn'):
        stack_params['RoleARN'] = module.params['role_arn']

    result = {}

    try:
        region, ec2_url, aws_connect_kwargs = ansible.module_utils.ec2.get_aws_connection_info(module, boto3=True)
        cfn = ansible.module_utils.ec2.boto3_conn(module, conn_type='client', resource='cloudformation', region=region, endpoint=ec2_url, **aws_connect_kwargs)
    except botocore.exceptions.NoCredentialsError as e:
        module.fail_json(msg=boto_exception(e))

    # Wrap the cloudformation client methods that this module uses with
    # automatic backoff / retry for throttling error codes
    backoff_wrapper = AWSRetry.jittered_backoff(retries=10, delay=3, max_delay=30)
    cfn.describe_stack_events = backoff_wrapper(cfn.describe_stack_events)
    cfn.create_stack = backoff_wrapper(cfn.create_stack)
    cfn.list_change_sets = backoff_wrapper(cfn.list_change_sets)
    cfn.create_change_set = backoff_wrapper(cfn.create_change_set)
    cfn.update_stack = backoff_wrapper(cfn.update_stack)
    cfn.describe_stacks = backoff_wrapper(cfn.describe_stacks)
    cfn.list_stack_resources = backoff_wrapper(cfn.list_stack_resources)
    cfn.delete_stack = backoff_wrapper(cfn.delete_stack)

    stack_info = get_stack_facts(cfn, stack_params['StackName'])

    if module.check_mode:
        if state == 'absent' and stack_info:
            module.exit_json(changed=True, msg='Stack would be deleted', meta=[])
        elif state == 'absent' and not stack_info:
            module.exit_json(changed=False, msg='Stack doesn\'t exist', meta=[])
        elif state == 'present' and not stack_info:
            module.exit_json(changed=True, msg='New stack would be created', meta=[])
        else:
            module.exit_json(**check_mode_changeset(module, stack_params, cfn))

    if state == 'present':
        if not stack_info:
            result = create_stack(module, stack_params, cfn)
        elif module.params.get('create_changeset'):
            result = create_changeset(module, stack_params, cfn)
        else:
            result = update_stack(module, stack_params, cfn)

        # format the stack output

        stack = get_stack_facts(cfn, stack_params['StackName'])
        if result.get('stack_outputs') is None:
            # always define stack_outputs, but it may be empty
            result['stack_outputs'] = {}
        for output in stack.get('Outputs', []):
            result['stack_outputs'][output['OutputKey']] = output['OutputValue']
        stack_resources = []
        reslist = cfn.list_stack_resources(StackName=stack_params['StackName'])
        for res in reslist.get('StackResourceSummaries', []):
            stack_resources.append({
                "logical_resource_id": res['LogicalResourceId'],
                "physical_resource_id": res.get('PhysicalResourceId', ''),
                "resource_type": res['ResourceType'],
                "last_updated_time": res['LastUpdatedTimestamp'],
                "status": res['ResourceStatus'],
                "status_reason": res.get('ResourceStatusReason') # can be blank, apparently
            })
        result['stack_resources'] = stack_resources

    elif state == 'absent':
        # absent state is different because of the way delete_stack works.
        # problem is it it doesn't give an error if stack isn't found
        # so must describe the stack first

        try:
            stack = get_stack_facts(cfn, stack_params['StackName'])
            if not stack:
                result = {'changed': False, 'output': 'Stack not found.'}
            else:
                cfn.delete_stack(StackName=stack_params['StackName'])
                result = stack_operation(cfn, stack_params['StackName'], 'DELETE')
        except Exception as err:
            module.fail_json(msg=boto_exception(err), exception=traceback.format_exc())

    if module.params['template_format'] is not None:
        result['warnings'] = [('Argument `template_format` is deprecated '
            'since Ansible 2.3, JSON and YAML templates are now passed '
            'directly to the CloudFormation API.')]
    module.exit_json(**result)
Пример #25
0
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
Пример #26
0
def create_changeset(module, stack_params, cfn, events_limit):
    if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
        module.fail_json(
            msg="Either 'template' or 'template_url' is required.")
    if module.params['changeset_name'] is not None:
        stack_params['ChangeSetName'] = module.params['changeset_name']

    # changesets don't accept ClientRequestToken parameters
    stack_params.pop('ClientRequestToken', None)

    try:
        changeset_name = build_changeset_name(stack_params)
        stack_params['ChangeSetName'] = changeset_name

        # Determine if this changeset already exists
        pending_changesets = list_changesets(cfn, stack_params['StackName'])
        if changeset_name in pending_changesets:
            warning = 'WARNING: %d pending changeset(s) exist(s) for this stack!' % len(
                pending_changesets)
            result = dict(changed=False,
                          output='ChangeSet %s already exists.' %
                          changeset_name,
                          warnings=[warning])
        else:
            cs = cfn.create_change_set(**stack_params)
            # Make sure we don't enter an infinite loop
            time_end = time.time() + 600
            while time.time() < time_end:
                try:
                    newcs = cfn.describe_change_set(ChangeSetName=cs['Id'])
                except botocore.exceptions.BotoCoreError as err:
                    error_msg = boto_exception(err)
                    module.fail_json(msg=error_msg)
                if newcs['Status'] == 'CREATE_PENDING' or newcs[
                        'Status'] == 'CREATE_IN_PROGRESS':
                    time.sleep(1)
                elif newcs[
                        'Status'] == 'FAILED' and "The submitted information didn't contain changes" in newcs[
                            'StatusReason']:
                    cfn.delete_change_set(ChangeSetName=cs['Id'])
                    result = dict(
                        changed=False,
                        output=
                        'Stack is already up-to-date, Change Set refused to create due to lack of changes.'
                    )
                    module.exit_json(**result)
                else:
                    break
                # Lets not hog the cpu/spam the AWS API
                time.sleep(1)
            result = stack_operation(cfn, stack_params['StackName'],
                                     'CREATE_CHANGESET', events_limit)
            result['warnings'] = [
                'Created changeset named %s for stack %s' %
                (changeset_name, stack_params['StackName']),
                'You can execute it using: aws cloudformation execute-change-set --change-set-name %s'
                % cs['Id'],
                'NOTE that dependencies on this stack might fail due to pending changes!'
            ]
    except Exception as err:
        error_msg = boto_exception(err)
        if 'No updates are to be performed.' in error_msg:
            result = dict(changed=False, output='Stack is already up-to-date.')
        else:
            module.fail_json(
                msg="Failed to create change set: {0}".format(error_msg),
                exception=traceback.format_exc())

    if not result:
        module.fail_json(msg="empty result")
    return result
Пример #27
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            mode=dict(choices=['push'], default='push'),
            file_change_strategy=dict(
                choices=['force', 'date_size', 'checksum'],
                default='date_size'),
            bucket=dict(required=True),
            key_prefix=dict(required=False, default=''),
            file_root=dict(required=True, type='path'),
            permission=dict(required=False,
                            choices=[
                                'private', 'public-read', 'public-read-write',
                                'authenticated-read', 'aws-exec-read',
                                'bucket-owner-read',
                                'bucket-owner-full-control'
                            ]),
            retries=dict(required=False),
            mime_map=dict(required=False, type='dict'),
            exclude=dict(required=False, default=".*"),
            include=dict(required=False, default="*"),
            cache_control=dict(required=False, default=''),
            delete=dict(required=False, type='bool', default=False),
            # future options: encoding, metadata, storage_class, retries
        ))

    module = AnsibleModule(argument_spec=argument_spec, )
    if not HAS_BOTO3:
        module.fail_json(msg='boto3 required for this module')

    result = {}
    mode = module.params['mode']

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module,
                                                                  boto3=True)
    if not region:
        module.fail_json(msg="Region must be specified")
    s3 = boto3_conn(module,
                    conn_type='client',
                    resource='s3',
                    region=region,
                    endpoint=ec2_url,
                    **aws_connect_kwargs)

    if mode == 'push':
        try:
            result['filelist_initial'] = gather_files(
                module.params['file_root'],
                exclude=module.params['exclude'],
                include=module.params['include'])
            result['filelist_typed'] = determine_mimetypes(
                result['filelist_initial'], module.params.get('mime_map'))
            result['filelist_s3'] = calculate_s3_path(
                result['filelist_typed'], module.params['key_prefix'])
            result['filelist_local_etag'] = calculate_local_etag(
                result['filelist_s3'])
            result['filelist_actionable'] = filter_list(
                s3, module.params['bucket'], result['filelist_local_etag'],
                module.params['file_change_strategy'])
            result['uploads'] = upload_files(s3, module.params['bucket'],
                                             result['filelist_actionable'],
                                             module.params)

            if module.params['delete']:
                result['removed'] = remove_files(s3,
                                                 result['filelist_local_etag'],
                                                 module.params)

            # mark changed if we actually upload something.
            if result.get('uploads') or result.get('removed'):
                result['changed'] = True
            # result.update(filelist=actionable_filelist)
        except botocore.exceptions.ClientError as err:
            error_msg = boto_exception(err)
            module.fail_json(msg=error_msg,
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(err.response))

    module.exit_json(**result)
Пример #28
0
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