Ejemplo n.º 1
0
def get_trail_facts(module, client, name):
    """
    Describes existing trail in an account

    module : AnsibleModule object
    client : boto3 client connection object
    name : Name of the trail
    """
    # get Trail info
    try:
        trail_resp = client.describe_trails(trailNameList=[name])
    except ClientError as err:
        module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response))

    # Now check to see if our trail exists and get status and tags
    if len(trail_resp['trailList']):
        trail = trail_resp['trailList'][0]
        try:
            status_resp = client.get_trail_status(Name=trail['Name'])
            tags_list = client.list_tags(ResourceIdList=[trail['TrailARN']])
        except ClientError as err:
            module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response))

        trail['IsLogging'] = status_resp['IsLogging']
        trail['tags'] = boto3_tag_list_to_ansible_dict(tags_list['ResourceTagList'][0]['TagsList'])
        # Check for non-existent values and populate with None
        optional_vals = set(['S3KeyPrefix', 'SnsTopicName', 'SnsTopicARN', 'CloudWatchLogsLogGroupArn', 'CloudWatchLogsRoleArn', 'KmsKeyId'])
        for v in optional_vals - set(trail.keys()):
            trail[v] = None
        return trail

    else:
        # trail doesn't exist return None
        return None
Ejemplo n.º 2
0
def describe_subnets(connection, module):
    """
    Describe Subnets.

    module  : AnsibleModule object
    connection  : boto3 client connection object
    """
    # collect parameters
    filters = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
    subnet_ids = module.params.get('subnet_ids')

    if subnet_ids is None:
        # Set subnet_ids to empty list if it is None
        subnet_ids = []

    # init empty list for return vars
    subnet_info = list()

    # Get the basic VPC info
    try:
        response = describe_subnets_with_backoff(connection, subnet_ids, filters)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    for subnet in response['Subnets']:
        # for backwards compatibility
        subnet['id'] = subnet['SubnetId']
        subnet_info.append(camel_dict_to_snake_dict(subnet))
        # convert tag list to ansible dict
        subnet_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(subnet.get('Tags', []))

    module.exit_json(subnets=subnet_info)
Ejemplo n.º 3
0
def update_tags(module, connection, group, tags):
    changed = False
    existing_tags = connection.list_tags_for_resource(ResourceName=group['DBParameterGroupArn'])['TagList']
    to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(existing_tags),
                                            tags, module.params['purge_tags'])
    if to_update:
        try:
            connection.add_tags_to_resource(ResourceName=group['DBParameterGroupArn'],
                                            Tags=ansible_dict_to_boto3_tag_list(to_update))
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't add tags to parameter group: %s" % str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        except botocore.exceptions.ParamValidationError as e:
            # Usually a tag value has been passed as an int or bool, needs to be a string
            # The AWS exception message is reasonably ok for this purpose
            module.fail_json(msg="Couldn't add tags to parameter group: %s." % str(e),
                             exception=traceback.format_exc())
    if to_delete:
        try:
            connection.remove_tags_from_resource(ResourceName=group['DBParameterGroupArn'],
                                                 TagKeys=to_delete)
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't remove tags from parameter group: %s" % str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    return changed
Ejemplo n.º 4
0
def create_vpc_endpoint(client, module):
    params = dict()
    changed = False
    token_provided = False
    params['VpcId'] = module.params.get('vpc_id')
    params['ServiceName'] = module.params.get('service')
    params['DryRun'] = module.check_mode

    if module.params.get('route_table_ids'):
        params['RouteTableIds'] = module.params.get('route_table_ids')

    if module.params.get('client_token'):
        token_provided = True
        request_time = datetime.datetime.utcnow()
        params['ClientToken'] = module.params.get('client_token')

    policy = None
    if module.params.get('policy'):
        try:
            policy = json.loads(module.params.get('policy'))
        except ValueError as e:
            module.fail_json(msg=str(e), exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    elif module.params.get('policy_file'):
        try:
            with open(module.params.get('policy'), 'r') as json_data:
                policy = json.load(json_data)
        except Exception as e:
            module.fail_json(msg=str(e), exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    if policy:
        params['PolicyDocument'] = json.dumps(policy)

    try:
        changed = True
        result = camel_dict_to_snake_dict(client.create_vpc_endpoint(**params)['VpcEndpoint'])
        if token_provided and (request_time > result['creation_timestamp'].replace(tzinfo=None)):
            changed = False
        elif module.params.get('wait') and not module.check_mode:
            status_achieved, result = wait_for_status(client, module, result['vpc_endpoint_id'], 'available')
            if not status_achieved:
                module.fail_json(msg='Error waiting for vpc endpoint to become available - please check the AWS console')
    except botocore.exceptions.ClientError as e:
        if "DryRunOperation" in e.message:
            changed = True
            result = 'Would have created VPC Endpoint if not in check mode'
        elif "IdempotentParameterMismatch" in e.message:
            module.fail_json(msg="IdempotentParameterMismatch - updates of endpoints are not allowed by the API")
        elif "RouteAlreadyExists" in e.message:
            module.fail_json(msg="RouteAlreadyExists for one of the route tables - update is not allowed by the API")
        else:
            module.fail_json(msg=str(e), exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    except Exception as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    return changed, result
Ejemplo n.º 5
0
def detach_all_entities(module, iam, policy, **kwargs):
    try:
        entities = iam.list_entities_for_policy(PolicyArn=policy['Arn'], **kwargs)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't detach list entities for policy %s: %s" % (policy['PolicyName'], str(e)),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    for g in entities['PolicyGroups']:
        try:
            iam.detach_group_policy(PolicyArn=policy['Arn'], GroupName=g['GroupName'])
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't detach group policy %s: %s" % (g['GroupName'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    for u in entities['PolicyUsers']:
        try:
            iam.detach_user_policy(PolicyArn=policy['Arn'], UserName=u['UserName'])
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't detach user policy %s: %s" % (u['UserName'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    for r in entities['PolicyRoles']:
        try:
            iam.detach_role_policy(PolicyArn=policy['Arn'], RoleName=r['RoleName'])
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't detach role policy %s: %s" % (r['RoleName'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    if entities['IsTruncated']:
        detach_all_entities(module, iam, policy, marker=entities['Marker'])
Ejemplo n.º 6
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            vpc_id=dict(),
            service=dict(),
            policy=dict(type='json'),
            policy_file=dict(type='path'),
            state=dict(default='present', choices=['present', 'absent']),
            wait=dict(type='bool', default=False),
            wait_timeout=dict(type='int', default=320, required=False),
            route_table_ids=dict(type='list'),
            vpc_endpoint_id=dict(),
            client_token=dict(),
        )
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        mutually_exclusive=[['policy', 'policy_file']],
        required_if=[
            ['state', 'present', ['vpc_id', 'service']],
            ['state', 'absent', ['vpc_endpoint_id']],
        ]
    )

    # Validate Requirements
    if not HAS_BOTO3:
        module.fail_json(msg='botocore and boto3 are required for this module')

    state = module.params.get('state')

    try:
        region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    except NameError as e:
        # Getting around the get_aws_connection_info boto reliance for region
        if "global name 'boto' is not defined" in e.message:
            module.params['region'] = botocore.session.get_session().get_config_variable('region')
            if not module.params['region']:
                module.fail_json(msg="Error - no region provided")
        else:
            module.fail_json(msg="Can't retrieve connection information - " + str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    try:
        region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
        ec2 = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs)
    except botocore.exceptions.NoCredentialsError as e:
        module.fail_json(msg="Failed to connect to AWS due to wrong or missing credentials: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    # Ensure resource is present
    if state == 'present':
        (changed, results) = setup_creation(ec2, module)
    else:
        (changed, results) = setup_removal(ec2, module)

    module.exit_json(changed=changed, result=results)
Ejemplo n.º 7
0
def create_or_update_identity(connection, module, region, account_id):
    identity = module.params.get('identity')
    changed = False
    verification_attributes = get_verification_attributes(connection, module, identity)
    if verification_attributes is None:
        if '@' in identity:
            call_and_handle_errors(module, connection.verify_email_identity, EmailAddress=identity)
        else:
            call_and_handle_errors(module, connection.verify_domain_identity, Domain=identity)
        verification_attributes = get_verification_attributes(connection, module, identity, retries=4)
        changed = True
    elif verification_attributes['VerificationStatus'] not in ('Pending', 'Success'):
        module.fail_json(msg="Identity " + identity + " in bad status " + verification_attributes['VerificationStatus'],
                         verification_attributes=camel_dict_to_snake_dict(verification_attributes))

    if verification_attributes is None:
        module.fail_json(msg='Unable to load identity verification attributes after registering identity.')

    notifications_changed, notification_attributes = update_identity_notifications(connection, module)
    changed |= notifications_changed

    if notification_attributes is None:
        module.fail_json(msg='Unable to load identity notification attributes.')

    identity_arn = 'arn:aws:ses:' + region + ':' + account_id + ':identity/' + identity

    module.exit_json(
        changed=changed,
        identity=identity,
        identity_arn=identity_arn,
        verification_attributes=camel_dict_to_snake_dict(verification_attributes),
        notification_attributes=camel_dict_to_snake_dict(notification_attributes),
    )
Ejemplo n.º 8
0
def get_subnet_info(subnet):
    if 'Subnets' in subnet:
        return [get_subnet_info(s) for s in subnet['Subnets']]
    elif 'Subnet' in subnet:
        subnet = camel_dict_to_snake_dict(subnet['Subnet'])
    else:
        subnet = camel_dict_to_snake_dict(subnet)

    if 'tags' in subnet:
        subnet['tags'] = boto3_tag_list_to_ansible_dict(subnet['tags'])
    else:
        subnet['tags'] = dict()

    if 'subnet_id' in subnet:
        subnet['id'] = subnet['subnet_id']
        del subnet['subnet_id']

    subnet['ipv6_cidr_block'] = ''
    subnet['ipv6_association_id'] = ''
    ipv6set = subnet.get('ipv6_cidr_block_association_set')
    if ipv6set:
        for item in ipv6set:
            if item.get('ipv6_cidr_block_state', {}).get('state') in ('associated', 'associating'):
                subnet['ipv6_cidr_block'] = item['ipv6_cidr_block']
                subnet['ipv6_association_id'] = item['association_id']

    return subnet
Ejemplo n.º 9
0
def find_clusters(conn, module, identifier=None, tags=None):

    try:
        cluster_paginator = conn.get_paginator('describe_clusters')
        clusters = cluster_paginator.paginate().build_full_result()
    except ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    matched_clusters = []

    if identifier is not None:
        identifier_prog = re.compile('^' + identifier)

    for cluster in clusters['Clusters']:

        matched_identifier = True
        if identifier:
            matched_identifier = identifier_prog.search(cluster['ClusterIdentifier'])

        matched_tags = True
        if tags:
            matched_tags = match_tags(tags, cluster)

        if matched_identifier and matched_tags:
            matched_clusters.append(camel_dict_to_snake_dict(cluster))

    return matched_clusters
Ejemplo n.º 10
0
def get_key_details(connection, module, key_id, tokens=None):
    if not tokens:
        tokens = []
    try:
        result = get_kms_metadata_with_backoff(connection, key_id)['KeyMetadata']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed to obtain key metadata",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    result['KeyArn'] = result.pop('Arn')

    try:
        aliases = get_kms_aliases_lookup(connection)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed to obtain aliases",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    result['aliases'] = aliases.get(result['KeyId'], [])

    if module.params.get('pending_deletion'):
        return camel_dict_to_snake_dict(result)

    try:
        result['grants'] = get_kms_grants_with_backoff(connection, key_id, tokens=tokens)['Grants']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed to obtain key grants",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    tags = get_kms_tags(connection, module, key_id)

    result = camel_dict_to_snake_dict(result)
    result['tags'] = boto3_tag_list_to_ansible_dict(tags, 'TagKey', 'TagValue')
    result['policies'] = get_kms_policies(connection, module, key_id)
    return result
Ejemplo n.º 11
0
def destroy_role(connection, module):

    params = dict()
    params['RoleName'] = module.params.get('name')

    if get_role(connection, module, params['RoleName']):

        # We need to remove any instance profiles from the role before we delete it
        try:
            instance_profiles = connection.list_instance_profiles_for_role(RoleName=params['RoleName'])['InstanceProfiles']
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

        # Now remove the role from the instance profile(s)
        for profile in instance_profiles:
            try:
                connection.remove_role_from_instance_profile(InstanceProfileName=profile['InstanceProfileName'], RoleName=params['RoleName'])
            except ClientError as e:
                module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

        # Now remove any attached policies otherwise deletion fails
        try:
            for policy in get_attached_policy_list(connection, module, params['RoleName']):
                connection.detach_role_policy(RoleName=params['RoleName'], PolicyArn=policy['PolicyArn'])
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

        try:
            connection.delete_role(**params)
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
    else:
        module.exit_json(changed=False)

    module.exit_json(changed=True)
Ejemplo n.º 12
0
def destroy_group(connection, module):

    params = dict()
    params['GroupName'] = module.params.get('name')

    try:
        group = get_group(connection, module, params['GroupName'])
    except ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    if group:
        # Check mode means we would remove this group
        if module.check_mode:
            module.exit_json(changed=True)

        # Remove any attached policies otherwise deletion fails
        try:
            for policy in get_attached_policy_list(connection, module, params['GroupName']):
                connection.detach_group_policy(GroupName=params['GroupName'], PolicyArn=policy['PolicyArn'])
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        except ParamValidationError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc())

        # Remove any users in the group otherwise deletion fails
        current_group_members_list = []
        try:
            current_group_members = get_group(connection, module, params['GroupName'])['Users']
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        for member in current_group_members:
            current_group_members_list.append(member['UserName'])
        for user in current_group_members_list:
            try:
                connection.remove_user_from_group(GroupName=params['GroupName'], UserName=user)
            except ClientError as e:
                module.fail_json(msg=e.message, exception=traceback.format_exc(),
                                 **camel_dict_to_snake_dict(e.response))
            except ParamValidationError as e:
                module.fail_json(msg=e.message, exception=traceback.format_exc())

        try:
            connection.delete_group(**params)
        except ClientError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        except ParamValidationError as e:
            module.fail_json(msg=e.message, exception=traceback.format_exc())

    else:
        module.exit_json(changed=False)

    module.exit_json(changed=True)
Ejemplo n.º 13
0
def ensure_present(module, connection):
    groupname = module.params['name']
    tags = module.params.get('tags')
    changed = False
    errors = []
    try:
        response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname)
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'DBParameterGroupNotFound':
            response = None
        else:
            module.fail_json(msg="Couldn't access parameter group information: %s" % str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    if not response:
        params = dict(DBParameterGroupName=groupname,
                      DBParameterGroupFamily=module.params['engine'],
                      Description=module.params['description'])
        if tags:
            params['Tags'] = ansible_dict_to_boto3_tag_list(tags)
        try:
            response = connection.create_db_parameter_group(**params)
            changed = True
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't create parameter group: %s" % str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    else:
        group = response['DBParameterGroups'][0]
        if tags:
            changed = update_tags(module, connection, group, tags)

    if module.params.get('params'):
        params_changed, errors = update_parameters(module, connection)
        changed = changed or params_changed

    try:
        response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname)
        group = camel_dict_to_snake_dict(response['DBParameterGroups'][0])
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't obtain parameter group information: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    try:
        tags = connection.list_tags_for_resource(ResourceName=group['db_parameter_group_arn'])['TagList']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't obtain parameter group tags: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    group['tags'] = boto3_tag_list_to_ansible_dict(tags)

    module.exit_json(changed=changed, errors=errors, **group)
