def find_and_update_web_acl(client, module, web_acl_id):
    acl = get_web_acl(client, module, web_acl_id)
    rule_lookup = create_rule_lookup(client, module)
    existing_rules = acl['Rules']
    desired_rules = [{
        'RuleId': rule_lookup[rule['name']]['RuleId'],
        'Priority': rule['priority'],
        'Action': {
            'Type': rule['action'].upper()
        },
        'Type': rule.get('type', 'regular').upper()
    } for rule in module.params['rules']]
    missing = [rule for rule in desired_rules if rule not in existing_rules]
    extras = []
    if module.params['purge_rules']:
        extras = [rule for rule in existing_rules if rule not in desired_rules]

    insertions = [format_for_update(rule, 'INSERT') for rule in missing]
    deletions = [format_for_update(rule, 'DELETE') for rule in extras]
    changed = bool(insertions + deletions)

    # Purge rules before adding new ones in case a deletion shares the same
    # priority as an insertion.
    params = {
        'WebACLId': acl['WebACLId'],
        'DefaultAction': acl['DefaultAction']
    }
    change_tokens = []
    if deletions:
        try:
            params['Updates'] = deletions
            result = run_func_with_change_token_backoff(
                client, module, params, client.update_web_acl)
            change_tokens.append(result['ChangeToken'])
            get_waiter(
                client,
                'change_token_in_sync',
            ).wait(ChangeToken=result['ChangeToken'])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not update Web ACL')
    if insertions:
        try:
            params['Updates'] = insertions
            result = run_func_with_change_token_backoff(
                client, module, params, client.update_web_acl)
            change_tokens.append(result['ChangeToken'])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not update Web ACL')
    if change_tokens:
        for token in change_tokens:
            get_waiter(
                client,
                'change_token_in_sync',
            ).wait(ChangeToken=token)
    if changed:
        acl = get_web_acl(client, module, web_acl_id)
    return changed, acl
Exemple #2
0
def handle_waiter(conn, module, waiter_name, params, start_time):
    try:
        get_waiter(conn, waiter_name).wait(
            **waiter_params(module, params, start_time)
        )
    except botocore.exceptions.WaiterError as e:
        module.fail_json_aws(e, "Failed to wait for updates to complete")
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, "An exception happened while trying to wait for updates")
Exemple #3
0
def run_func_with_change_token_backoff(client,
                                       module,
                                       params,
                                       func,
                                       wait=False):
    params['ChangeToken'] = get_change_token(client, module)
    result = func(**params)
    if wait:
        get_waiter(
            client,
            'change_token_in_sync',
        ).wait(ChangeToken=result['ChangeToken'])
    return result
def wait_until(client, module, waiter_name='cluster_active'):
    name = module.params.get('name')
    wait_timeout = module.params.get('wait_timeout')

    waiter = get_waiter(client, waiter_name)
    attempts = 1 + int(wait_timeout / waiter.config.delay)
    waiter.wait(name=name, WaiterConfig={'MaxAttempts': attempts})
Exemple #5
0
 def wait(client, db_instance_id, waiter_name, extra_retry_codes):
     retry = AWSRetry.jittered_backoff(
         catch_extra_error_codes=extra_retry_codes)
     try:
         waiter = client.get_waiter(waiter_name)
     except ValueError:
         # using a waiter in ansible.module_utils.aws.waiters
         waiter = get_waiter(client, waiter_name)
     waiter.wait(WaiterConfig={
         'Delay': 60,
         'MaxAttempts': 60
     },
                 DBInstanceIdentifier=db_instance_id)
Exemple #6
0
def create_vgw(client, module):
    params = dict()
    params['Type'] = module.params.get('type')
    if module.params.get('asn'):
        params['AmazonSideAsn'] = module.params.get('asn')

    try:
        response = client.create_vpn_gateway(**params)
        get_waiter(client, 'vpn_gateway_exists').wait(
            VpnGatewayIds=[response['VpnGateway']['VpnGatewayId']])
    except botocore.exceptions.WaiterError as e:
        module.fail_json(
            msg="Failed to wait for Vpn Gateway {0} to be available".format(
                response['VpnGateway']['VpnGatewayId']),
            exception=traceback.format_exc())
    except is_boto3_error_code('VpnGatewayLimitExceeded'):
        module.fail_json(msg="Too many VPN gateways exist in this account.",
                         exception=traceback.format_exc())
    except botocore.exceptions.ClientError as e:  # pylint: disable=duplicate-except
        module.fail_json(msg=to_native(e), exception=traceback.format_exc())

    result = response
    return result
