def delete_unused_regex_pattern(self, regex_pattern_set_id): try: regex_pattern_set = self.client.get_regex_pattern_set( RegexPatternSetId=regex_pattern_set_id)['RegexPatternSet'] updates = list() for regex_pattern_string in regex_pattern_set[ 'RegexPatternStrings']: updates.append({ 'Action': 'DELETE', 'RegexPatternString': regex_pattern_string }) run_func_with_change_token_backoff( self.client, self.module, { 'RegexPatternSetId': regex_pattern_set_id, 'Updates': updates }, self.client.update_regex_pattern_set) run_func_with_change_token_backoff( self.client, self.module, {'RegexPatternSetId': regex_pattern_set_id}, self.client.delete_regex_pattern_set, wait=True) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: if e.response['Error']['Code'] == 'WAFNonexistentItemException': return self.module.fail_json_aws(e, msg='Could not delete regex pattern')
def find_and_delete_condition(self, condition_set_id): current_condition = self.get_condition_by_id(condition_set_id) in_use_rules = self.find_condition_in_rules(condition_set_id) if in_use_rules: rulenames = ', '.join(in_use_rules) self.module.fail_json(msg="Condition %s is in use by %s" % (current_condition['Name'], rulenames)) if current_condition[self.conditiontuples]: # Filters are deleted using update with the DELETE action func = getattr(self.client, 'update_' + self.method_suffix) params = self.format_for_deletion(current_condition) try: # We do not need to wait for the conditiontuple delete because we wait later for the delete_* call run_func_with_change_token_backoff(self.client, self.module, params, func) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws( e, msg='Could not delete filters from condition') func = getattr(self.client, 'delete_' + self.method_suffix) params = dict() params[self.conditionsetid] = condition_set_id try: run_func_with_change_token_backoff(self.client, self.module, params, func, wait=True) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws(e, msg='Could not delete condition') # tidy up regex patterns if self.type == 'regex': self.tidy_up_regex_patterns(current_condition) return True, {}
def ensure_regex_pattern_present(self, regex_pattern): name = regex_pattern['name'] pattern_set = self.get_regex_pattern_by_name(name) if not pattern_set: pattern_set = run_func_with_change_token_backoff( self.client, self.module, {'Name': name}, self.client.create_regex_pattern_set)['RegexPatternSet'] missing = set(regex_pattern['regex_strings']) - set( pattern_set['RegexPatternStrings']) extra = set(pattern_set['RegexPatternStrings']) - set( regex_pattern['regex_strings']) if not missing and not extra: return pattern_set updates = [{ 'Action': 'INSERT', 'RegexPatternString': pattern } for pattern in missing] updates.extend([{ 'Action': 'DELETE', 'RegexPatternString': pattern } for pattern in extra]) run_func_with_change_token_backoff( self.client, self.module, { 'RegexPatternSetId': pattern_set['RegexPatternSetId'], 'Updates': updates }, self.client.update_regex_pattern_set, wait=True) return self.get_regex_pattern_set_with_backoff( pattern_set['RegexPatternSetId'])['RegexPatternSet']
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
def remove_rules_from_web_acl(client, module, web_acl_id): acl = get_web_acl(client, module, web_acl_id) deletions = [format_for_update(rule, 'DELETE') for rule in acl['Rules']] try: params = {'WebACLId': acl['WebACLId'], 'DefaultAction': acl['DefaultAction'], 'Updates': deletions} run_func_with_change_token_backoff(client, module, params, client.update_web_acl) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not remove rule')
def ensure_web_acl_absent(client, module): web_acl_id = get_web_acl_by_name(client, module, module.params['name']) if web_acl_id: web_acl = get_web_acl(client, module, web_acl_id) if web_acl['Rules']: remove_rules_from_web_acl(client, module, web_acl_id) try: run_func_with_change_token_backoff(client, module, {'WebACLId': web_acl_id}, client.delete_web_acl, wait=True) return True, {} except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not delete Web ACL') return False, {}
def remove_rule_conditions(client, module, rule_id): conditions = get_rule(client, module, rule_id)['Predicates'] updates = [ format_for_deletion(camel_dict_to_snake_dict(condition)) for condition in conditions ] try: run_func_with_change_token_backoff(client, module, { 'RuleId': rule_id, 'Updates': updates }, client.update_rule) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not remove rule conditions')
def find_and_update_condition(self, condition_set_id): current_condition = self.get_condition_by_id(condition_set_id) update = self.format_for_update(condition_set_id) missing = self.find_missing(update, current_condition) if self.module.params.get('purge_filters'): extra = [{ 'Action': 'DELETE', self.conditiontuple: current_tuple } for current_tuple in current_condition[self.conditiontuples] if current_tuple not in [ desired[self.conditiontuple] for desired in update['Updates'] ]] else: extra = [] changed = bool(missing or extra) if changed: update['Updates'] = missing + extra func = getattr(self.client, 'update_' + self.method_suffix) try: result = run_func_with_change_token_backoff(self.client, self.module, update, func, wait=True) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws(e, msg='Could not update condition') return changed, self.get_condition_by_id(condition_set_id)
def ensure_web_acl_present(client, module): changed = False result = None name = module.params['name'] web_acl_id = get_web_acl_by_name(client, module, name) if web_acl_id: (changed, result) = find_and_update_web_acl(client, module, web_acl_id) else: metric_name = module.params['metric_name'] if not metric_name: metric_name = re.sub(r'[^A-Za-z0-9]', '', module.params['name']) default_action = module.params['default_action'].upper() try: params = { 'Name': name, 'MetricName': metric_name, 'DefaultAction': { 'Type': default_action } } new_web_acl = run_func_with_change_token_backoff( client, module, params, client.create_web_acl) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not create Web ACL') (changed, result) = find_and_update_web_acl(client, module, new_web_acl['WebACL']['WebACLId']) return changed, result
def ensure_condition_present(self): name = self.module.params['name'] condition_set_id = self.get_condition_by_name(name) if condition_set_id: return self.find_and_update_condition(condition_set_id) else: params = dict() params['Name'] = name func = getattr(self.client, 'create_' + self.method_suffix) try: condition = run_func_with_change_token_backoff( self.client, self.module, params, func) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws(e, msg='Could not create condition') return self.find_and_update_condition( condition[self.conditionset][self.conditionsetid])
def ensure_rule_absent(client, module): rule_id = get_rule_by_name(client, module, module.params['name']) in_use_web_acls = find_rule_in_web_acls(client, module, rule_id) if in_use_web_acls: web_acl_names = ', '.join(in_use_web_acls) module.fail_json(msg="Rule %s is in use by Web ACL(s) %s" % (module.params['name'], web_acl_names)) if rule_id: remove_rule_conditions(client, module, rule_id) try: return True, run_func_with_change_token_backoff( client, module, {'RuleId': rule_id}, client.delete_rule, wait=True) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not delete rule') return False, {}
def ensure_rule_present(client, module): name = module.params['name'] rule_id = get_rule_by_name(client, module, name) params = dict() if rule_id: return find_and_update_rule(client, module, rule_id) else: params['Name'] = module.params['name'] metric_name = module.params['metric_name'] if not metric_name: metric_name = re.sub(r'[^a-zA-Z0-9]', '', module.params['name']) params['MetricName'] = metric_name try: new_rule = run_func_with_change_token_backoff( client, module, params, client.create_rule)['Rule'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not create rule') return find_and_update_rule(client, module, new_rule['RuleId'])
def find_and_update_rule(client, module, rule_id): rule = get_rule(client, module, rule_id) rule_id = rule['RuleId'] existing_conditions = dict( (condition_type, dict()) for condition_type in MATCH_LOOKUP) desired_conditions = dict( (condition_type, dict()) for condition_type in MATCH_LOOKUP) all_conditions = dict() for condition_type in MATCH_LOOKUP: method = 'list_' + MATCH_LOOKUP[condition_type]['method'] + 's' all_conditions[condition_type] = dict() try: paginator = client.get_paginator(method) func = paginator.paginate().build_full_result except (KeyError, botocore.exceptions.OperationNotPageableError): # list_geo_match_sets and list_regex_match_sets do not have a paginator # and throw different exceptions func = getattr(client, method) try: pred_results = func()[MATCH_LOOKUP[condition_type]['conditionset'] + 's'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not list %s conditions' % condition_type) for pred in pred_results: pred['DataId'] = pred[MATCH_LOOKUP[condition_type]['conditionset'] + 'Id'] all_conditions[condition_type][ pred['Name']] = camel_dict_to_snake_dict(pred) all_conditions[condition_type][ pred['DataId']] = camel_dict_to_snake_dict(pred) for condition in module.params['conditions']: desired_conditions[condition['type']][condition['name']] = condition reverse_condition_types = dict( (v['type'], k) for (k, v) in MATCH_LOOKUP.items()) for condition in rule['Predicates']: existing_conditions[reverse_condition_types[condition['Type']]][ condition['DataId']] = camel_dict_to_snake_dict(condition) insertions = list() deletions = list() for condition_type in desired_conditions: for (condition_name, condition) in desired_conditions[condition_type].items(): if condition_name not in all_conditions[condition_type]: module.fail_json(msg="Condition %s of type %s does not exist" % (condition_name, condition_type)) condition['data_id'] = all_conditions[condition_type][ condition_name]['data_id'] if condition['data_id'] not in existing_conditions[condition_type]: insertions.append(format_for_insertion(condition)) if module.params['purge_conditions']: for condition_type in existing_conditions: deletions.extend([ format_for_deletion(condition) for condition in existing_conditions[condition_type].values() if not all_conditions[condition_type][condition['data_id']] ['name'] in desired_conditions[condition_type] ]) changed = bool(insertions or deletions) update = {'RuleId': rule_id, 'Updates': insertions + deletions} if changed: try: run_func_with_change_token_backoff(client, module, update, client.update_rule, wait=True) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg='Could not update rule conditions') return changed, get_rule(client, module, rule_id)