Ejemplo n.º 14
0
def main():
    argument_spec = ec2_utils.ec2_argument_spec()
    argument_spec.update(
        dict(
            state=dict(type='str', default='present', choices=['present', 'absent']),
            filters=dict(type='dict', default={}),
            vpn_gateway_id=dict(type='str'),
            tags=dict(default={}, type='dict'),
            connection_type=dict(default='ipsec.1', type='str'),
            static_only=dict(default=False, type='bool'),
            customer_gateway_id=dict(type='str'),
            vpn_connection_id=dict(type='str'),
            purge_tags=dict(type='bool', default=False),
            routes=dict(type='list', default=[]),
            purge_routes=dict(type='bool', default=False),
        )
    )
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

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

    # Retrieve any AWS settings from the environment.
    region, ec2_url, aws_connect_kwargs = ec2_utils.get_aws_connection_info(module, boto3=True)

    if not region:
        module.fail_json(msg="Either region or AWS_REGION or EC2_REGION environment variable or boto config aws_region or ec2_region must be set.")

    connection = ec2_utils.boto3_conn(module, conn_type='client',
                                      resource='ec2', region=region,
                                      endpoint=ec2_url, **aws_connect_kwargs)

    state = module.params.get('state')
    parameters = dict(module.params)

    try:
        if state == 'present':
            changed, response = ensure_present(connection, parameters, module.check_mode)
        elif state == 'absent':
            changed, response = ensure_absent(connection, parameters, module.check_mode)
    except VPNConnectionException as e:
        if e.response and e.error_traceback:
            module.fail_json(msg=e.msg, exception=e.error_traceback, **ec2_utils.camel_dict_to_snake_dict(e.response))
        elif e.error_traceback:
            module.fail_json(msg=e.msg, exception=e.error_traceback)
        else:
            module.fail_json(msg=e.msg)

    facts_result = dict(changed=changed, **ec2_utils.camel_dict_to_snake_dict(response))

    module.exit_json(**facts_result)
Ejemplo n.º 15
0
def list_mfa_devices(connection, module):
    user_name = module.params.get('user_name')
    changed = False

    args = {}
    if user_name is not None:
        args['UserName'] = user_name
    try:
        response = connection.list_mfa_devices(**args)
    except ClientError as e:
        module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response))

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
Ejemplo n.º 16
0
def get_bucket_list(module, connection):
    """
    Return result of list_buckets json encoded
    :param module:
    :param connection:
    :return:
    """
    try:
        buckets = camel_dict_to_snake_dict(connection.list_buckets())['buckets']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    return buckets
Ejemplo n.º 17
0
def ensure_ipv6_cidr_block(conn, module, subnet, ipv6_cidr, check_mode, start_time):
    wait = module.params['wait']
    changed = False

    if subnet['ipv6_association_id'] and not ipv6_cidr:
        if not check_mode:
            disassociate_ipv6_cidr(conn, module, subnet, start_time)
        changed = True

    if ipv6_cidr:
        filters = ansible_dict_to_boto3_filter_list({'ipv6-cidr-block-association.ipv6-cidr-block': ipv6_cidr,
                                                     'vpc-id': subnet['vpc_id']})

        try:
            check_subnets = get_subnet_info(describe_subnets_with_backoff(conn, Filters=filters))
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't get subnet info")

        if check_subnets and check_subnets[0]['ipv6_cidr_block']:
            module.fail_json(msg="The IPv6 CIDR '{0}' conflicts with another subnet".format(ipv6_cidr))

        if subnet['ipv6_association_id']:
            if not check_mode:
                disassociate_ipv6_cidr(conn, module, subnet, start_time)
            changed = True

        try:
            if not check_mode:
                associate_resp = conn.associate_subnet_cidr_block(SubnetId=subnet['id'], Ipv6CidrBlock=ipv6_cidr)
            changed = True
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't associate ipv6 cidr {0} to {1}".format(ipv6_cidr, subnet['id']))
        else:
            if not check_mode and wait:
                filters = ansible_dict_to_boto3_filter_list(
                    {'ipv6-cidr-block-association.state': ['associated'],
                     'vpc-id': subnet['vpc_id']}
                )
                handle_waiter(conn, module, 'subnet_exists',
                              {'SubnetIds': [subnet['id']], 'Filters': filters}, start_time)

        if associate_resp.get('Ipv6CidrBlockAssociation', {}).get('AssociationId'):
            subnet['ipv6_association_id'] = associate_resp['Ipv6CidrBlockAssociation']['AssociationId']
            subnet['ipv6_cidr_block'] = associate_resp['Ipv6CidrBlockAssociation']['Ipv6CidrBlock']
            if subnet['ipv6_cidr_block_association_set']:
                subnet['ipv6_cidr_block_association_set'][0] = camel_dict_to_snake_dict(associate_resp['Ipv6CidrBlockAssociation'])
            else:
                subnet['ipv6_cidr_block_association_set'].append(camel_dict_to_snake_dict(associate_resp['Ipv6CidrBlockAssociation']))

    return changed
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        state=dict(required=True, choices=['present', 'absent']),
        name=dict(),
        location=dict(),
        bandwidth=dict(choices=['1Gbps', '10Gbps']),
        link_aggregation_group=dict(),
        connection_id=dict(),
        forced_update=dict(type='bool', default=False)
    ))

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        required_one_of=[('connection_id', 'name')],
        required_if=[('state', 'present', ('location', 'bandwidth'))]
    )

    connection = module.client('directconnect')

    state = module.params.get('state')
    try:
        connection_id = connection_exists(
            connection,
            connection_id=module.params.get('connection_id'),
            connection_name=module.params.get('name')
        )
        if not connection_id and module.params.get('connection_id'):
            module.fail_json(msg="The Direct Connect connection {0} does not exist.".format(module.params.get('connection_id')))

        if state == 'present':
            changed, connection_id = ensure_present(connection,
                                                    connection_id=connection_id,
                                                    connection_name=module.params.get('name'),
                                                    location=module.params.get('location'),
                                                    bandwidth=module.params.get('bandwidth'),
                                                    lag_id=module.params.get('link_aggregation_group'),
                                                    forced_update=module.params.get('forced_update'))
            response = connection_status(connection, connection_id)
        elif state == 'absent':
            changed = ensure_absent(connection, connection_id)
            response = {}
    except DirectConnectError as e:
        if e.last_traceback:
            module.fail_json(msg=e.msg, exception=e.last_traceback, **camel_dict_to_snake_dict(e.exception.response))
        else:
            module.fail_json(msg=e.msg)

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
Ejemplo n.º 19
0
    def fail_json_aws(self, exception, msg=None):
        """call fail_json with processed exception

        function for converting exceptions thrown by AWS SDK modules,
        botocore, boto3 and boto, into nice error messages.
        """
        last_traceback = traceback.format_exc()

        # to_native is trusted to handle exceptions that str() could
        # convert to text.
        try:
            except_msg = to_native(exception.message)
        except AttributeError:
            except_msg = to_native(exception)

        if msg is not None:
            message = '{0}: {1}'.format(msg, except_msg)
        else:
            message = except_msg

        try:
            response = exception.response
        except AttributeError:
            response = None

        if response is None:
            self._module.fail_json(msg=message, exception=last_traceback)
        else:
            self._module.fail_json(msg=message, exception=last_traceback,
                                   **camel_dict_to_snake_dict(response))
Ejemplo n.º 20
0
def policy_details(client, module):
    """
    Returns policy attached to a lambda function.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    if module.params.get('max_items') or module.params.get('next_marker'):
        module.fail_json(msg='Cannot specify max_items nor next_marker for query=policy.')

    lambda_facts = dict()

    function_name = module.params.get('function_name')
    if function_name:
        try:
            # get_policy returns a JSON string so must convert to dict before reassigning to its key
            lambda_facts.update(policy=json.loads(client.get_policy(FunctionName=function_name)['Policy']))
        except ClientError as e:
            if e.response['Error']['Code'] == 'ResourceNotFoundException':
                lambda_facts.update(policy={})
            else:
                module.fail_json_aws(e, msg="Trying to get {0} policy".format(function_name))
    else:
        module.fail_json(msg='Parameter function_name required for query=policy.')

    return {function_name: camel_dict_to_snake_dict(lambda_facts)}
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(state=dict(default='present', choices=['present', 'absent']),
                              name=dict(),
                              amazon_asn=dict(),
                              virtual_gateway_id=dict(),
                              direct_connect_gateway_id=dict(),
                              wait_timeout=dict(type='int', default=320)))
    required_if = [('state', 'present', ['name', 'amazon_asn']),
                   ('state', 'absent', ['direct_connect_gateway_id'])]
    module = AnsibleModule(argument_spec=argument_spec,
                           required_if=required_if)

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

    state = module.params.get('state')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    client = boto3_conn(module, conn_type='client', resource='directconnect', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    if state == 'present':
        (changed, results) = ensure_present(client, module)
    elif state == 'absent':
        changed = ensure_absent(client, module)
        results = {}

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(results))
Ejemplo n.º 22
0
def version_details(client, module):
    """
    Returns all lambda function versions.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    lambda_facts = dict()

    function_name = module.params.get('function_name')
    if function_name:
        params = dict()
        if module.params.get('max_items'):
            params['MaxItems'] = module.params.get('max_items')

        if module.params.get('next_marker'):
            params['Marker'] = module.params.get('next_marker')

        try:
            lambda_facts.update(versions=client.list_versions_by_function(FunctionName=function_name, **params)['Versions'])
        except ClientError as e:
            if e.response['Error']['Code'] == 'ResourceNotFoundException':
                lambda_facts.update(versions=[])
            else:
                module.fail_json_aws(e, msg="Trying to get {0} versions".format(function_name))
    else:
        module.fail_json(msg='Parameter function_name required for query=versions.')

    return {function_name: camel_dict_to_snake_dict(lambda_facts)}
Ejemplo n.º 23
0
def main():
    argument_spec = dict(
        state=dict(type='str', default='present', choices=['present', 'absent']),
        filters=dict(type='dict', default={}),
        vpn_gateway_id=dict(type='str'),
        tags=dict(default={}, type='dict'),
        connection_type=dict(default='ipsec.1', type='str'),
        tunnel_options=dict(type='list', default=[]),
        static_only=dict(default=False, type='bool'),
        customer_gateway_id=dict(type='str'),
        vpn_connection_id=dict(type='str'),
        purge_tags=dict(type='bool', default=False),
        routes=dict(type='list', default=[]),
        purge_routes=dict(type='bool', default=False),
    )
    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)
    connection = module.client('ec2')

    state = module.params.get('state')
    parameters = dict(module.params)

    try:
        if state == 'present':
            changed, response = ensure_present(connection, parameters, module.check_mode)
        elif state == 'absent':
            changed, response = ensure_absent(connection, parameters, module.check_mode)
    except VPNConnectionException as e:
        if e.exception:
            module.fail_json_aws(e.exception, msg=e.msg)
        else:
            module.fail_json(msg=e.msg)

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
Ejemplo n.º 24
0
def alias_details(client, module):
    """
    Returns list of aliases for a specified function.

    :param client: AWS API client reference (boto3)
    :param module: Ansible module reference
    :return dict:
    """

    lambda_facts = dict()

    function_name = module.params.get('function_name')
    if function_name:
        params = dict()
        if module.params.get('max_items'):
            params['MaxItems'] = module.params.get('max_items')

        if module.params.get('next_marker'):
            params['Marker'] = module.params.get('next_marker')
        try:
            lambda_facts.update(aliases=client.list_aliases(FunctionName=function_name, **params)['Aliases'])
        except ClientError as e:
            if e.response['Error']['Code'] == 'ResourceNotFoundException':
                lambda_facts.update(aliases=[])
            else:
                module.fail_json_aws(e, msg="Trying to get aliases")
    else:
        module.fail_json(msg='Parameter function_name required for query=aliases.')

    return {function_name: camel_dict_to_snake_dict(lambda_facts)}
Ejemplo n.º 25
0
def list_web_acls(client, module):
    try:
        return list_web_acls_with_backoff(client)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't obtain web acls",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 26
0
def describe_iam_roles(module, client):
    name = module.params['name']
    path_prefix = module.params['path_prefix']
    if name:
        try:
            roles = [client.get_role(RoleName=name)['Role']]
        except botocore.exceptions.ClientError as e:
            if e.response['Error']['Code'] == 'NoSuchEntity':
                return []
            else:
                module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name)
        except botocore.exceptions.BotoCoreError as e:
            module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name)
    else:
        params = dict()
        if path_prefix:
            if not path_prefix.startswith('/'):
                path_prefix = '/' + path_prefix
            if not path_prefix.endswith('/'):
                path_prefix = path_prefix + '/'
            params['PathPrefix'] = path_prefix
        try:
            roles = list_iam_roles_with_backoff(client, **params)['Roles']
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't list IAM roles")
    return [camel_dict_to_snake_dict(describe_iam_role(module, client, role)) for role in roles]
Ejemplo n.º 27
0
def fail_json_aws(module, exception, msg=None):
    """call fail_json with processed exception
    function for converting exceptions thrown by AWS SDK modules,
    botocore, boto3 and boto, into nice error messages.
    """
    last_traceback = traceback.format_exc()

    try:
        except_msg = exception.message
    except AttributeError:
        except_msg = str(exception)

    if msg is not None:
        message = '{}: {}'.format(msg, except_msg)
    else:
        message = except_msg

    try:
        response = exception.response
    except AttributeError:
        response = None

    if response is None:
        module.fail_json(msg=message, traceback=last_traceback)
    else:
        module.fail_json(msg=message, traceback=last_traceback,
                         **camel_dict_to_snake_dict(response))
Ejemplo n.º 28
0
    def create(self):
        params = dict()

        check_mode = self.params['check_mode']
        description = self.params['description']
        name = self.params['name']
        untagged_interfaces = self.params['untagged_interfaces']
        tagged_interfaces = self.params['tagged_interfaces']
        partition = self.params['partition']
        tag = self.params['tag']

        if tag is not None:
            params['tag'] = tag

        if untagged_interfaces is not None or tagged_interfaces is not None:
            tmp = []
            ifcs = self.api.tm.net.interfaces.get_collection()
            ifcs = [str(x.name) for x in ifcs]

            if len(ifcs) is 0:
                raise F5ModuleError(
                    'No interfaces were found'
                )

            pinterfaces = []
            if untagged_interfaces:
                interfaces = untagged_interfaces
            elif tagged_interfaces:
                interfaces = tagged_interfaces

            for ifc in interfaces:
                ifc = str(ifc)
                if ifc in ifcs:
                    pinterfaces.append(ifc)

            if tagged_interfaces:
                tmp = [dict(name=x, tagged=True) for x in pinterfaces]
            elif untagged_interfaces:
                tmp = [dict(name=x, untagged=True) for x in pinterfaces]

            if tmp:
                params['interfaces'] = tmp

        if description is not None:
            params['description'] = self.params['description']

        params['name'] = name
        params['partition'] = partition

        self.cparams = camel_dict_to_snake_dict(params)
        if check_mode:
            return True

        d = self.api.tm.net.vlans.vlan
        d.create(**params)

        if self.exists():
            return True
        else:
            raise F5ModuleError("Failed to create the VLAN")