Exemple #7
0
def wait_for_cluster_status(client, module, db_cluster_id, waiter_name):
    try:
        waiter = get_waiter(
            client, waiter_name).wait(DBClusterIdentifier=db_cluster_id)
    except WaiterError as e:
        if waiter_name == 'cluster_deleted':
            msg = "Failed to wait for DB cluster {0} to be deleted".format(
                db_cluster_id)
        else:
            msg = "Failed to wait for DB cluster {0} to be available".format(
                db_cluster_id)
        module.fail_json_aws(e, msg=msg)
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(
            e,
            msg=
            "Failed with an unexpected error while waiting for the DB cluster {0}"
            .format(db_cluster_id))
Exemple #8
0
    def ensure_igw_present(self, vpc_id, tags):
        self.check_input_tags(tags)

        igw = self.get_matching_igw(vpc_id)

        if igw is None:
            if self._check_mode:
                self._results['changed'] = True
                self._results['gateway_id'] = None
                return self._results

            try:
                response = self._connection.create_internet_gateway()

                # Ensure the gateway exists before trying to attach it or add tags
                waiter = get_waiter(self._connection,
                                    'internet_gateway_exists')
                waiter.wait(InternetGatewayIds=[
                    response['InternetGateway']['InternetGatewayId']
                ])

                igw = camel_dict_to_snake_dict(response['InternetGateway'])
                self._connection.attach_internet_gateway(
                    InternetGatewayId=igw['internet_gateway_id'], VpcId=vpc_id)
                self._results['changed'] = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                self._module.fail_json_aws(
                    e, msg='Unable to create Internet Gateway')

        igw['vpc_id'] = vpc_id

        igw['tags'] = self.ensure_tags(igw_id=igw['internet_gateway_id'],
                                       tags=tags,
                                       add_only=False)

        igw_info = self.get_igw_info(igw)
        self._results.update(igw_info)

        return self._results
Exemple #9
0
def ensure_vgw_present(client, module):

    # If an existing vgw name and type matches our args, then a match is considered to have been
    # found and we will not create another vgw.

    changed = False
    params = dict()
    result = dict()
    params['Name'] = module.params.get('name')
    params['VpcId'] = module.params.get('vpc_id')
    params['Type'] = module.params.get('type')
    params['Tags'] = module.params.get('tags')
    params['VpnGatewayIds'] = module.params.get('vpn_gateway_id')

    # check that the vpc_id exists. If not, an exception is thrown
    if params['VpcId']:
        vpc = find_vpc(client, module)

    # check if a gateway matching our module args already exists
    existing_vgw = find_vgw(client, module)

    if existing_vgw != []:
        vpn_gateway_id = existing_vgw[0]['VpnGatewayId']
        vgw, changed = check_tags(client, module, existing_vgw, vpn_gateway_id)

        # if a vpc_id was provided, check if it exists and if it's attached
        if params['VpcId']:

            current_vpc_attachments = existing_vgw[0]['VpcAttachments']

            if current_vpc_attachments != [] and current_vpc_attachments[0][
                    'State'] == 'attached':
                if current_vpc_attachments[0]['VpcId'] != params[
                        'VpcId'] or current_vpc_attachments[0][
                            'State'] != 'attached':
                    # detach the existing vpc from the virtual gateway
                    vpc_to_detach = current_vpc_attachments[0]['VpcId']
                    detach_vgw(client, module, vpn_gateway_id, vpc_to_detach)
                    get_waiter(client, 'vpn_gateway_detached').wait(
                        VpnGatewayIds=[vpn_gateway_id])
                    attached_vgw = attach_vgw(client, module, vpn_gateway_id)
                    changed = True
            else:
                # attach the vgw to the supplied vpc
                attached_vgw = attach_vgw(client, module, vpn_gateway_id)
                changed = True

        # if params['VpcId'] is not provided, check the vgw is attached to a vpc. if so, detach it.
        else:
            existing_vgw = find_vgw(client, module, [vpn_gateway_id])

            if existing_vgw[0]['VpcAttachments'] != []:
                if existing_vgw[0]['VpcAttachments'][0]['State'] == 'attached':
                    # detach the vpc from the vgw
                    vpc_to_detach = existing_vgw[0]['VpcAttachments'][0][
                        'VpcId']
                    detach_vgw(client, module, vpn_gateway_id, vpc_to_detach)
                    changed = True

    else:
        # create a new vgw
        new_vgw = create_vgw(client, module)
        changed = True
        vpn_gateway_id = new_vgw['VpnGateway']['VpnGatewayId']

        # tag the new virtual gateway
        create_tags(client, module, vpn_gateway_id)

        # if a vpc-id was supplied, attempt to attach it to the vgw
        if params['VpcId']:
            attached_vgw = attach_vgw(client, module, vpn_gateway_id)
            changed = True

    # return current state of the vgw
    vgw = find_vgw(client, module, [vpn_gateway_id])
    result = get_vgw_info(vgw)
    return changed, result
