Adding support for ForwardConfig
property in ListernRule
in CloudFormation (#3993)
* Add ssm parsing support for cloudformation stacks * Start adding unit tests for ssm parameter parsing * Add tests for code update * Add tests to parse ssm parameters code * Fix black lint errors * Fix bug. * Need to specify region_name * region needs to be same * Use ssm_backends[region] instead of ssm_backend * StringList -> string * Linting * check if servermode tests are on * Typo * Added support for ListenerRule. Will remove cruft * Pushing latest * Something works * Put back ripped out code * Save point. Incase I need more validations * Revert "Save point. Incase I need more validations" This reverts commit dac4953335dd9335eddb7a91a63667bc3c17104c. * Fixed validations and some refactor * Fix formatting * Linting * Cannot refactor if I have to fix all tests * Remove exceptions for now. Will do in another PR * Remove validations. Will add in next PR * Fix broken tests. Almost.: * Fix all tests. Some sneaky for now. * Python2 making me write bad code * OrderedDict.move_to_end() does not work in python2 * Linting * Add more checks to field in conditions later. * Unwnated change in FakeListener * Revert "Unwnated change in FakeListener" This reverts commit 962c2fdfd76fce999de9feccf1dd1c3ec48c459f. * Add back default listener rule * Linting fix * Fix priority sorting * Add cloudformation test for edge case * Add validation for ForwardConfig in Action of ListernRule CF * use not in * set the priority template correctly * Check for boolean in condition * One more check Co-authored-by: Bert Blommers <bblommers@users.noreply.github.com>
This commit is contained in:
parent
43426c71f4
commit
3f5408c9d0
@ -330,7 +330,24 @@ class FakeListenerRule(CloudFormationModel):
|
|||||||
default_actions = []
|
default_actions = []
|
||||||
for i, action in enumerate(properties["Actions"]):
|
for i, action in enumerate(properties["Actions"]):
|
||||||
action_type = action["Type"]
|
action_type = action["Type"]
|
||||||
if action_type == "forward":
|
if action_type == "forward" and "ForwardConfig" in action:
|
||||||
|
action_forward_config = action["ForwardConfig"]
|
||||||
|
action_target_groups = action_forward_config["TargetGroups"]
|
||||||
|
target_group_action = []
|
||||||
|
for action_target_group in action_target_groups:
|
||||||
|
target_group_action.append(
|
||||||
|
{
|
||||||
|
"target_group_arn": action_target_group["TargetGroupArn"],
|
||||||
|
"weight": action_target_group["Weight"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
default_actions.append(
|
||||||
|
{
|
||||||
|
"type": action_type,
|
||||||
|
"forward_config": {"target_groups": target_group_action},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
elif action_type == "forward" and "ForwardConfig" not in action:
|
||||||
default_actions.append(
|
default_actions.append(
|
||||||
{"type": action_type, "target_group_arn": action["TargetGroupArn"],}
|
{"type": action_type, "target_group_arn": action["TargetGroupArn"],}
|
||||||
)
|
)
|
||||||
@ -381,7 +398,19 @@ class FakeAction(BaseModel):
|
|||||||
def to_xml(self):
|
def to_xml(self):
|
||||||
template = Template(
|
template = Template(
|
||||||
"""<Type>{{ action.type }}</Type>
|
"""<Type>{{ action.type }}</Type>
|
||||||
{% if action.type == "forward" %}
|
{% if action.type == "forward" and "forward_config" in action.data %}
|
||||||
|
<ForwardConfig>
|
||||||
|
<TargetGroups>
|
||||||
|
{% for target_group in action.data["forward_config"]["target_groups"] %}
|
||||||
|
<member>
|
||||||
|
<TargetGroupArn>{{ target_group["target_group_arn"] }}</TargetGroupArn>
|
||||||
|
<Weight>{{ target_group["weight"] }}</Weight>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</TargetGroups>
|
||||||
|
</ForwardConfig>
|
||||||
|
{% endif %}
|
||||||
|
{% if action.type == "forward" and "forward_config" not in action.data %}
|
||||||
<TargetGroupArn>{{ action.data["target_group_arn"] }}</TargetGroupArn>
|
<TargetGroupArn>{{ action.data["target_group_arn"] }}</TargetGroupArn>
|
||||||
{% elif action.type == "redirect" %}
|
{% elif action.type == "redirect" %}
|
||||||
<RedirectConfig>
|
<RedirectConfig>
|
||||||
@ -666,7 +695,7 @@ class ELBv2Backend(BaseBackend):
|
|||||||
for i, action in enumerate(actions):
|
for i, action in enumerate(actions):
|
||||||
index = i + 1
|
index = i + 1
|
||||||
action_type = action.type
|
action_type = action.type
|
||||||
if action_type == "forward":
|
if action_type == "forward" and "target_group_arn" in action.data:
|
||||||
action_target_group_arn = action.data["target_group_arn"]
|
action_target_group_arn = action.data["target_group_arn"]
|
||||||
if action_target_group_arn not in target_group_arns:
|
if action_target_group_arn not in target_group_arns:
|
||||||
raise ActionTargetGroupNotFoundError(action_target_group_arn)
|
raise ActionTargetGroupNotFoundError(action_target_group_arn)
|
||||||
@ -674,6 +703,16 @@ class ELBv2Backend(BaseBackend):
|
|||||||
self._validate_fixed_response_action(action, i, index)
|
self._validate_fixed_response_action(action, i, index)
|
||||||
elif action_type in ["redirect", "authenticate-cognito"]:
|
elif action_type in ["redirect", "authenticate-cognito"]:
|
||||||
pass
|
pass
|
||||||
|
# pass if listener rule has forward_config as an Action property
|
||||||
|
elif (
|
||||||
|
action_type == "forward"
|
||||||
|
and "forward_config._target_groups.member.{}._target_group_arn".format(
|
||||||
|
index
|
||||||
|
)
|
||||||
|
in action.data.keys()
|
||||||
|
or "forward_config" in action.data.keys()
|
||||||
|
):
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
raise InvalidActionTypeError(action_type, index)
|
raise InvalidActionTypeError(action_type, index)
|
||||||
|
|
||||||
|
@ -739,7 +739,19 @@ CREATE_RULE_TEMPLATE = """<CreateRuleResponse xmlns="http://elasticloadbalancing
|
|||||||
{% for action in rules.actions %}
|
{% for action in rules.actions %}
|
||||||
<member>
|
<member>
|
||||||
<Type>{{ action["type"] }}</Type>
|
<Type>{{ action["type"] }}</Type>
|
||||||
{% if action["type"] == "forward" %}
|
{% if action["type"] == "forward" and "forward_config" in action.data %}
|
||||||
|
<ForwardConfig>
|
||||||
|
<TargetGroups>
|
||||||
|
{% for target_group in action.data["forward_config"]["target_groups"] %}
|
||||||
|
<member>
|
||||||
|
<TargetGroupArn>{{ target_group["target_group_arn"] }}</TargetGroupArn>
|
||||||
|
<Weight>{{ target_group["weight"] }}</Weight>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</TargetGroups>
|
||||||
|
</ForwardConfig>
|
||||||
|
{% endif %}
|
||||||
|
{% if action["type"] == "forward" and "forward_config" not in action.data %}
|
||||||
<TargetGroupArn>{{ action["target_group_arn"] }}</TargetGroupArn>
|
<TargetGroupArn>{{ action["target_group_arn"] }}</TargetGroupArn>
|
||||||
{% elif action["type"] == "redirect" %}
|
{% elif action["type"] == "redirect" %}
|
||||||
<RedirectConfig>{{ action["redirect_config"] }}</RedirectConfig>
|
<RedirectConfig>{{ action["redirect_config"] }}</RedirectConfig>
|
||||||
@ -1235,11 +1247,10 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
|
|||||||
SET_RULE_PRIORITIES_TEMPLATE = """<SetRulePrioritiesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
SET_RULE_PRIORITIES_TEMPLATE = """<SetRulePrioritiesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<SetRulePrioritiesResult>
|
<SetRulePrioritiesResult>
|
||||||
<Rules>
|
<Rules>
|
||||||
{% for rule in rules %}
|
|
||||||
<member>
|
<member>
|
||||||
<IsDefault>{{ "true" if rule.is_default else "false" }}</IsDefault>
|
<IsDefault>{{ "true" if rules.is_default else "false" }}</IsDefault>
|
||||||
<Conditions>
|
<Conditions>
|
||||||
{% for condition in rule.conditions %}
|
{% for condition in rules.conditions %}
|
||||||
<member>
|
<member>
|
||||||
<Field>{{ condition["field"] }}</Field>
|
<Field>{{ condition["field"] }}</Field>
|
||||||
<Values>
|
<Values>
|
||||||
@ -1250,18 +1261,31 @@ SET_RULE_PRIORITIES_TEMPLATE = """<SetRulePrioritiesResponse xmlns="http://elast
|
|||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Conditions>
|
</Conditions>
|
||||||
<Priority>{{ rule.priority }}</Priority>
|
<Priority>{{ rules.priority }}</Priority>
|
||||||
<Actions>
|
<Actions>
|
||||||
{% for action in rule.actions %}
|
{% for action in rules.actions %}
|
||||||
<member>
|
<member>
|
||||||
<Type>{{ action["type"] }}</Type>
|
<Type>{{ action["type"] }}</Type>
|
||||||
|
{% if action["type"] == "forward" and "forward_config" in action.data %}
|
||||||
|
<ForwardConfig>
|
||||||
|
<TargetGroups>
|
||||||
|
{% for target_group in action.data["forward_config"]["target_groups"] %}
|
||||||
|
<member>
|
||||||
|
<TargetGroupArn>{{ target_group["target_group_arn"] }}</TargetGroupArn>
|
||||||
|
<Weight>{{ target_group["weight"] }}</Weight>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</TargetGroups>
|
||||||
|
</ForwardConfig>
|
||||||
|
{% endif %}
|
||||||
|
{% if action["type"] == "forward" and "forward_config" not in action.data %}
|
||||||
<TargetGroupArn>{{ action["target_group_arn"] }}</TargetGroupArn>
|
<TargetGroupArn>{{ action["target_group_arn"] }}</TargetGroupArn>
|
||||||
|
{% endif %}
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Actions>
|
</Actions>
|
||||||
<RuleArn>{{ rule.arn }}</RuleArn>
|
<RuleArn>{{ rules.arn }}</RuleArn>
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
|
||||||
</Rules>
|
</Rules>
|
||||||
</SetRulePrioritiesResult>
|
</SetRulePrioritiesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
|
@ -2307,13 +2307,38 @@ def test_stack_elbv2_resources_integration():
|
|||||||
"Type": "AWS::ElasticLoadBalancingV2::ListenerRule",
|
"Type": "AWS::ElasticLoadBalancingV2::ListenerRule",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
"Actions": [
|
"Actions": [
|
||||||
{"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup2"}}
|
{
|
||||||
|
"Type": "forward",
|
||||||
|
"ForwardConfig": {
|
||||||
|
"TargetGroups": [
|
||||||
|
{
|
||||||
|
"TargetGroupArn": {"Ref": "mytargetgroup2"},
|
||||||
|
"Weight": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TargetGroupArn": {"Ref": "mytargetgroup1"},
|
||||||
|
"Weight": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Conditions": [{"field": "path-pattern", "values": ["/*"]}],
|
"Conditions": [{"field": "path-pattern", "values": ["/*"]}],
|
||||||
"ListenerArn": {"Ref": "listener"},
|
"ListenerArn": {"Ref": "listener"},
|
||||||
"Priority": 2,
|
"Priority": 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"rule2": {
|
||||||
|
"Type": "AWS::ElasticLoadBalancingV2::ListenerRule",
|
||||||
|
"Properties": {
|
||||||
|
"Actions": [
|
||||||
|
{"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup2"}}
|
||||||
|
],
|
||||||
|
"Conditions": [{"field": "host-header", "values": ["example.com"]}],
|
||||||
|
"ListenerArn": {"Ref": "listener"},
|
||||||
|
"Priority": 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
"myvpc": {
|
"myvpc": {
|
||||||
"Type": "AWS::EC2::VPC",
|
"Type": "AWS::EC2::VPC",
|
||||||
"Properties": {"CidrBlock": "10.0.0.0/16"},
|
"Properties": {"CidrBlock": "10.0.0.0/16"},
|
||||||
@ -2395,15 +2420,39 @@ def test_stack_elbv2_resources_integration():
|
|||||||
listener_rule = elbv2_conn.describe_rules(ListenerArn=listeners[0]["ListenerArn"])[
|
listener_rule = elbv2_conn.describe_rules(ListenerArn=listeners[0]["ListenerArn"])[
|
||||||
"Rules"
|
"Rules"
|
||||||
]
|
]
|
||||||
len(listener_rule).should.equal(2)
|
len(listener_rule).should.equal(3)
|
||||||
listener_rule[0]["Priority"].should.equal("2")
|
listener_rule[0]["Priority"].should.equal("2")
|
||||||
listener_rule[0]["Actions"].should.equal(
|
listener_rule[0]["Actions"].should.equal(
|
||||||
[{"Type": "forward", "TargetGroupArn": target_groups[1]["TargetGroupArn"]}]
|
[
|
||||||
|
{
|
||||||
|
"Type": "forward",
|
||||||
|
"ForwardConfig": {
|
||||||
|
"TargetGroups": [
|
||||||
|
{
|
||||||
|
"TargetGroupArn": target_groups[1]["TargetGroupArn"],
|
||||||
|
"Weight": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TargetGroupArn": target_groups[0]["TargetGroupArn"],
|
||||||
|
"Weight": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
)
|
)
|
||||||
listener_rule[0]["Conditions"].should.equal(
|
listener_rule[0]["Conditions"].should.equal(
|
||||||
[{"Field": "path-pattern", "Values": ["/*"]}]
|
[{"Field": "path-pattern", "Values": ["/*"]}]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
listener_rule[1]["Priority"].should.equal("30")
|
||||||
|
listener_rule[1]["Actions"].should.equal(
|
||||||
|
[{"Type": "forward", "TargetGroupArn": target_groups[1]["TargetGroupArn"]}]
|
||||||
|
)
|
||||||
|
listener_rule[1]["Conditions"].should.equal(
|
||||||
|
[{"Field": "host-header", "Values": ["example.com"]}]
|
||||||
|
)
|
||||||
|
|
||||||
# test outputs
|
# test outputs
|
||||||
stacks = cfn_conn.describe_stacks(StackName="elb_stack")["Stacks"]
|
stacks = cfn_conn.describe_stacks(StackName="elb_stack")["Stacks"]
|
||||||
len(stacks).should.equal(1)
|
len(stacks).should.equal(1)
|
||||||
|
@ -1102,14 +1102,70 @@ def test_handle_listener_rules():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# add rule that uses forward_config
|
||||||
|
priority = 550
|
||||||
|
host = "aaa.example.com"
|
||||||
|
path_pattern = "barfoo"
|
||||||
|
rules = conn.create_rule(
|
||||||
|
ListenerArn=http_listener_arn,
|
||||||
|
Priority=priority,
|
||||||
|
Conditions=[
|
||||||
|
{"Field": "host-header", "Values": [host]},
|
||||||
|
{"Field": "path-pattern", "Values": [path_pattern]},
|
||||||
|
{
|
||||||
|
"Field": "path-pattern",
|
||||||
|
"PathPatternConfig": {"Values": [pathpatternconfig_pattern]},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Actions=[
|
||||||
|
{
|
||||||
|
"Type": "forward",
|
||||||
|
"ForwardConfig": {
|
||||||
|
"TargetGroups": [
|
||||||
|
{
|
||||||
|
"TargetGroupArn": target_group.get("TargetGroupArn"),
|
||||||
|
"Weight": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TargetGroupArn": target_group.get("TargetGroupArn"),
|
||||||
|
"Weight": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# test for PriorityInUse
|
||||||
|
with pytest.raises(ClientError):
|
||||||
|
conn.create_rule(
|
||||||
|
ListenerArn=http_listener_arn,
|
||||||
|
Priority=priority,
|
||||||
|
Conditions=[
|
||||||
|
{"Field": "host-header", "Values": [host]},
|
||||||
|
{"Field": "path-pattern", "Values": [path_pattern]},
|
||||||
|
{
|
||||||
|
"Field": "path-pattern",
|
||||||
|
"PathPatternConfig": {"Values": [pathpatternconfig_pattern]},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Actions=[
|
||||||
|
{
|
||||||
|
"TargetGroupArn": target_group.get("TargetGroupArn"),
|
||||||
|
"Type": "forward",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# test for describe listeners
|
# test for describe listeners
|
||||||
obtained_rules = conn.describe_rules(ListenerArn=http_listener_arn)
|
obtained_rules = conn.describe_rules(ListenerArn=http_listener_arn)
|
||||||
obtained_rules["Rules"].should.have.length_of(3)
|
obtained_rules["Rules"].should.have.length_of(4)
|
||||||
priorities = [rule["Priority"] for rule in obtained_rules["Rules"]]
|
priorities = [rule["Priority"] for rule in obtained_rules["Rules"]]
|
||||||
priorities.should.equal(["100", "500", "default"])
|
priorities.should.equal(["100", "500", "550", "default"])
|
||||||
|
|
||||||
first_rule = obtained_rules["Rules"][0]
|
first_rule = obtained_rules["Rules"][0]
|
||||||
second_rule = obtained_rules["Rules"][1]
|
second_rule = obtained_rules["Rules"][1]
|
||||||
|
third_rule = obtained_rules["Rules"][2]
|
||||||
obtained_rules = conn.describe_rules(RuleArns=[first_rule["RuleArn"]])
|
obtained_rules = conn.describe_rules(RuleArns=[first_rule["RuleArn"]])
|
||||||
obtained_rules["Rules"].should.equal([first_rule])
|
obtained_rules["Rules"].should.equal([first_rule])
|
||||||
|
|
||||||
@ -1173,11 +1229,53 @@ def test_handle_listener_rules():
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# modify forward_config rule partially rule
|
||||||
|
new_host_2 = "new.examplewebsite.com"
|
||||||
|
new_path_pattern_2 = "new_path_2"
|
||||||
|
new_pathpatternconfig_pattern_2 = "new_path_2"
|
||||||
|
modified_rule = conn.modify_rule(
|
||||||
|
RuleArn=third_rule["RuleArn"],
|
||||||
|
Conditions=[
|
||||||
|
{"Field": "host-header", "Values": [new_host_2]},
|
||||||
|
{"Field": "path-pattern", "Values": [new_path_pattern_2]},
|
||||||
|
{
|
||||||
|
"Field": "path-pattern",
|
||||||
|
"PathPatternConfig": {"Values": [new_pathpatternconfig_pattern_2]},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Actions=[
|
||||||
|
{"TargetGroupArn": target_group.get("TargetGroupArn"), "Type": "forward",}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
rules = conn.describe_rules(ListenerArn=http_listener_arn)
|
||||||
|
obtained_rule = rules["Rules"][2]
|
||||||
|
obtained_rule["Conditions"][0]["Values"][0].should.equal(new_host_2)
|
||||||
|
obtained_rule["Conditions"][1]["Values"][0].should.equal(new_path_pattern_2)
|
||||||
|
obtained_rule["Conditions"][2]["Values"][0].should.equal(
|
||||||
|
new_pathpatternconfig_pattern_2
|
||||||
|
)
|
||||||
|
obtained_rule["Actions"][0]["TargetGroupArn"].should.equal(
|
||||||
|
target_group.get("TargetGroupArn")
|
||||||
|
)
|
||||||
|
|
||||||
|
# modify priority
|
||||||
|
conn.set_rule_priorities(
|
||||||
|
RulePriorities=[
|
||||||
|
{
|
||||||
|
"RuleArn": third_rule["RuleArn"],
|
||||||
|
"Priority": int(third_rule["Priority"]) - 1,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(ClientError):
|
with pytest.raises(ClientError):
|
||||||
conn.set_rule_priorities(
|
conn.set_rule_priorities(
|
||||||
RulePriorities=[
|
RulePriorities=[
|
||||||
{"RuleArn": first_rule["RuleArn"], "Priority": 999},
|
{"RuleArn": first_rule["RuleArn"], "Priority": 999},
|
||||||
{"RuleArn": second_rule["RuleArn"], "Priority": 999},
|
{"RuleArn": second_rule["RuleArn"], "Priority": 999},
|
||||||
|
{"RuleArn": third_rule["RuleArn"], "Priority": 999},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1185,7 +1283,7 @@ def test_handle_listener_rules():
|
|||||||
arn = first_rule["RuleArn"]
|
arn = first_rule["RuleArn"]
|
||||||
conn.delete_rule(RuleArn=arn)
|
conn.delete_rule(RuleArn=arn)
|
||||||
rules = conn.describe_rules(ListenerArn=http_listener_arn)["Rules"]
|
rules = conn.describe_rules(ListenerArn=http_listener_arn)["Rules"]
|
||||||
len(rules).should.equal(2)
|
len(rules).should.equal(3)
|
||||||
|
|
||||||
# test for invalid action type
|
# test for invalid action type
|
||||||
safe_priority = 2
|
safe_priority = 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user