Ejemplo n.º 29
0
 def format_facts(self, server, collection_type=None):
     result = dict()
     server_dict = server.to_dict()
     result.update(self.format_string_facts(server_dict))
     result.update(self.format_address_facts(server))
     result.update(self.format_virtual_server_facts(server))
     return camel_dict_to_snake_dict(result)
Ejemplo n.º 30
0
def create_or_update_bucket_cors(connection, module):

    name = module.params.get("name")
    rules = module.params.get("rules", [])
    changed = False

    try:
        current_camel_rules = connection.get_bucket_cors(Bucket=name)['CORSRules']
    except ClientError:
        current_camel_rules = []

    new_camel_rules = snake_dict_to_camel_dict(rules, capitalize_first=True)
    # compare_policies() takes two dicts and makes them hashable for comparison
    if compare_policies(new_camel_rules, current_camel_rules):
        changed = True

    if changed:
        try:
            cors = connection.put_bucket_cors(Bucket=name, CORSConfiguration={'CORSRules': new_camel_rules})
        except ClientError as e:
            module.fail_json(
                msg="Unable to update CORS for bucket {0}: {1}".format(name, to_native(e)),
                exception=traceback.format_exc(),
                **camel_dict_to_snake_dict(e.response)
            )
        except BotoCoreError as e:
            module.fail_json(
                msg=to_native(e),
                exception=traceback.format_exc()
            )

    module.exit_json(changed=changed, name=name, rules=rules)
Ejemplo n.º 31
0
def create_or_update_target_group(connection, module):

    changed = False
    new_target_group = False
    params = dict()
    params['Name'] = module.params.get("name")
    if module.params.get("target_type") != "lambda":
        params['Protocol'] = module.params.get("protocol").upper()
        params['Port'] = module.params.get("port")
        params['VpcId'] = module.params.get("vpc_id")
    tags = module.params.get("tags")
    purge_tags = module.params.get("purge_tags")
    deregistration_delay_timeout = module.params.get(
        "deregistration_delay_timeout")
    stickiness_enabled = module.params.get("stickiness_enabled")
    stickiness_lb_cookie_duration = module.params.get(
        "stickiness_lb_cookie_duration")
    stickiness_type = module.params.get("stickiness_type")

    health_option_keys = [
        "health_check_path", "health_check_protocol", "health_check_interval",
        "health_check_timeout", "healthy_threshold_count",
        "unhealthy_threshold_count", "successful_response_codes"
    ]
    health_options = any([
        module.params[health_option_key] is not None
        for health_option_key in health_option_keys
    ])

    # Set health check if anything set
    if health_options:

        if module.params.get("health_check_protocol") is not None:
            params['HealthCheckProtocol'] = module.params.get(
                "health_check_protocol").upper()

        if module.params.get("health_check_port") is not None:
            params['HealthCheckPort'] = module.params.get("health_check_port")

        if module.params.get("health_check_interval") is not None:
            params['HealthCheckIntervalSeconds'] = module.params.get(
                "health_check_interval")

        if module.params.get("health_check_timeout") is not None:
            params['HealthCheckTimeoutSeconds'] = module.params.get(
                "health_check_timeout")

        if module.params.get("healthy_threshold_count") is not None:
            params['HealthyThresholdCount'] = module.params.get(
                "healthy_threshold_count")

        if module.params.get("unhealthy_threshold_count") is not None:
            params['UnhealthyThresholdCount'] = module.params.get(
                "unhealthy_threshold_count")

        # Only need to check response code and path for http(s) health checks
        protocol = module.params.get("health_check_protocol")
        if protocol is not None and protocol.upper() in ['HTTP', 'HTTPS']:

            if module.params.get("health_check_path") is not None:
                params['HealthCheckPath'] = module.params.get(
                    "health_check_path")

            if module.params.get("successful_response_codes") is not None:
                params['Matcher'] = {}
                params['Matcher']['HttpCode'] = module.params.get(
                    "successful_response_codes")

    # Get target type
    if module.params.get("target_type") is not None:
        params['TargetType'] = module.params.get("target_type")
        if params['TargetType'] == 'ip':
            fail_if_ip_target_type_not_supported(module)

    # Get target group
    tg = get_target_group(connection, module)

    if tg:
        diffs = [
            param for param in ('Port', 'Protocol', 'VpcId')
            if tg.get(param) != params.get(param)
        ]
        if diffs:
            module.fail_json(
                msg="Cannot modify %s parameter(s) for a target group" %
                ", ".join(diffs))
        # Target group exists so check health check parameters match what has been passed
        health_check_params = dict()

        # Modify health check if anything set
        if health_options:

            # Health check protocol
            if 'HealthCheckProtocol' in params and tg[
                    'HealthCheckProtocol'] != params['HealthCheckProtocol']:
                health_check_params['HealthCheckProtocol'] = params[
                    'HealthCheckProtocol']

            # Health check port
            if 'HealthCheckPort' in params and tg['HealthCheckPort'] != params[
                    'HealthCheckPort']:
                health_check_params['HealthCheckPort'] = params[
                    'HealthCheckPort']

            # Health check interval
            if 'HealthCheckIntervalSeconds' in params and tg[
                    'HealthCheckIntervalSeconds'] != params[
                        'HealthCheckIntervalSeconds']:
                health_check_params['HealthCheckIntervalSeconds'] = params[
                    'HealthCheckIntervalSeconds']

            # Health check timeout
            if 'HealthCheckTimeoutSeconds' in params and tg[
                    'HealthCheckTimeoutSeconds'] != params[
                        'HealthCheckTimeoutSeconds']:
                health_check_params['HealthCheckTimeoutSeconds'] = params[
                    'HealthCheckTimeoutSeconds']

            # Healthy threshold
            if 'HealthyThresholdCount' in params and tg[
                    'HealthyThresholdCount'] != params['HealthyThresholdCount']:
                health_check_params['HealthyThresholdCount'] = params[
                    'HealthyThresholdCount']

            # Unhealthy threshold
            if 'UnhealthyThresholdCount' in params and tg[
                    'UnhealthyThresholdCount'] != params[
                        'UnhealthyThresholdCount']:
                health_check_params['UnhealthyThresholdCount'] = params[
                    'UnhealthyThresholdCount']

            # Only need to check response code and path for http(s) health checks
            if tg['HealthCheckProtocol'] in ['HTTP', 'HTTPS']:
                # Health check path
                if 'HealthCheckPath' in params and tg[
                        'HealthCheckPath'] != params['HealthCheckPath']:
                    health_check_params['HealthCheckPath'] = params[
                        'HealthCheckPath']

                # Matcher (successful response codes)
                # TODO: required and here?
                if 'Matcher' in params:
                    current_matcher_list = tg['Matcher']['HttpCode'].split(',')
                    requested_matcher_list = params['Matcher'][
                        'HttpCode'].split(',')
                    if set(current_matcher_list) != set(
                            requested_matcher_list):
                        health_check_params['Matcher'] = {}
                        health_check_params['Matcher']['HttpCode'] = ','.join(
                            requested_matcher_list)

            try:
                if health_check_params:
                    connection.modify_target_group(
                        TargetGroupArn=tg['TargetGroupArn'],
                        **health_check_params)
                    changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Couldn't update target group")

        # Do we need to modify targets?
        if module.params.get("modify_targets"):
            # get list of current target instances. I can't see anything like a describe targets in the doco so
            # describe_target_health seems to be the only way to get them
            try:
                current_targets = connection.describe_target_health(
                    TargetGroupArn=tg['TargetGroupArn'])
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Couldn't get target group health")

            if module.params.get("targets"):

                if module.params.get("target_type") != "lambda":
                    params['Targets'] = module.params.get("targets")

                    # Correct type of target ports
                    for target in params['Targets']:
                        target['Port'] = int(
                            target.get('Port', module.params.get('port')))

                    current_instance_ids = []

                    for instance in current_targets[
                            'TargetHealthDescriptions']:
                        current_instance_ids.append(instance['Target']['Id'])

                    new_instance_ids = []
                    for instance in params['Targets']:
                        new_instance_ids.append(instance['Id'])

                    add_instances = set(new_instance_ids) - set(
                        current_instance_ids)

                    if add_instances:
                        instances_to_add = []
                        for target in params['Targets']:
                            if target['Id'] in add_instances:
                                instances_to_add.append({
                                    'Id': target['Id'],
                                    'Port': target['Port']
                                })

                        changed = True
                        try:
                            connection.register_targets(
                                TargetGroupArn=tg['TargetGroupArn'],
                                Targets=instances_to_add)
                        except (botocore.exceptions.ClientError,
                                botocore.exceptions.BotoCoreError) as e:
                            module.fail_json_aws(
                                e, msg="Couldn't register targets")

                        if module.params.get("wait"):
                            status_achieved, registered_instances = wait_for_status(
                                connection, module, tg['TargetGroupArn'],
                                instances_to_add, 'healthy')
                            if not status_achieved:
                                module.fail_json(
                                    msg=
                                    'Error waiting for target registration to be healthy - please check the AWS console'
                                )

                    remove_instances = set(current_instance_ids) - set(
                        new_instance_ids)

                    if remove_instances:
                        instances_to_remove = []
                        for target in current_targets[
                                'TargetHealthDescriptions']:
                            if target['Target']['Id'] in remove_instances:
                                instances_to_remove.append({
                                    'Id':
                                    target['Target']['Id'],
                                    'Port':
                                    target['Target']['Port']
                                })

                        changed = True
                        try:
                            connection.deregister_targets(
                                TargetGroupArn=tg['TargetGroupArn'],
                                Targets=instances_to_remove)
                        except (botocore.exceptions.ClientError,
                                botocore.exceptions.BotoCoreError) as e:
                            module.fail_json_aws(e,
                                                 msg="Couldn't remove targets")

                        if module.params.get("wait"):
                            status_achieved, registered_instances = wait_for_status(
                                connection, module, tg['TargetGroupArn'],
                                instances_to_remove, 'unused')
                            if not status_achieved:
                                module.fail_json(
                                    msg=
                                    'Error waiting for target deregistration - please check the AWS console'
                                )

                # register lambda target
                else:
                    try:
                        changed = False
                        target = module.params.get("targets")[0]
                        if len(current_targets["TargetHealthDescriptions"]
                               ) == 0:
                            changed = True
                        else:
                            for item in current_targets[
                                    "TargetHealthDescriptions"]:
                                if target["Id"] != item["Target"]["Id"]:
                                    changed = True
                                    break  # only one target is possible with lambda

                        if changed:
                            if target.get("Id"):
                                response = connection.register_targets(
                                    TargetGroupArn=tg['TargetGroupArn'],
                                    Targets=[{
                                        "Id": target['Id']
                                    }])

                    except (botocore.exceptions.ClientError,
                            botocore.exceptions.BotoCoreError) as e:
                        module.fail_json_aws(e,
                                             msg="Couldn't register targets")
            else:
                if module.params.get("target_type") != "lambda":

                    current_instances = current_targets[
                        'TargetHealthDescriptions']

                    if current_instances:
                        instances_to_remove = []
                        for target in current_targets[
                                'TargetHealthDescriptions']:
                            instances_to_remove.append({
                                'Id':
                                target['Target']['Id'],
                                'Port':
                                target['Target']['Port']
                            })

                        changed = True
                        try:
                            connection.deregister_targets(
                                TargetGroupArn=tg['TargetGroupArn'],
                                Targets=instances_to_remove)
                        except (botocore.exceptions.ClientError,
                                botocore.exceptions.BotoCoreError) as e:
                            module.fail_json_aws(e,
                                                 msg="Couldn't remove targets")

                        if module.params.get("wait"):
                            status_achieved, registered_instances = wait_for_status(
                                connection, module, tg['TargetGroupArn'],
                                instances_to_remove, 'unused')
                            if not status_achieved:
                                module.fail_json(
                                    msg=
                                    'Error waiting for target deregistration - please check the AWS console'
                                )

                # remove lambda targets
                else:
                    changed = False
                    if current_targets["TargetHealthDescriptions"]:
                        changed = True
                        # only one target is possible with lambda
                        target_to_remove = current_targets[
                            "TargetHealthDescriptions"][0]["Target"]["Id"]
                    if changed:
                        connection.deregister_targets(
                            TargetGroupArn=tg['TargetGroupArn'],
                            Targets=[{
                                "Id": target_to_remove
                            }])
    else:
        try:
            connection.create_target_group(**params)
            changed = True
            new_target_group = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Couldn't create target group")

        tg = get_target_group(connection, module)

        if module.params.get("targets"):
            if module.params.get("target_type") != "lambda":
                params['Targets'] = module.params.get("targets")
                try:
                    connection.register_targets(
                        TargetGroupArn=tg['TargetGroupArn'],
                        Targets=params['Targets'])
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, msg="Couldn't register targets")

                if module.params.get("wait"):
                    status_achieved, registered_instances = wait_for_status(
                        connection, module, tg['TargetGroupArn'],
                        params['Targets'], 'healthy')
                    if not status_achieved:
                        module.fail_json(
                            msg=
                            'Error waiting for target registration to be healthy - please check the AWS console'
                        )

            else:
                try:
                    target = module.params.get("targets")[0]
                    response = connection.register_targets(
                        TargetGroupArn=tg['TargetGroupArn'],
                        Targets=[{
                            "Id": target["Id"]
                        }])
                    changed = True
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, msg="Couldn't register targets")

    # Now set target group attributes
    update_attributes = []

    # Get current attributes
    current_tg_attributes = get_tg_attributes(connection, module,
                                              tg['TargetGroupArn'])

    if deregistration_delay_timeout is not None:
        if str(deregistration_delay_timeout) != current_tg_attributes[
                'deregistration_delay_timeout_seconds']:
            update_attributes.append({
                'Key': 'deregistration_delay.timeout_seconds',
                'Value': str(deregistration_delay_timeout)
            })
    if stickiness_enabled is not None:
        if stickiness_enabled and current_tg_attributes[
                'stickiness_enabled'] != "true":
            update_attributes.append({
                'Key': 'stickiness.enabled',
                'Value': 'true'
            })
    if stickiness_lb_cookie_duration is not None:
        if str(stickiness_lb_cookie_duration) != current_tg_attributes[
                'stickiness_lb_cookie_duration_seconds']:
            update_attributes.append({
                'Key':
                'stickiness.lb_cookie.duration_seconds',
                'Value':
                str(stickiness_lb_cookie_duration)
            })
    if stickiness_type is not None and "stickiness_type" in current_tg_attributes:
        if stickiness_type != current_tg_attributes['stickiness_type']:
            update_attributes.append({
                'Key': 'stickiness.type',
                'Value': stickiness_type
            })

    if update_attributes:
        try:
            connection.modify_target_group_attributes(
                TargetGroupArn=tg['TargetGroupArn'],
                Attributes=update_attributes)
            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            # Something went wrong setting attributes. If this target group was created during this task, delete it to leave a consistent state
            if new_target_group:
                connection.delete_target_group(
                    TargetGroupArn=tg['TargetGroupArn'])
            module.fail_json_aws(e, msg="Couldn't delete target group")

    # Tags - only need to play with tags if tags parameter has been set to something
    if tags:
        # Get tags
        current_tags = get_target_group_tags(connection, module,
                                             tg['TargetGroupArn'])

        # Delete necessary tags
        tags_need_modify, tags_to_delete = compare_aws_tags(
            boto3_tag_list_to_ansible_dict(current_tags), tags, purge_tags)
        if tags_to_delete:
            try:
                connection.remove_tags(ResourceArns=[tg['TargetGroupArn']],
                                       TagKeys=tags_to_delete)
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(
                    e, msg="Couldn't delete tags from target group")
            changed = True

        # Add/update tags
        if tags_need_modify:
            try:
                connection.add_tags(
                    ResourceArns=[tg['TargetGroupArn']],
                    Tags=ansible_dict_to_boto3_tag_list(tags_need_modify))
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e,
                                     msg="Couldn't add tags to target group")
            changed = True

    # Get the target group again
    tg = get_target_group(connection, module)

    # Get the target group attributes again
    tg.update(get_tg_attributes(connection, module, tg['TargetGroupArn']))

    # Convert tg to snake_case
    snaked_tg = camel_dict_to_snake_dict(tg)

    snaked_tg['tags'] = boto3_tag_list_to_ansible_dict(
        get_target_group_tags(connection, module, tg['TargetGroupArn']))

    module.exit_json(changed=changed, **snaked_tg)