def ensure_route_table_present(connection, module):

    lookup = module.params.get('lookup')
    propagating_vgw_ids = module.params.get('propagating_vgw_ids')
    purge_routes = module.params.get('purge_routes')
    purge_subnets = module.params.get('purge_subnets')
    purge_tags = module.params.get('purge_tags')
    route_table_id = module.params.get('route_table_id')
    subnets = module.params.get('subnets')
    tags = module.params.get('tags')
    vpc_id = module.params.get('vpc_id')
    routes = create_route_spec(connection, module, vpc_id)

    changed = False
    tags_valid = False

    if lookup == 'tag':
        if tags is not None:
            try:
                route_table = get_route_table_by_tags(connection, module, vpc_id, tags)
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Error finding route table with lookup 'tag'")
        else:
            route_table = None
    elif lookup == 'id':
        try:
            route_table = get_route_table_by_id(connection, module, route_table_id)
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Error finding route table with lookup 'id'")

    # If no route table returned then create new route table
    if route_table is None:
        changed = True
        if not module.check_mode:
            try:
                route_table = connection.create_route_table(VpcId=vpc_id)['RouteTable']
                # try to wait for route table to be present before moving on
                get_waiter(
                    connection, 'route_table_exists'
                ).wait(
                    RouteTableIds=[route_table['RouteTableId']],
                )
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Error creating route table")
        else:
            route_table = {"id": "rtb-xxxxxxxx", "route_table_id": "rtb-xxxxxxxx", "vpc_id": vpc_id}
            module.exit_json(changed=changed, route_table=route_table)

    if routes is not None:
        result = ensure_routes(connection=connection, module=module, route_table=route_table,
                               route_specs=routes, propagating_vgw_ids=propagating_vgw_ids,
                               check_mode=module.check_mode, purge_routes=purge_routes)
        changed = changed or result['changed']

    if propagating_vgw_ids is not None:
        result = ensure_propagation(connection=connection, module=module, route_table=route_table,
                                    propagating_vgw_ids=propagating_vgw_ids, check_mode=module.check_mode)
        changed = changed or result['changed']

    if not tags_valid and tags is not None:
        result = ensure_tags(connection=connection, module=module, resource_id=route_table['RouteTableId'], tags=tags,
                             purge_tags=purge_tags, check_mode=module.check_mode)
        route_table['Tags'] = result['tags']
        changed = changed or result['changed']

    if subnets is not None:
        associated_subnets = find_subnets(connection, module, vpc_id, subnets)

        result = ensure_subnet_associations(connection=connection, module=module, route_table=route_table,
                                            subnets=associated_subnets, check_mode=module.check_mode,
                                            purge_subnets=purge_subnets)
        changed = changed or result['changed']

    if changed:
        # pause to allow route table routes/subnets/associations to be updated before exiting with final state
        sleep(5)
    module.exit_json(changed=changed, route_table=get_route_table_info(connection, module, route_table))