Ejemplo n.º 32
0
 def _snakify(self, dict):
     """Converts cammel case to snake case"""
     return camel_dict_to_snake_dict(dict)
Ejemplo n.º 33
0
def deregister_target(connection, module):
    """
    Deregisters a target to a target group

    :param module: ansible module object
    :param connection: boto3 connection
    :return:
    """

    deregister_unused = module.params.get("deregister_unused")
    target_group_arn = module.params.get("target_group_arn")
    target_id = module.params.get("target_id")
    target_port = module.params.get("target_port")
    target_status = module.params.get("target_status")
    target_status_timeout = module.params.get("target_status_timeout")
    changed = False

    if not target_group_arn:
        target_group_arn = convert_tg_name_to_arn(
            connection, module, module.params.get("target_group_name"))

    target = dict(Id=target_id)
    if target_port:
        target['Port'] = target_port

    target_description = describe_targets(connection, module, target_group_arn,
                                          [target])
    current_target_state = target_description['TargetHealth']['State']
    current_target_reason = target_description['TargetHealth'].get('Reason')

    needs_deregister = False

    if deregister_unused and current_target_state == 'unused':
        if current_target_reason != 'Target.NotRegistered':
            needs_deregister = True
    elif current_target_state not in ['unused', 'draining']:
        needs_deregister = True

    if needs_deregister:
        try:
            connection.deregister_targets(TargetGroupArn=target_group_arn,
                                          Targets=[target])
            changed = True
        except ClientError as e:
            module.fail_json(msg="Unable to deregister target {0}: {1}".format(
                target, to_native(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        except BotoCoreError as e:
            module.fail_json(msg="Unable to deregister target {0}: {1}".format(
                target, to_native(e)),
                             exception=traceback.format_exc())
    else:
        if current_target_reason != 'Target.NotRegistered' and current_target_state != 'draining':
            module.warn(
                warning=
                "Your specified target has an 'unused' state but is still registered to the target group. "
                +
                "To force deregistration use the 'deregister_unused' option.")

    if target_status:
        target_status_check(connection, module, target_group_arn, target,
                            target_status, target_status_timeout)

    # Get all targets for the target group
    target_descriptions = describe_targets(connection, module,
                                           target_group_arn, [])

    module.exit_json(changed=changed,
                     target_health_descriptions=camel_dict_to_snake_dict(
                         target_descriptions),
                     target_group_arn=target_group_arn)
Ejemplo n.º 34
0
def create_launch_config(connection, module):
    name = module.params.get('name')
    vpc_id = module.params.get('vpc_id')
    try:
        region, ec2_url, aws_connect_kwargs = get_aws_connection_info(
            module, boto3=True)
        ec2_connection = boto3_conn(module, 'client', 'ec2', region, ec2_url,
                                    **aws_connect_kwargs)
        security_groups = get_ec2_security_group_ids_from_names(
            module.params.get('security_groups'),
            ec2_connection,
            vpc_id=vpc_id,
            boto3=True)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed to get Security Group IDs",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    except ValueError as e:
        module.fail_json(msg="Failed to get Security Group IDs",
                         exception=traceback.format_exc())
    user_data = module.params.get('user_data')
    user_data_path = module.params.get('user_data_path')
    volumes = module.params['volumes']
    instance_monitoring = module.params.get('instance_monitoring')
    assign_public_ip = module.params.get('assign_public_ip')
    instance_profile_name = module.params.get('instance_profile_name')
    ebs_optimized = module.params.get('ebs_optimized')
    classic_link_vpc_id = module.params.get('classic_link_vpc_id')
    classic_link_vpc_security_groups = module.params.get(
        'classic_link_vpc_security_groups')

    block_device_mapping = []

    convert_list = [
        'image_id', 'instance_type', 'instance_type', 'instance_id',
        'placement_tenancy', 'key_name', 'kernel_id', 'ramdisk_id',
        'spot_price'
    ]

    launch_config = (snake_dict_to_camel_dict(
        dict((k.capitalize(), str(v)) for k, v in module.params.items()
             if v is not None and k in convert_list)))

    if user_data_path:
        try:
            with open(user_data_path, 'r') as user_data_file:
                user_data = user_data_file.read()
        except IOError as e:
            module.fail_json(msg="Failed to open file for reading",
                             exception=traceback.format_exc())

    if volumes:
        for volume in volumes:
            if 'device_name' not in volume:
                module.fail_json(msg='Device name must be set for volume')
            # Minimum volume size is 1GB. We'll use volume size explicitly set to 0 to be a signal not to create this volume
            if 'volume_size' not in volume or int(volume['volume_size']) > 0:
                block_device_mapping.append(
                    create_block_device_meta(module, volume))

    try:
        launch_configs = connection.describe_launch_configurations(
            LaunchConfigurationNames=[name]).get('LaunchConfigurations')
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed to describe launch configuration by name",
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))

    changed = False
    result = {}

    launch_config['LaunchConfigurationName'] = name

    if security_groups is not None:
        launch_config['SecurityGroups'] = security_groups

    if classic_link_vpc_id is not None:
        launch_config['ClassicLinkVPCId'] = classic_link_vpc_id

    if instance_monitoring is not None:
        launch_config['InstanceMonitoring'] = {'Enabled': instance_monitoring}

    if classic_link_vpc_security_groups is not None:
        launch_config[
            'ClassicLinkVPCSecurityGroups'] = classic_link_vpc_security_groups

    if block_device_mapping:
        launch_config['BlockDeviceMappings'] = block_device_mapping

    if instance_profile_name is not None:
        launch_config['IamInstanceProfile'] = instance_profile_name

    if assign_public_ip is not None:
        launch_config['AssociatePublicIpAddress'] = assign_public_ip

    if user_data is not None:
        launch_config['UserData'] = user_data

    if ebs_optimized is not None:
        launch_config['EbsOptimized'] = ebs_optimized

    if len(launch_configs) == 0:
        try:
            connection.create_launch_configuration(**launch_config)
            launch_configs = connection.describe_launch_configurations(
                LaunchConfigurationNames=[name]).get('LaunchConfigurations')
            changed = True
            if launch_configs:
                launch_config = launch_configs[0]
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Failed to create launch configuration",
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))

    result = (dict((k, v) for k, v in launch_config.items() if k not in [
        'Connection', 'CreatedTime', 'InstanceMonitoring',
        'BlockDeviceMappings'
    ]))

    result['CreatedTime'] = to_text(launch_config.get('CreatedTime'))

    try:
        result['InstanceMonitoring'] = module.boolean(
            launch_config.get('InstanceMonitoring').get('Enabled'))
    except AttributeError:
        result['InstanceMonitoring'] = False

    result['BlockDeviceMappings'] = []

    for block_device_mapping in launch_config.get('BlockDeviceMappings', []):
        result['BlockDeviceMappings'].append(
            dict(device_name=block_device_mapping.get('DeviceName'),
                 virtual_name=block_device_mapping.get('VirtualName')))
        if block_device_mapping.get('Ebs') is not None:
            result['BlockDeviceMappings'][-1]['ebs'] = dict(
                snapshot_id=block_device_mapping.get('Ebs').get('SnapshotId'),
                volume_size=block_device_mapping.get('Ebs').get('VolumeSize'))

    if user_data_path:
        result[
            'UserData'] = "hidden"  # Otherwise, we dump binary to the user's terminal

    return_object = {
        'Name': result.get('LaunchConfigurationName'),
        'CreatedTime': result.get('CreatedTime'),
        'ImageId': result.get('ImageId'),
        'Arn': result.get('LaunchConfigurationARN'),
        'SecurityGroups': result.get('SecurityGroups'),
        'InstanceType': result.get('InstanceType'),
        'Result': result
    }

    module.exit_json(changed=changed,
                     **camel_dict_to_snake_dict(return_object))
Ejemplo n.º 35
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            bgp_asn=dict(required=False, type='int'),
            ip_address=dict(required=True),
            name=dict(required=True),
            state=dict(default='present', choices=['present', 'absent']),
        ))

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True,
                           required_if=[('state', 'present', ['bgp_arn'])])

    if not HAS_BOTOCORE:
        module.fail_json(msg='botocore is required.')

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

    gw_mgr = Ec2CustomerGatewayManager(module)

    name = module.params.get('name')

    existing = gw_mgr.describe_gateways(module.params['ip_address'])
    # describe_gateways returns a key of CustomerGateways where as create_gateway returns a
    # key of CustomerGateway. For consistency, change it here
    existing['CustomerGateway'] = existing['CustomerGateways']

    results = dict(changed=False)
    if module.params['state'] == 'present':
        if existing['CustomerGateway']:
            results['gateway'] = existing
            if existing['CustomerGateway'][0]['Tags']:
                tag_array = existing['CustomerGateway'][0]['Tags']
                for key, value in enumerate(tag_array):
                    if value['Key'] == 'Name':
                        current_name = value['Value']
                        if current_name != name:
                            results['name'] = gw_mgr.tag_cgw_name(
                                results['gateway']['CustomerGateway'][0]
                                ['CustomerGatewayId'],
                                module.params['name'],
                            )
                            results['changed'] = True
        else:
            if not module.check_mode:
                results['gateway'] = gw_mgr.ensure_cgw_present(
                    module.params['bgp_asn'],
                    module.params['ip_address'],
                )
                results['name'] = gw_mgr.tag_cgw_name(
                    results['gateway']['CustomerGateway']['CustomerGatewayId'],
                    module.params['name'],
                )
            results['changed'] = True

    elif module.params['state'] == 'absent':
        if existing['CustomerGateway']:
            results['gateway'] = existing
            if not module.check_mode:
                results['gateway'] = gw_mgr.ensure_cgw_absent(
                    existing['CustomerGateway'][0]['CustomerGatewayId'])
            results['changed'] = True

    pretty_results = camel_dict_to_snake_dict(results)
    module.exit_json(**pretty_results)
Ejemplo n.º 36
0
def create_dirkey(module, s3, bucket, obj, encrypt):
    if module.check_mode:
        module.exit_json(msg="PUT operation skipped - running in check mode", changed=True)
    try:
        params = {'Bucket': bucket, 'Key': obj, 'Body': b''}
        if encrypt:
            params['ServerSideEncryption'] = 'AES256'

        s3.put_object(**params)
        for acl in module.params.get('permission'):
            s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
        module.exit_json(msg="Virtual directory %s created in bucket %s" % (obj, bucket), changed=True)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed while creating object %s." % obj, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 37
0
def upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers):
    if module.check_mode:
        module.exit_json(msg="PUT operation skipped - running in check mode", changed=True)
    try:
        extra = {}
        if encrypt:
            extra['ServerSideEncryption'] = 'AES256'
        if metadata:
            extra['Metadata'] = {}

            # determine object metadata and extra arguments
            for option in metadata:
                extra_args_option = option_in_extra_args(option)
                if extra_args_option is not None:
                    extra[extra_args_option] = metadata[option]
                else:
                    extra['Metadata'][option] = metadata[option]

        if 'ContentType' not in extra:
            content_type = mimetypes.guess_type(src)[0]
            if content_type is None:
                # s3 default content type
                content_type = 'binary/octet-stream'
            extra['ContentType'] = content_type

        s3.upload_file(Filename=src, Bucket=bucket, Key=obj, ExtraArgs=extra)
        for acl in module.params.get('permission'):
            s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
        url = s3.generate_presigned_url(ClientMethod='put_object',
                                        Params={'Bucket': bucket, 'Key': obj},
                                        ExpiresIn=expiry)
        module.exit_json(msg="PUT operation complete", url=url, changed=True)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Unable to complete PUT operation.", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 38
0
def download_s3file(module, s3, bucket, obj, dest, retries, version=None):
    if module.check_mode:
        module.exit_json(msg="GET operation skipped - running in check mode", changed=True)
    # retries is the number of loops; range/xrange needs to be one
    # more to get that count of loops.
    try:
        if version:
            key = s3.get_object(Bucket=bucket, Key=obj, VersionId=version)
        else:
            key = s3.get_object(Bucket=bucket, Key=obj)
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] != "404":
            module.fail_json(msg="Could not find the key %s." % obj, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))

    for x in range(0, retries + 1):
        try:
            s3.download_file(bucket, obj, dest)
            module.exit_json(msg="GET operation complete", changed=True)
        except botocore.exceptions.ClientError as e:
            # actually fail on last pass through the loop.
            if x >= retries:
                module.fail_json(msg="Failed while downloading %s." % obj, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
            # otherwise, try again, this may be a transient timeout.
        except SSLError as e:  # will ClientError catch SSLError?
            # actually fail on last pass through the loop.
            if x >= retries:
                module.fail_json(msg="s3 download failed: %s." % e, exception=traceback.format_exc())
Ejemplo n.º 39
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="*"),
            # future options: cache_control (string or map, perhaps), 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 = ansible.module_utils.ec2.get_aws_connection_info(
        module, boto3=True)
    if not region:
        module.fail_json(msg="Region must be specified")
    s3 = ansible.module_utils.ec2.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)

            # mark changed if we actually upload something.
            if result.get('uploads') and len(result.get('uploads')):
                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)
Ejemplo n.º 40
0
def get_download_url(module, s3, bucket, obj, expiry, changed=True):
    try:
        url = s3.generate_presigned_url(ClientMethod='get_object',
                                        Params={'Bucket': bucket, 'Key': obj},
                                        ExpiresIn=expiry)
        module.exit_json(msg="Download url:", url=url, expiry=expiry, changed=changed)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed while getting download url.", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 41
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            api_id=dict(type='str', required=False),
            state=dict(type='str', default='present', choices=['present', 'absent']),
            swagger_file=dict(type='path', default=None, aliases=['src', 'api_file']),
            swagger_dict=dict(type='json', default=None),
            swagger_text=dict(type='str', default=None),
            stage=dict(type='str', default=None),
            deploy_desc=dict(type='str', default="Automatic deployment by Ansible."),
        )
    )

    mutually_exclusive = [['swagger_file', 'swagger_dict', 'swagger_text']]  # noqa: F841

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,
                           mutually_exclusive=mutually_exclusive)

    api_id = module.params.get('api_id')
    state = module.params.get('state')   # noqa: F841
    swagger_file = module.params.get('swagger_file')
    swagger_dict = module.params.get('swagger_dict')
    swagger_text = module.params.get('swagger_text')
    stage = module.params.get('stage')
    deploy_desc = module.params.get('deploy_desc')

#    check_mode = module.check_mode
    changed = False

    if not HAS_BOTO3:
        module.fail_json(msg='Python module "boto3" is missing, please install boto3')

    if not HAS_BOTOCORE:
        module.fail_json(msg='Python module "botocore" is missing, please install it')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    try:
        client = boto3_conn(module, conn_type='client', resource='apigateway',
                            region=region, endpoint=ec2_url, **aws_connect_kwargs)
    except botocore.exceptions.NoRegionError:
        module.fail_json(msg="Region must be specified as a parameter, in "
                         "AWS_DEFAULT_REGION environment variable or in boto configuration file")
    except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as e:
        fail_json_aws(module, e, msg="connecting to AWS")

    changed = True   # for now it will stay that way until we can sometimes avoid change

    conf_res = None
    dep_res = None
    del_res = None

    if state == "present":
        if api_id is None:
            api_id = create_empty_api(module, client)
        api_data = get_api_definitions(module, swagger_file=swagger_file,
                                       swagger_dict=swagger_dict, swagger_text=swagger_text)
        conf_res, dep_res = ensure_api_in_correct_state(module, client, api_id=api_id,
                                                        api_data=api_data, stage=stage,
                                                        deploy_desc=deploy_desc)
    if state == "absent":
        del_res = delete_rest_api(module, client, api_id)

    exit_args = {"changed": changed, "api_id": api_id}

    if conf_res is not None:
        exit_args['configure_response'] = camel_dict_to_snake_dict(conf_res)
    if dep_res is not None:
        exit_args['deploy_response'] = camel_dict_to_snake_dict(dep_res)
    if del_res is not None:
        exit_args['delete_response'] = camel_dict_to_snake_dict(del_res)

    module.exit_json(**exit_args)
Ejemplo n.º 42
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(log_group_name=dict(required=True, type='str'),
             state=dict(choices=['present', 'absent'], default='present'),
             kms_key_id=dict(required=False, type='str'),
             tags=dict(required=False, type='dict'),
             retention=dict(required=False, type='int'),
             overwrite=dict(required=False, type='bool', default=False)))

    module = AnsibleModule(argument_spec=argument_spec)

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

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module,
                                                                  boto3=True)
    logs = boto3_conn(module,
                      conn_type='client',
                      resource='logs',
                      region=region,
                      endpoint=ec2_url,
                      **aws_connect_kwargs)

    state = module.params.get('state')
    changed = False

    # Determine if the log group exists
    desc_log_group = describe_log_group(
        client=logs,
        log_group_name=module.params['log_group_name'],
        module=module)
    found_log_group = {}
    for i in desc_log_group.get('logGroups', []):
        if module.params['log_group_name'] == i['logGroupName']:
            found_log_group = i
            break

    if state == 'present':
        if found_log_group and module.params['overwrite'] is True:
            changed = True
            delete_log_group(client=logs,
                             log_group_name=module.params['log_group_name'],
                             module=module)
            found_log_group = create_log_group(
                client=logs,
                log_group_name=module.params['log_group_name'],
                kms_key_id=module.params['kms_key_id'],
                tags=module.params['tags'],
                retention=module.params['retention'],
                module=module)
        elif not found_log_group:
            changed = True
            found_log_group = create_log_group(
                client=logs,
                log_group_name=module.params['log_group_name'],
                kms_key_id=module.params['kms_key_id'],
                tags=module.params['tags'],
                retention=module.params['retention'],
                module=module)
        elif found_log_group:
            if module.params['retention'] != found_log_group['retentionInDays']:
                changed = True
                input_retention_policy(
                    client=logs,
                    log_group_name=module.params['log_group_name'],
                    retention=module.params['retention'],
                    module=module)
                found_log_group['retentionInDays'] = module.params['retention']

        module.exit_json(changed=changed,
                         **camel_dict_to_snake_dict(found_log_group))

    elif state == 'absent':
        if found_log_group:
            changed = True
            delete_log_group(client=logs,
                             log_group_name=module.params['log_group_name'],
                             module=module)

    module.exit_json(changed=changed)
Ejemplo n.º 43
0
def main():
    argument_spec = dict(
        state=dict(default='present',
                   choices=['present', 'absent', 'enabled', 'disabled']),
        name=dict(default='default'),
        enable_logging=dict(default=True, type='bool'),
        s3_bucket_name=dict(),
        s3_key_prefix=dict(),
        sns_topic_name=dict(),
        is_multi_region_trail=dict(default=False, type='bool'),
        enable_log_file_validation=dict(
            type='bool', aliases=['log_file_validation_enabled']),
        include_global_events=dict(default=True,
                                   type='bool',
                                   aliases=['include_global_service_events']),
        cloudwatch_logs_role_arn=dict(),
        cloudwatch_logs_log_group_arn=dict(),
        kms_key_id=dict(),
        tags=dict(default={}, type='dict'),
    )

    required_if = [('state', 'present', ['s3_bucket_name']),
                   ('state', 'enabled', ['s3_bucket_name'])]
    required_together = [('cloudwatch_logs_role_arn',
                          'cloudwatch_logs_log_group_arn')]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              required_together=required_together,
                              required_if=required_if)

    # collect parameters
    if module.params['state'] in ('present', 'enabled'):
        state = 'present'
    elif module.params['state'] in ('absent', 'disabled'):
        state = 'absent'
    tags = module.params['tags']
    enable_logging = module.params['enable_logging']
    ct_params = dict(
        Name=module.params['name'],
        S3BucketName=module.params['s3_bucket_name'],
        IncludeGlobalServiceEvents=module.params['include_global_events'],
        IsMultiRegionTrail=module.params['is_multi_region_trail'],
    )

    if module.params['s3_key_prefix']:
        ct_params['S3KeyPrefix'] = module.params['s3_key_prefix'].rstrip('/')

    if module.params['sns_topic_name']:
        ct_params['SnsTopicName'] = module.params['sns_topic_name']

    if module.params['cloudwatch_logs_role_arn']:
        ct_params['CloudWatchLogsRoleArn'] = module.params[
            'cloudwatch_logs_role_arn']

    if module.params['cloudwatch_logs_log_group_arn']:
        ct_params['CloudWatchLogsLogGroupArn'] = module.params[
            'cloudwatch_logs_log_group_arn']

    if module.params['enable_log_file_validation'] is not None:
        ct_params['EnableLogFileValidation'] = module.params[
            'enable_log_file_validation']

    if module.params['kms_key_id']:
        ct_params['KmsKeyId'] = module.params['kms_key_id']

    client = module.client('cloudtrail')
    region = module.region

    results = dict(changed=False, exists=False)

    # Get existing trail facts
    trail = get_trail_facts(module, client, ct_params['Name'])

    # If the trail exists set the result exists variable
    if trail is not None:
        results['exists'] = True

    if state == 'absent' and results['exists']:
        # If Trail exists go ahead and delete
        results['changed'] = True
        results['exists'] = False
        results['trail'] = dict()
        if not module.check_mode:
            delete_trail(module, client, trail['TrailARN'])

    elif state == 'present' and results['exists']:
        # If Trail exists see if we need to update it
        do_update = False
        for key in ct_params:
            tkey = str(key)
            # boto3 has inconsistent parameter naming so we handle it here
            if key == 'EnableLogFileValidation':
                tkey = 'LogFileValidationEnabled'
            # We need to make an empty string equal None
            if ct_params.get(key) == '':
                val = None
            else:
                val = ct_params.get(key)
            if val != trail.get(tkey):
                do_update = True
                results['changed'] = True
                # If we are in check mode copy the changed values to the trail facts in result output to show what would change.
                if module.check_mode:
                    trail.update({tkey: ct_params.get(key)})

        if not module.check_mode and do_update:
            update_trail(module, client, ct_params)
            trail = get_trail_facts(module, client, ct_params['Name'])

        # Check if we need to start/stop logging
        if enable_logging and not trail['IsLogging']:
            results['changed'] = True
            trail['IsLogging'] = True
            if not module.check_mode:
                set_logging(module,
                            client,
                            name=ct_params['Name'],
                            action='start')
        if not enable_logging and trail['IsLogging']:
            results['changed'] = True
            trail['IsLogging'] = False
            if not module.check_mode:
                set_logging(module,
                            client,
                            name=ct_params['Name'],
                            action='stop')

        # Check if we need to update tags on resource
        tag_dry_run = False
        if module.check_mode:
            tag_dry_run = True
        tags_changed = tag_trail(module,
                                 client,
                                 tags=tags,
                                 trail_arn=trail['TrailARN'],
                                 curr_tags=trail['tags'],
                                 dry_run=tag_dry_run)
        if tags_changed:
            results['changed'] = True
            trail['tags'] = tags
        # Populate trail facts in output
        results['trail'] = camel_dict_to_snake_dict(trail)

    elif state == 'present' and not results['exists']:
        # Trail doesn't exist just go create it
        results['changed'] = True
        if not module.check_mode:
            # If we aren't in check_mode then actually create it
            created_trail = create_trail(module, client, ct_params)
            # Apply tags
            tag_trail(module,
                      client,
                      tags=tags,
                      trail_arn=created_trail['TrailARN'])
            # Get the trail status
            try:
                status_resp = client.get_trail_status(
                    Name=created_trail['Name'])
            except (BotoCoreError, ClientError) as err:
                module.fail_json_aws(err, msg="Failed to fetch Trail statuc")
            # Set the logging state for the trail to desired value
            if enable_logging and not status_resp['IsLogging']:
                set_logging(module,
                            client,
                            name=ct_params['Name'],
                            action='start')
            if not enable_logging and status_resp['IsLogging']:
                set_logging(module,
                            client,
                            name=ct_params['Name'],
                            action='stop')
            # Get facts for newly created Trail
            trail = get_trail_facts(module, client, ct_params['Name'])

        # If we are in check mode create a fake return structure for the newly minted trail
        if module.check_mode:
            acct_id = '123456789012'
            try:
                sts_client = module.client('sts')
                acct_id = sts_client.get_caller_identity()['Account']
            except (BotoCoreError, ClientError):
                pass
            trail = dict()
            trail.update(ct_params)
            if 'EnableLogFileValidation' not in ct_params:
                ct_params['EnableLogFileValidation'] = False
            trail['EnableLogFileValidation'] = ct_params[
                'EnableLogFileValidation']
            trail.pop('EnableLogFileValidation')
            fake_arn = 'arn:aws:cloudtrail:' + region + ':' + acct_id + ':trail/' + ct_params[
                'Name']
            trail['HasCustomEventSelectors'] = False
            trail['HomeRegion'] = region
            trail['TrailARN'] = fake_arn
            trail['IsLogging'] = enable_logging
            trail['tags'] = tags
        # Populate trail facts in output
        results['trail'] = camel_dict_to_snake_dict(trail)

    module.exit_json(**results)
Ejemplo n.º 44
0
def delete_key(module, s3, bucket, obj):
    if module.check_mode:
        module.exit_json(msg="DELETE operation skipped - running in check mode", changed=True)
    try:
        s3.delete_object(Bucket=bucket, Key=obj)
        module.exit_json(msg="Object deleted from bucket %s." % (bucket), changed=True)
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed while trying to delete %s." % obj, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 45
0
    def update(self):
        changed = False
        params = dict()
        current = self.read()

        check_mode = self.params['check_mode']
        description = self.params['description']
        name = self.params['name']
        tag = self.params['tag']
        partition = self.params['partition']
        tagged_interfaces = self.params['tagged_interfaces']
        untagged_interfaces = self.params['untagged_interfaces']

        if untagged_interfaces is not None or tagged_interfaces is not None:
            ifcs = self.api.tm.net.interfaces.get_collection()
            ifcs = [str(x.name) for x in ifcs]

            if len(ifcs) is 0:
                raise F5ModuleError(
                    'No interfaces were found'
                )

            pinterfaces = []
            if untagged_interfaces:
                interfaces = untagged_interfaces
            elif tagged_interfaces:
                interfaces = tagged_interfaces

            for ifc in interfaces:
                ifc = str(ifc)
                if ifc in ifcs:
                    pinterfaces.append(ifc)
                else:
                    raise F5ModuleError(
                        'The specified interface "%s" was not found' % (ifc)
                    )

            if tagged_interfaces:
                tmp = [dict(name=x, tagged=True) for x in pinterfaces]
                if 'tagged_interfaces' in current:
                    if pinterfaces != current['tagged_interfaces']:
                        params['interfaces'] = tmp
                else:
                    params['interfaces'] = tmp
            elif untagged_interfaces:
                tmp = [dict(name=x, untagged=True) for x in pinterfaces]
                if 'untagged_interfaces' in current:
                    if pinterfaces != current['untagged_interfaces']:
                        params['interfaces'] = tmp
                else:
                    params['interfaces'] = tmp

        if description is not None:
            if 'description' in current:
                if description != current['description']:
                    params['description'] = description
            else:
                params['description'] = description

        if tag is not None:
            if 'tag' in current:
                if tag != current['tag']:
                    params['tag'] = tag
            else:
                params['tag'] = tag

        if params:
            changed = True
            params['name'] = name
            params['partition'] = partition
            if check_mode:
                return changed
            self.cparams = camel_dict_to_snake_dict(params)
        else:
            return changed

        r = self.api.tm.net.vlans.vlan.load(
            name=name,
            partition=partition
        )
        r.update(**params)
        r.refresh()

        return True
Ejemplo n.º 46
0
    def converge_file_system(self, name, tags, purge_tags, targets,
                             throughput_mode, provisioned_throughput_in_mibps):
        """
         Change attributes (mount targets and tags) of filesystem by name
        """
        result = False
        fs_id = self.get_file_system_id(name)

        if tags is not None:
            tags_need_modify, tags_to_delete = compare_aws_tags(
                boto3_tag_list_to_ansible_dict(
                    self.get_tags(FileSystemId=fs_id)), tags, purge_tags)

            if tags_to_delete:
                try:
                    self.connection.delete_tags(FileSystemId=fs_id,
                                                TagKeys=tags_to_delete)
                except ClientError as e:
                    self.module.fail_json(
                        msg="Unable to delete tags: {0}".format(to_native(e)),
                        exception=traceback.format_exc(),
                        **camel_dict_to_snake_dict(e.response))
                except BotoCoreError as e:
                    self.module.fail_json(
                        msg="Unable to delete tags: {0}".format(to_native(e)),
                        exception=traceback.format_exc())

                result = True

            if tags_need_modify:
                try:
                    self.connection.create_tags(
                        FileSystemId=fs_id,
                        Tags=ansible_dict_to_boto3_tag_list(tags_need_modify))
                except ClientError as e:
                    self.module.fail_json(
                        msg="Unable to create tags: {0}".format(to_native(e)),
                        exception=traceback.format_exc(),
                        **camel_dict_to_snake_dict(e.response))
                except BotoCoreError as e:
                    self.module.fail_json(
                        msg="Unable to create tags: {0}".format(to_native(e)),
                        exception=traceback.format_exc())

                result = True

        if targets is not None:
            incomplete_states = [self.STATE_CREATING, self.STATE_DELETING]
            wait_for(
                lambda: len(
                    self.get_mount_targets_in_state(fs_id, incomplete_states)),
                0)
            current_targets = _index_by_key(
                'SubnetId', self.get_mount_targets(FileSystemId=fs_id))
            targets = _index_by_key('SubnetId', targets)

            targets_to_create, intersection, targets_to_delete = dict_diff(
                current_targets, targets, True)

            # To modify mount target it should be deleted and created again
            changed = [
                sid for sid in intersection if not targets_equal(
                    ['SubnetId', 'IpAddress', 'NetworkInterfaceId'],
                    current_targets[sid], targets[sid])
            ]
            targets_to_delete = list(targets_to_delete) + changed
            targets_to_create = list(targets_to_create) + changed

            if targets_to_delete:
                for sid in targets_to_delete:
                    self.connection.delete_mount_target(
                        MountTargetId=current_targets[sid]['MountTargetId'])
                wait_for(
                    lambda: len(
                        self.get_mount_targets_in_state(
                            fs_id, incomplete_states)), 0)
                result = True

            if targets_to_create:
                for sid in targets_to_create:
                    self.connection.create_mount_target(FileSystemId=fs_id,
                                                        **targets[sid])
                wait_for(
                    lambda: len(
                        self.get_mount_targets_in_state(
                            fs_id, incomplete_states)), 0, self.wait_timeout)
                result = True

            # If no security groups were passed into the module, then do not change it.
            security_groups_to_update = [
                sid for sid in intersection
                if 'SecurityGroups' in targets[sid] and current_targets[sid]
                ['SecurityGroups'] != targets[sid]['SecurityGroups']
            ]

            if security_groups_to_update:
                for sid in security_groups_to_update:
                    self.connection.modify_mount_target_security_groups(
                        MountTargetId=current_targets[sid]['MountTargetId'],
                        SecurityGroups=targets[sid].get(
                            'SecurityGroups', None))
                result = True

        return result
Ejemplo n.º 47
0
def instance_to_facts(instance):
    assert 'DBInstanceIdentifier' in instance, "instance argument was not a valid instance"
    d = camel_dict_to_snake_dict(instance)
    return d
Ejemplo n.º 48
0
def main():
    """
     Module action handler
    """
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(encrypt=dict(required=False, type="bool", default=False),
             state=dict(required=False,
                        type='str',
                        choices=["present", "absent"],
                        default="present"),
             kms_key_id=dict(required=False, type='str', default=None),
             purge_tags=dict(default=True, type='bool'),
             id=dict(required=False, type='str', default=None),
             name=dict(required=False, type='str', default=None),
             tags=dict(required=False, type="dict", default={}),
             targets=dict(required=False, type="list", default=[]),
             performance_mode=dict(required=False,
                                   type='str',
                                   choices=["general_purpose", "max_io"],
                                   default="general_purpose"),
             throughput_mode=dict(required=False,
                                  type='str',
                                  choices=["bursting", "provisioned"],
                                  default=None),
             provisioned_throughput_in_mibps=dict(required=False,
                                                  type='float'),
             wait=dict(required=False, type="bool", default=False),
             wait_timeout=dict(required=False, type="int", default=0)))

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

    region, ec2_url, aws_connect_params = get_aws_connection_info(module,
                                                                  boto3=True)
    connection = EFSConnection(module, region, **aws_connect_params)

    name = module.params.get('name')
    fs_id = module.params.get('id')
    tags = module.params.get('tags')
    target_translations = {
        'ip_address': 'IpAddress',
        'security_groups': 'SecurityGroups',
        'subnet_id': 'SubnetId'
    }
    targets = [
        dict((target_translations[key], value) for (key, value) in x.items())
        for x in module.params.get('targets')
    ]
    performance_mode_translations = {
        'general_purpose': 'generalPurpose',
        'max_io': 'maxIO'
    }
    encrypt = module.params.get('encrypt')
    kms_key_id = module.params.get('kms_key_id')
    performance_mode = performance_mode_translations[module.params.get(
        'performance_mode')]
    purge_tags = module.params.get('purge_tags')
    throughput_mode = module.params.get('throughput_mode')
    provisioned_throughput_in_mibps = module.params.get(
        'provisioned_throughput_in_mibps')
    state = str(module.params.get('state')).lower()
    changed = False

    if state == 'present':
        if not name:
            module.fail_json(msg='Name parameter is required for create')

        changed = connection.create_file_system(
            name, performance_mode, encrypt, kms_key_id, throughput_mode,
            provisioned_throughput_in_mibps)
        if connection.supports_provisioned_mode():
            changed = connection.update_file_system(
                name, throughput_mode,
                provisioned_throughput_in_mibps) or changed
        changed = connection.converge_file_system(
            name=name,
            tags=tags,
            purge_tags=purge_tags,
            targets=targets,
            throughput_mode=throughput_mode,
            provisioned_throughput_in_mibps=provisioned_throughput_in_mibps
        ) or changed
        result = first_or_default(
            connection.get_file_systems(CreationToken=name))

    elif state == 'absent':
        if not name and not fs_id:
            module.fail_json(
                msg='Either name or id parameter is required for delete')

        changed = connection.delete_file_system(name, fs_id)
        result = None
    if result:
        result = camel_dict_to_snake_dict(result)
    module.exit_json(changed=changed, efs=result)
def create_or_update_elb(elb_obj):
    """Create ELB or modify main attributes. json_exit here"""

    if elb_obj.elb:
        # ELB exists so check subnets, security groups and tags match what has been passed

        # Subnets
        if not elb_obj.compare_subnets():
            elb_obj.modify_subnets()

        # Security Groups
        if not elb_obj.compare_security_groups():
            elb_obj.modify_security_groups()

        # Tags - only need to play with tags if tags parameter has been set to something
        if elb_obj.tags is not None:

            # Delete necessary tags
            tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(elb_obj.elb['tags']),
                                                                boto3_tag_list_to_ansible_dict(elb_obj.tags), elb_obj.purge_tags)
            if tags_to_delete:
                elb_obj.delete_tags(tags_to_delete)

            # Add/update tags
            if tags_need_modify:
                elb_obj.modify_tags()

    else:
        # Create load balancer
        elb_obj.create_elb()

    # ELB attributes
    elb_obj.update_elb_attributes()
    elb_obj.modify_elb_attributes()

    # Listeners
    listeners_obj = ELBListeners(elb_obj.connection, elb_obj.module, elb_obj.elb['LoadBalancerArn'])

    listeners_to_add, listeners_to_modify, listeners_to_delete = listeners_obj.compare_listeners()

    # Delete listeners
    for listener_to_delete in listeners_to_delete:
        listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_delete, elb_obj.elb['LoadBalancerArn'])
        listener_obj.delete()
        listeners_obj.changed = True

    # Add listeners
    for listener_to_add in listeners_to_add:
        listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_add, elb_obj.elb['LoadBalancerArn'])
        listener_obj.add()
        listeners_obj.changed = True

    # Modify listeners
    for listener_to_modify in listeners_to_modify:
        listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_modify, elb_obj.elb['LoadBalancerArn'])
        listener_obj.modify()
        listeners_obj.changed = True

    # If listeners changed, mark ELB as changed
    if listeners_obj.changed:
        elb_obj.changed = True

    # Rules of each listener
    for listener in listeners_obj.listeners:
        if 'Rules' in listener:
            rules_obj = ELBListenerRules(elb_obj.connection, elb_obj.module, elb_obj.elb['LoadBalancerArn'], listener['Rules'], listener['Port'])

            rules_to_add, rules_to_modify, rules_to_delete = rules_obj.compare_rules()

            # Delete rules
            for rule in rules_to_delete:
                rule_obj = ELBListenerRule(elb_obj.connection, elb_obj.module, {'RuleArn': rule}, rules_obj.listener_arn)
                rule_obj.delete()
                elb_obj.changed = True

            # Add rules
            for rule in rules_to_add:
                rule_obj = ELBListenerRule(elb_obj.connection, elb_obj.module, rule, rules_obj.listener_arn)
                rule_obj.create()
                elb_obj.changed = True

            # Modify rules
            for rule in rules_to_modify:
                rule_obj = ELBListenerRule(elb_obj.connection, elb_obj.module, rule, rules_obj.listener_arn)
                rule_obj.modify()
                elb_obj.changed = True

    # Get the ELB again
    elb_obj.update()

    # Get the ELB listeners again
    listeners_obj.update()

    # Update the ELB attributes
    elb_obj.update_elb_attributes()

    # Convert to snake_case and merge in everything we want to return to the user
    snaked_elb = camel_dict_to_snake_dict(elb_obj.elb)
    snaked_elb.update(camel_dict_to_snake_dict(elb_obj.elb_attributes))
    snaked_elb['listeners'] = []
    for listener in listeners_obj.current_listeners:
        # For each listener, get listener rules
        listener['rules'] = get_elb_listener_rules(elb_obj.connection, elb_obj.module, listener['ListenerArn'])
        snaked_elb['listeners'].append(camel_dict_to_snake_dict(listener))

    # Change tags to ansible friendly dict
    snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags'])

    elb_obj.module.exit_json(changed=elb_obj.changed, **snaked_elb)
Ejemplo n.º 50
0
def snapshot_to_facts(snapshot):
    assert 'DBSnapshotIdentifier' in snapshot, "snapshot argument was not a valid snapshot"
    d = camel_dict_to_snake_dict(snapshot)
    return d
Ejemplo n.º 51
0
def main():
    module = AnsibleAWSModule(
        argument_spec={
            'name': dict(required=True),
            'state': dict(choices=['present', 'absent'], default='present'),
            'description': dict(default=""),
            'kms_key_id': dict(),
            'secret_type': dict(choices=['binary', 'string'],
                                default="string"),
            'secret': dict(default=""),
            'tags': dict(type='dict', default={}),
            'rotation_lambda': dict(),
            'rotation_interval': dict(type='int', default=30),
            'recovery_window': dict(type='int', default=30),
        },
        supports_check_mode=True,
    )

    changed = False
    state = module.params.get('state')
    secrets_mgr = SecretsManagerInterface(module)
    recovery_window = module.params.get('recovery_window')
    secret = Secret(module.params.get('name'),
                    module.params.get('secret_type'),
                    module.params.get('secret'),
                    description=module.params.get('description'),
                    kms_key_id=module.params.get('kms_key_id'),
                    tags=module.params.get('tags'),
                    lambda_arn=module.params.get('rotation_lambda'),
                    rotation_interval=module.params.get('rotation_interval'))

    current_secret = secrets_mgr.get_secret(secret.name)

    if state == 'absent':
        if current_secret:
            if not current_secret.get("DeletedDate"):
                result = camel_dict_to_snake_dict(
                    secrets_mgr.delete_secret(secret.name,
                                              recovery_window=recovery_window))
                changed = True
            elif current_secret.get("DeletedDate") and recovery_window == 0:
                result = camel_dict_to_snake_dict(
                    secrets_mgr.delete_secret(secret.name,
                                              recovery_window=recovery_window))
                changed = True
        else:
            result = "secret does not exist"
    if state == 'present':
        if current_secret is None:
            result = secrets_mgr.create_secret(secret)
            changed = True
        else:
            if current_secret.get("DeletedDate"):
                secrets_mgr.restore_secret(secret.name)
                changed = True
            if not secrets_mgr.secrets_match(secret, current_secret):
                result = secrets_mgr.update_secret(secret)
                changed = True
            if not rotation_match(secret, current_secret):
                result = secrets_mgr.update_rotation(secret)
                changed = True
            current_tags = boto3_tag_list_to_ansible_dict(
                current_secret.get('Tags', []))
            tags_to_add, tags_to_remove = compare_aws_tags(
                current_tags, secret.tags)
            if tags_to_add:
                secrets_mgr.tag_secret(
                    secret.name, ansible_dict_to_boto3_tag_list(tags_to_add))
                changed = True
            if tags_to_remove:
                secrets_mgr.untag_secret(secret.name, tags_to_remove)
                changed = True
        result = camel_dict_to_snake_dict(secrets_mgr.get_secret(secret.name))
        result.pop("response_metadata")
    module.exit_json(changed=changed, secret=result)
Ejemplo n.º 52
0
def find_asgs(conn, module, name=None, tags=None):
    """
    Args:
        conn (boto3.AutoScaling.Client): Valid Boto3 ASG client.
        name (str): Optional name of the ASG you are looking for.
        tags (dict): Optional dictionary of tags and values to search for.

    Basic Usage:
        >>> name = 'public-webapp-production'
        >>> tags = { 'env': 'production' }
        >>> conn = boto3.client('autoscaling', region_name='us-west-2')
        >>> results = find_asgs(name, conn)

    Returns:
        List
        [
            {
                "auto_scaling_group_arn": (
                    "arn:aws:autoscaling:us-west-2:275977225706:autoScalingGroup:58abc686-9783-4528-b338-3ad6f1cbbbaf:"
                    "autoScalingGroupName/public-webapp-production"
                ),
                "auto_scaling_group_name": "public-webapp-production",
                "availability_zones": ["us-west-2c", "us-west-2b", "us-west-2a"],
                "created_time": "2016-02-02T23:28:42.481000+00:00",
                "default_cooldown": 300,
                "desired_capacity": 2,
                "enabled_metrics": [],
                "health_check_grace_period": 300,
                "health_check_type": "ELB",
                "instances":
                [
                    {
                        "availability_zone": "us-west-2c",
                        "health_status": "Healthy",
                        "instance_id": "i-047a12cb",
                        "launch_configuration_name": "public-webapp-production-1",
                        "lifecycle_state": "InService",
                        "protected_from_scale_in": false
                    },
                    {
                        "availability_zone": "us-west-2a",
                        "health_status": "Healthy",
                        "instance_id": "i-7a29df2c",
                        "launch_configuration_name": "public-webapp-production-1",
                        "lifecycle_state": "InService",
                        "protected_from_scale_in": false
                    }
                ],
                "launch_config_name": "public-webapp-production-1",
                "launch_configuration_name": "public-webapp-production-1",
                "load_balancer_names": ["public-webapp-production-lb"],
                "max_size": 4,
                "min_size": 2,
                "new_instances_protected_from_scale_in": false,
                "placement_group": None,
                "status": None,
                "suspended_processes": [],
                "tags":
                [
                    {
                        "key": "Name",
                        "propagate_at_launch": true,
                        "resource_id": "public-webapp-production",
                        "resource_type": "auto-scaling-group",
                        "value": "public-webapp-production"
                    },
                    {
                        "key": "env",
                        "propagate_at_launch": true,
                        "resource_id": "public-webapp-production",
                        "resource_type": "auto-scaling-group",
                        "value": "production"
                    }
                ],
                "target_group_names": [],
                "target_group_arns": [],
                "termination_policies":
                [
                    "Default"
                ],
                "vpc_zone_identifier":
                [
                    "subnet-a1b1c1d1",
                    "subnet-a2b2c2d2",
                    "subnet-a3b3c3d3"
                ]
            }
        ]
    """

    try:
        asgs_paginator = conn.get_paginator('describe_auto_scaling_groups')
        asgs = asgs_paginator.paginate().build_full_result()
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg='Failed to describe AutoScalingGroups')

    if not asgs:
        return asgs

    try:
        elbv2 = module.client('elbv2')
    except ClientError as e:
        # This is nice to have, not essential
        elbv2 = None
    matched_asgs = []

    if name is not None:
        # if the user didn't specify a name
        name_prog = re.compile(r'^' + name)

    for asg in asgs['AutoScalingGroups']:
        if name:
            matched_name = name_prog.search(asg['AutoScalingGroupName'])
        else:
            matched_name = True

        if tags:
            matched_tags = match_asg_tags(tags, asg)
        else:
            matched_tags = True

        if matched_name and matched_tags:
            asg = camel_dict_to_snake_dict(asg)
            # compatibility with ec2_asg module
            if 'launch_configuration_name' in asg:
                asg['launch_config_name'] = asg['launch_configuration_name']
            # workaround for https://github.com/ansible/ansible/pull/25015
            if 'target_group_ar_ns' in asg:
                asg['target_group_arns'] = asg['target_group_ar_ns']
                del (asg['target_group_ar_ns'])
            if asg.get('target_group_arns'):
                if elbv2:
                    try:
                        tg_paginator = elbv2.get_paginator(
                            'describe_target_groups')
                        tg_result = tg_paginator.paginate(
                            TargetGroupArns=asg['target_group_arns']
                        ).build_full_result()
                        asg['target_group_names'] = [
                            tg['TargetGroupName']
                            for tg in tg_result['TargetGroups']
                        ]
                    except ClientError as e:
                        if e.response['Error'][
                                'Code'] == 'TargetGroupNotFound':
                            asg['target_group_names'] = []
                        else:
                            module.fail_json_aws(
                                e, msg="Failed to describe Target Groups")
                    except BotoCoreError as e:
                        module.fail_json_aws(
                            e, msg="Failed to describe Target Groups")
            else:
                asg['target_group_names'] = []
            matched_asgs.append(asg)

    return matched_asgs
Ejemplo n.º 53
0
def delete_bucket(module, s3, bucket):
    if module.check_mode:
        module.exit_json(msg="DELETE operation skipped - running in check mode", changed=True)
    try:
        exists = bucket_check(module, s3, bucket)
        if exists is False:
            return False
        # if there are contents then we need to delete them before we can delete the bucket
        for keys in paginated_list(s3, Bucket=bucket):
            formatted_keys = [{'Key': key} for key in keys]
            if formatted_keys:
                s3.delete_objects(Bucket=bucket, Delete={'Objects': formatted_keys})
        s3.delete_bucket(Bucket=bucket)
        return True
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Failed while deleting bucket %s.", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
Ejemplo n.º 54
0
def lambda_event_stream(module, aws):
    """
    Adds, updates or deletes lambda stream (DynamoDb, Kinesis) event notifications.
    :param module:
    :param aws:
    :return:
    """

    client = aws.client('lambda')
    facts = dict()
    changed = False
    current_state = 'absent'
    state = module.params['state']

    api_params = dict(FunctionName=module.params['lambda_function_arn'])

    # check if required sub-parameters are present and valid
    source_params = module.params['source_params']

    source_arn = source_params.get('source_arn')
    if source_arn:
        api_params.update(EventSourceArn=source_arn)
    else:
        module.fail_json(
            msg=
            "Source parameter 'source_arn' is required for stream event notification."
        )

    # check if optional sub-parameters are valid, if present
    batch_size = source_params.get('batch_size')
    if batch_size:
        try:
            source_params['batch_size'] = int(batch_size)
        except ValueError:
            module.fail_json(
                msg=
                "Source parameter 'batch_size' must be an integer, found: {0}".
                format(source_params['batch_size']))

    # optional boolean value needs special treatment as not present does not imply False
    source_param_enabled = module.boolean(source_params.get('enabled', 'True'))

    # check if event mapping exist
    try:
        facts = client.list_event_source_mappings(
            **api_params)['EventSourceMappings']
        if facts:
            current_state = 'present'
    except ClientError as e:
        module.fail_json(
            msg='Error retrieving stream event notification configuration: {0}'
            .format(e))

    if state == 'present':
        if current_state == 'absent':

            starting_position = source_params.get('starting_position')
            if starting_position:
                api_params.update(StartingPosition=starting_position)
            else:
                module.fail_json(
                    msg=
                    "Source parameter 'starting_position' is required for stream event notification."
                )

            if source_arn:
                api_params.update(Enabled=source_param_enabled)
            if source_params.get('batch_size'):
                api_params.update(BatchSize=source_params.get('batch_size'))

            try:
                if not module.check_mode:
                    facts = client.create_event_source_mapping(**api_params)
                changed = True
            except (ClientError, ParamValidationError,
                    MissingParametersError) as e:
                module.fail_json(
                    msg='Error creating stream source event mapping: {0}'.
                    format(e))

        else:
            # current_state is 'present'
            api_params = dict(
                FunctionName=module.params['lambda_function_arn'])
            current_mapping = facts[0]
            api_params.update(UUID=current_mapping['UUID'])
            mapping_changed = False

            # check if anything changed
            if source_params.get('batch_size') and source_params[
                    'batch_size'] != current_mapping['BatchSize']:
                api_params.update(BatchSize=source_params['batch_size'])
                mapping_changed = True

            if source_param_enabled is not None:
                if source_param_enabled:
                    if current_mapping['State'] not in ('Enabled', 'Enabling'):
                        api_params.update(Enabled=True)
                        mapping_changed = True
                else:
                    if current_mapping['State'] not in ('Disabled',
                                                        'Disabling'):
                        api_params.update(Enabled=False)
                        mapping_changed = True

            if mapping_changed:
                try:
                    if not module.check_mode:
                        facts = client.update_event_source_mapping(
                            **api_params)
                    changed = True
                except (ClientError, ParamValidationError,
                        MissingParametersError) as e:
                    module.fail_json(
                        msg='Error updating stream source event mapping: {0}'.
                        format(e))

    else:
        if current_state == 'present':
            # remove the stream event mapping
            api_params = dict(UUID=facts[0]['UUID'])

            try:
                if not module.check_mode:
                    facts = client.delete_event_source_mapping(**api_params)
                changed = True
            except (ClientError, ParamValidationError,
                    MissingParametersError) as e:
                module.fail_json(
                    msg='Error removing stream source event mapping: {0}'.
                    format(e))

    return camel_dict_to_snake_dict(dict(changed=changed, events=facts))
Ejemplo n.º 55
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            stack_name=dict(),
            all_facts=dict(required=False, default=False, type='bool'),
            stack_policy=dict(required=False, default=False, type='bool'),
            stack_events=dict(required=False, default=False, type='bool'),
            stack_resources=dict(required=False, default=False, type='bool'),
            stack_template=dict(required=False, default=False, type='bool'),
        ))

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=False)

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

    service_mgr = CloudFormationServiceManager(module)

    result = {'ansible_facts': {'cloudformation': {}}}

    for stack_description in service_mgr.describe_stacks(
            module.params.get('stack_name')):
        facts = {'stack_description': stack_description}
        stack_name = stack_description.get('StackName')

        # Create stack output and stack parameter dictionaries
        if facts['stack_description']:
            facts['stack_outputs'] = to_dict(
                facts['stack_description'].get('Outputs'), 'OutputKey',
                'OutputValue')
            facts['stack_parameters'] = to_dict(
                facts['stack_description'].get('Parameters'), 'ParameterKey',
                'ParameterValue')
            facts['stack_tags'] = boto3_tag_list_to_ansible_dict(
                facts['stack_description'].get('Tags'))

        # normalize stack description API output
        facts['stack_description'] = camel_dict_to_snake_dict(
            facts['stack_description'])

        # Create optional stack outputs
        all_facts = module.params.get('all_facts')
        if all_facts or module.params.get('stack_resources'):
            facts['stack_resource_list'] = service_mgr.list_stack_resources(
                stack_name)
            facts['stack_resources'] = to_dict(
                facts.get('stack_resource_list'), 'LogicalResourceId',
                'PhysicalResourceId')
        if all_facts or module.params.get('stack_template'):
            facts['stack_template'] = service_mgr.get_template(stack_name)
        if all_facts or module.params.get('stack_policy'):
            facts['stack_policy'] = service_mgr.get_stack_policy(stack_name)
        if all_facts or module.params.get('stack_events'):
            facts['stack_events'] = service_mgr.describe_stack_events(
                stack_name)

        result['ansible_facts']['cloudformation'][stack_name] = facts

    result['changed'] = False
    module.exit_json(**result)
Ejemplo n.º 56
0
def main():
    argument_spec = ec2_utils.ec2_argument_spec()
    argument_spec.update(
        dict(
            state=dict(type='str',
                       default='present',
                       choices=['present', 'absent']),
            filters=dict(type='dict', default={}),
            vpn_gateway_id=dict(type='str'),
            tags=dict(default={}, type='dict'),
            connection_type=dict(default='ipsec.1', type='str'),
            static_only=dict(default=False, type='bool'),
            customer_gateway_id=dict(type='str'),
            vpn_connection_id=dict(type='str'),
            purge_tags=dict(type='bool', default=False),
            routes=dict(type='list', default=[]),
            purge_routes=dict(type='bool', default=False),
        ))
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

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

    # Retrieve any AWS settings from the environment.
    region, ec2_url, aws_connect_kwargs = ec2_utils.get_aws_connection_info(
        module, boto3=True)

    if not region:
        module.fail_json(
            msg=
            "Either region or AWS_REGION or EC2_REGION environment variable or boto config aws_region or ec2_region must be set."
        )

    connection = ec2_utils.boto3_conn(module,
                                      conn_type='client',
                                      resource='ec2',
                                      region=region,
                                      endpoint=ec2_url,
                                      **aws_connect_kwargs)

    state = module.params.get('state')
    parameters = dict(module.params)

    try:
        if state == 'present':
            changed, response = ensure_present(connection, parameters,
                                               module.check_mode)
        elif state == 'absent':
            changed, response = ensure_absent(connection, parameters,
                                              module.check_mode)
    except VPNConnectionException as e:
        if e.response and e.error_traceback:
            module.fail_json(msg=e.msg,
                             exception=e.error_traceback,
                             **ec2_utils.camel_dict_to_snake_dict(e.response))
        elif e.error_traceback:
            module.fail_json(msg=e.msg, exception=e.error_traceback)
        else:
            module.fail_json(msg=e.msg)

    facts_result = dict(changed=changed,
                        **ec2_utils.camel_dict_to_snake_dict(response))

    module.exit_json(**facts_result)
Ejemplo n.º 57
0
def check_for_update(connection, module_params, vpn_connection_id):
    """ Determines if there are any tags or routes that need to be updated. Ensures non-modifiable attributes aren't expected to change. """
    tags = module_params.get('tags')
    routes = module_params.get('routes')
    purge_tags = module_params.get('purge_tags')
    purge_routes = module_params.get('purge_routes')

    vpn_connection = find_connection(connection,
                                     module_params,
                                     vpn_connection_id=vpn_connection_id)
    current_attrs = ec2_utils.camel_dict_to_snake_dict(vpn_connection)

    # Initialize changes dict
    changes = {
        'tags_to_add': [],
        'tags_to_remove': [],
        'routes_to_add': [],
        'routes_to_remove': []
    }

    # Get changes to tags
    if 'tags' in current_attrs:
        current_tags = ec2_utils.boto3_tag_list_to_ansible_dict(
            current_attrs['tags'], u'key', u'value')
        tags_to_add, changes['tags_to_remove'] = ec2_utils.compare_aws_tags(
            current_tags, tags, purge_tags)
        changes['tags_to_add'] = ec2_utils.ansible_dict_to_boto3_tag_list(
            tags_to_add)
    elif tags:
        current_tags = {}
        tags_to_add, changes['tags_to_remove'] = ec2_utils.compare_aws_tags(
            current_tags, tags, purge_tags)
        changes['tags_to_add'] = ec2_utils.ansible_dict_to_boto3_tag_list(
            tags_to_add)
    # Get changes to routes
    if 'Routes' in vpn_connection:
        current_routes = [
            route['DestinationCidrBlock'] for route in vpn_connection['Routes']
        ]
        if purge_routes:
            changes['routes_to_remove'] = [
                old_route for old_route in current_routes
                if old_route not in routes
            ]
        changes['routes_to_add'] = [
            new_route for new_route in routes
            if new_route not in current_routes
        ]

    # Check if nonmodifiable attributes are attempted to be modified
    for attribute in current_attrs:
        if attribute in ("tags", "routes", "state"):
            continue
        elif attribute == 'options':
            will_be = module_params.get('static_only', None)
            is_now = bool(current_attrs[attribute]['static_routes_only'])
            attribute = 'static_only'
        elif attribute == 'type':
            will_be = module_params.get("connection_type", None)
            is_now = current_attrs[attribute]
        else:
            is_now = current_attrs[attribute]
            will_be = module_params.get(attribute, None)

        if will_be is not None and to_text(will_be) != to_text(is_now):
            raise VPNConnectionException(
                msg=
                "You cannot modify {0}, the current value of which is {1}. Modifiable VPN "
                "connection attributes are tags and routes. The value you tried to change it to "
                "is {2}.".format(attribute, is_now, will_be))

    return changes
Ejemplo n.º 58
0
def create_or_update_glue_job(connection, module, glue_job):
    """
    Create or update an AWS Glue job

    :param connection: AWS boto3 glue connection
    :param module: Ansible module
    :param glue_job: a dict of AWS Glue job parameters or None
    :return:
    """

    changed = False
    params = dict()
    params['Name'] = module.params.get("name")
    params['Role'] = module.params.get("role")
    if module.params.get("allocated_capacity") is not None:
        params['AllocatedCapacity'] = module.params.get("allocated_capacity")
    if module.params.get("command_script_location") is not None:
        params['Command'] = {
            'Name': module.params.get("command_name"),
            'ScriptLocation': module.params.get("command_script_location")
        }
    if module.params.get("connections") is not None:
        params['Connections'] = {
            'Connections': module.params.get("connections")
        }
    if module.params.get("default_arguments") is not None:
        params['DefaultArguments'] = module.params.get("default_arguments")
    if module.params.get("description") is not None:
        params['Description'] = module.params.get("description")
    if module.params.get("max_concurrent_runs") is not None:
        params['ExecutionProperty'] = {
            'MaxConcurrentRuns': module.params.get("max_concurrent_runs")
        }
    if module.params.get("max_retries") is not None:
        params['MaxRetries'] = module.params.get("max_retries")
    if module.params.get("timeout") is not None:
        params['Timeout'] = module.params.get("timeout")

    # If glue_job is not None then check if it needs to be modified, else create it
    if glue_job:
        if _compare_glue_job_params(params, glue_job):
            try:
                # Update job needs slightly modified params
                update_params = {
                    'JobName': params['Name'],
                    'JobUpdate': copy.deepcopy(params)
                }
                del update_params['JobUpdate']['Name']
                connection.update_job(**update_params)
                changed = True
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e)
    else:
        try:
            connection.create_job(**params)
            changed = True
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(e)

    # If changed, get the Glue job again
    if changed:
        glue_job = _get_glue_job(connection, module, params['Name'])

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_job))
Ejemplo n.º 59
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(bucket=dict(required=True),
             dest=dict(default=None),
             encrypt=dict(default=True, type='bool'),
             expiry=dict(default=600, type='int', aliases=['expiration']),
             headers=dict(type='dict'),
             marker=dict(default=""),
             max_keys=dict(default=1000, type='int'),
             metadata=dict(type='dict'),
             mode=dict(choices=[
                 'get', 'put', 'delete', 'create', 'geturl', 'getstr',
                 'delobj', 'list'
             ],
                       required=True),
             object=dict(),
             permission=dict(type='list', default=['private']),
             version=dict(default=None),
             overwrite=dict(aliases=['force'], default='always'),
             prefix=dict(default=""),
             retries=dict(aliases=['retry'], type='int', default=0),
             s3_url=dict(aliases=['S3_URL']),
             rgw=dict(default='no', type='bool'),
             src=dict(),
             ignore_nonexistent_bucket=dict(default=False, type='bool')), )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    if module._name == 's3':
        module.deprecate("The 's3' module is being renamed 'aws_s3'",
                         version=2.7)

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

    bucket = module.params.get('bucket')
    encrypt = module.params.get('encrypt')
    expiry = module.params.get('expiry')
    dest = module.params.get('dest', '')
    headers = module.params.get('headers')
    marker = module.params.get('marker')
    max_keys = module.params.get('max_keys')
    metadata = module.params.get('metadata')
    mode = module.params.get('mode')
    obj = module.params.get('object')
    version = module.params.get('version')
    overwrite = module.params.get('overwrite')
    prefix = module.params.get('prefix')
    retries = module.params.get('retries')
    s3_url = module.params.get('s3_url')
    rgw = module.params.get('rgw')
    src = module.params.get('src')
    ignore_nonexistent_bucket = module.params.get('ignore_nonexistent_bucket')

    if dest:
        dest = os.path.expanduser(dest)

    object_canned_acl = [
        "private", "public-read", "public-read-write", "aws-exec-read",
        "authenticated-read", "bucket-owner-read", "bucket-owner-full-control"
    ]
    bucket_canned_acl = [
        "private", "public-read", "public-read-write", "authenticated-read"
    ]

    if overwrite not in ['always', 'never', 'different']:
        if module.boolean(overwrite):
            overwrite = 'always'
        else:
            overwrite = 'never'

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module,
                                                                  boto3=True)

    if region in ('us-east-1', '', None):
        # default to US Standard region
        location = 'us-east-1'
    else:
        # Boto uses symbolic names for locations but region strings will
        # actually work fine for everything except us-east-1 (US Standard)
        location = region

    if module.params.get('object'):
        obj = module.params['object']
        # If there is a top level object, do nothing - if the object starts with /
        # remove the leading character to maintain compatibility with Ansible versions < 2.4
        if obj.startswith('/'):
            obj = obj[1:]

    # Bucket deletion does not require obj.  Prevents ambiguity with delobj.
    if obj and mode == "delete":
        module.fail_json(msg='Parameter obj cannot be used with mode=delete')

    # allow eucarc environment variables to be used if ansible vars aren't set
    if not s3_url and 'S3_URL' in os.environ:
        s3_url = os.environ['S3_URL']

    # rgw requires an explicit url
    if rgw and not s3_url:
        module.fail_json(msg='rgw flavour requires s3_url')

    # Look at s3_url and tweak connection settings
    # if connecting to RGW, Walrus or fakes3
    for key in ['validate_certs', 'security_token', 'profile_name']:
        aws_connect_kwargs.pop(key, None)
    try:
        s3 = get_s3_connection(module, aws_connect_kwargs, location, rgw,
                               s3_url)
    except (botocore.exceptions.NoCredentialsError,
            botocore.exceptions.ProfileNotFound) as e:
        module.fail_json(
            msg=
            "Can't authorize connection. Check your credentials and profile.",
            exceptions=traceback.format_exc(),
            **camel_dict_to_snake_dict(e.response))

    validate = not ignore_nonexistent_bucket

    # separate types of ACLs
    bucket_acl = [
        acl for acl in module.params.get('permission')
        if acl in bucket_canned_acl
    ]
    object_acl = [
        acl for acl in module.params.get('permission')
        if acl in object_canned_acl
    ]
    error_acl = [
        acl for acl in module.params.get('permission')
        if acl not in bucket_canned_acl and acl not in object_canned_acl
    ]
    if error_acl:
        module.fail_json(msg='Unknown permission specified: %s' % error_acl)

    # First, we check to see if the bucket exists, we get "bucket" returned.
    bucketrtn = bucket_check(module, s3, bucket, validate=validate)

    if validate and mode not in ('create', 'put', 'delete') and not bucketrtn:
        module.fail_json(msg="Source bucket cannot be found.")

    # If our mode is a GET operation (download), go through the procedure as appropriate ...
    if mode == 'get':
        # Next, we check to see if the key in the bucket exists. If it exists, it also returns key_matches md5sum check.
        keyrtn = key_check(module,
                           s3,
                           bucket,
                           obj,
                           version=version,
                           validate=validate)
        if keyrtn is False:
            module.fail_json(msg="Key %s with version id %s does not exist." %
                             (obj, version))

        # If the destination path doesn't exist or overwrite is True, no need to do the md5um etag check, so just download.
        # Compare the remote MD5 sum of the object with the local dest md5sum, if it already exists.
        if path_check(dest):
            # Determine if the remote and local object are identical
            if keysum(module, s3, bucket, obj,
                      version=version) == module.md5(dest):
                sum_matches = True
                if overwrite == 'always':
                    download_s3file(module,
                                    s3,
                                    bucket,
                                    obj,
                                    dest,
                                    retries,
                                    version=version)
                else:
                    module.exit_json(
                        msg=
                        "Local and remote object are identical, ignoring. Use overwrite=always parameter to force.",
                        changed=False)
            else:
                sum_matches = False

                if overwrite in ('always', 'different'):
                    download_s3file(module,
                                    s3,
                                    bucket,
                                    obj,
                                    dest,
                                    retries,
                                    version=version)
                else:
                    module.exit_json(
                        msg=
                        "WARNING: Checksums do not match. Use overwrite parameter to force download."
                    )
        else:
            download_s3file(module,
                            s3,
                            bucket,
                            obj,
                            dest,
                            retries,
                            version=version)

    # if our mode is a PUT operation (upload), go through the procedure as appropriate ...
    if mode == 'put':

        # if putting an object in a bucket yet to be created, acls for the bucket and/or the object may be specified
        # these were separated into the variables bucket_acl and object_acl above

        # Lets check the src path.
        if not path_check(src):
            module.fail_json(msg="Local object for PUT does not exist")

        # Lets check to see if bucket exists to get ground truth.
        if bucketrtn:
            keyrtn = key_check(module,
                               s3,
                               bucket,
                               obj,
                               version=version,
                               validate=validate)

        # Lets check key state. Does it exist and if it does, compute the etag md5sum.
        if bucketrtn and keyrtn:
            # Compare the local and remote object
            if module.md5(src) == keysum(module, s3, bucket, obj):
                sum_matches = True
                if overwrite == 'always':
                    # only use valid object acls for the upload_s3file function
                    module.params['permission'] = object_acl
                    upload_s3file(module, s3, bucket, obj, src, expiry,
                                  metadata, encrypt, headers)
                else:
                    get_download_url(module,
                                     s3,
                                     bucket,
                                     obj,
                                     expiry,
                                     changed=False)
            else:
                sum_matches = False
                if overwrite in ('always', 'different'):
                    # only use valid object acls for the upload_s3file function
                    module.params['permission'] = object_acl
                    upload_s3file(module, s3, bucket, obj, src, expiry,
                                  metadata, encrypt, headers)
                else:
                    module.exit_json(
                        msg=
                        "WARNING: Checksums do not match. Use overwrite parameter to force upload."
                    )

        # If neither exist (based on bucket existence), we can create both.
        if not bucketrtn:
            # only use valid bucket acls for create_bucket function
            module.params['permission'] = bucket_acl
            create_bucket(module, s3, bucket, location)
            # only use valid object acls for the upload_s3file function
            module.params['permission'] = object_acl
            upload_s3file(module, s3, bucket, obj, src, expiry, metadata,
                          encrypt, headers)

        # If bucket exists but key doesn't, just upload.
        if bucketrtn and not keyrtn:
            # only use valid object acls for the upload_s3file function
            module.params['permission'] = object_acl
            upload_s3file(module, s3, bucket, obj, src, expiry, metadata,
                          encrypt, headers)

    # Delete an object from a bucket, not the entire bucket
    if mode == 'delobj':
        if obj is None:
            module.fail_json(msg="object parameter is required")
        if bucket:
            deletertn = delete_key(module, s3, bucket, obj)
            if deletertn is True:
                module.exit_json(msg="Object deleted from bucket %s." % bucket,
                                 changed=True)
        else:
            module.fail_json(msg="Bucket parameter is required.")

    # Delete an entire bucket, including all objects in the bucket
    if mode == 'delete':
        if bucket:
            deletertn = delete_bucket(module, s3, bucket)
            if deletertn is True:
                module.exit_json(
                    msg="Bucket %s and all keys have been deleted." % bucket,
                    changed=True)
        else:
            module.fail_json(msg="Bucket parameter is required.")

    # Support for listing a set of keys
    if mode == 'list':
        exists = bucket_check(module, s3, bucket)

        # If the bucket does not exist then bail out
        if not exists:
            module.fail_json(msg="Target bucket (%s) cannot be found" % bucket)

        list_keys(module, s3, bucket, prefix, marker, max_keys)

    # Need to research how to create directories without "populating" a key, so this should just do bucket creation for now.
    # WE SHOULD ENABLE SOME WAY OF CREATING AN EMPTY KEY TO CREATE "DIRECTORY" STRUCTURE, AWS CONSOLE DOES THIS.
    if mode == 'create':

        # if both creating a bucket and putting an object in it, acls for the bucket and/or the object may be specified
        # these were separated above into the variables bucket_acl and object_acl

        if bucket and not obj:
            if bucketrtn:
                module.exit_json(msg="Bucket already exists.", changed=False)
            else:
                # only use valid bucket acls when creating the bucket
                module.params['permission'] = bucket_acl
                module.exit_json(msg="Bucket created successfully",
                                 changed=create_bucket(module, s3, bucket,
                                                       location))
        if bucket and obj:
            if obj.endswith('/'):
                dirobj = obj
            else:
                dirobj = obj + "/"
            if bucketrtn:
                if key_check(module, s3, bucket, dirobj):
                    module.exit_json(
                        msg="Bucket %s and key %s already exists." %
                        (bucket, obj),
                        changed=False)
                else:
                    # setting valid object acls for the create_dirkey function
                    module.params['permission'] = object_acl
                    create_dirkey(module, s3, bucket, dirobj)
            else:
                # only use valid bucket acls for the create_bucket function
                module.params['permission'] = bucket_acl
                created = create_bucket(module, s3, bucket, location)
                # only use valid object acls for the create_dirkey function
                module.params['permission'] = object_acl
                create_dirkey(module, s3, bucket, dirobj)

    # Support for grabbing the time-expired URL for an object in S3/Walrus.
    if mode == 'geturl':
        if not bucket and not obj:
            module.fail_json(msg="Bucket and Object parameters must be set")

        keyrtn = key_check(module,
                           s3,
                           bucket,
                           obj,
                           version=version,
                           validate=validate)
        if keyrtn:
            get_download_url(module, s3, bucket, obj, expiry)
        else:
            module.fail_json(msg="Key %s does not exist." % obj)

    if mode == 'getstr':
        if bucket and obj:
            keyrtn = key_check(module,
                               s3,
                               bucket,
                               obj,
                               version=version,
                               validate=validate)
            if keyrtn:
                download_s3str(module, s3, bucket, obj, version=version)
            elif version is not None:
                module.fail_json(
                    msg="Key %s with version id %s does not exist." %
                    (obj, version))
            else:
                module.fail_json(msg="Key %s does not exist." % obj)

    module.exit_json(failed=False)
Ejemplo n.º 60
0
def register_target(connection, module):
    """
    Registers a target to a target group

    :param module: ansible module object
    :param connection: boto3 connection
    :return:
    """

    target_az = module.params.get("target_az")
    target_group_arn = module.params.get("target_group_arn")
    target_id = module.params.get("target_id")
    target_port = module.params.get("target_port")
    target_status = module.params.get("target_status")
    target_status_timeout = module.params.get("target_status_timeout")
    changed = False

    if not target_group_arn:
        target_group_arn = convert_tg_name_to_arn(
            connection, module, module.params.get("target_group_name"))

    target = dict(Id=target_id)
    if target_az:
        target['AvailabilityZone'] = target_az
    if target_port:
        target['Port'] = target_port

    target_description = describe_targets(connection, module, target_group_arn,
                                          [target])

    if 'Reason' in target_description['TargetHealth']:
        if target_description['TargetHealth'][
                'Reason'] == "Target.NotRegistered":
            try:
                connection.register_targets(TargetGroupArn=target_group_arn,
                                            Targets=[target])
                changed = True
                if target_status:
                    target_status_check(connection, module, target_group_arn,
                                        target, target_status,
                                        target_status_timeout)
            except ClientError as e:
                module.fail_json(
                    msg="Unable to deregister target {0}: {1}".format(
                        target, to_native(e)),
                    exception=traceback.format_exc(),
                    **camel_dict_to_snake_dict(e.response))
            except BotoCoreError as e:
                module.fail_json(
                    msg="Unable to deregister target {0}: {1}".format(
                        target, to_native(e)),
                    exception=traceback.format_exc())

    # Get all targets for the target group
    target_descriptions = describe_targets(connection, module,
                                           target_group_arn, [])

    module.exit_json(changed=changed,
                     target_health_descriptions=camel_dict_to_snake_dict(
                         target_descriptions),
                     target_group_arn=target_group_arn)