ELBv2 - Streamline parsing of Actions-parameter in create_rule (#4390)
This commit is contained in:
parent
03083ede42
commit
0d0354438e
@ -8,8 +8,6 @@ from collections import OrderedDict
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel
|
||||
from moto.core.utils import (
|
||||
camelcase_to_underscores,
|
||||
underscores_to_camelcase,
|
||||
iso_8601_datetime_with_milliseconds,
|
||||
get_random_hex,
|
||||
)
|
||||
@ -367,42 +365,42 @@ class FakeRule(BaseModel):
|
||||
class FakeAction(BaseModel):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.type = data.get("type")
|
||||
self.type = data.get("Type")
|
||||
|
||||
def to_xml(self):
|
||||
template = Template(
|
||||
"""<Type>{{ action.type }}</Type>
|
||||
{% if action.type == "forward" and "forward_config" in action.data %}
|
||||
{% if action.type == "forward" and "ForwardConfig" in action.data %}
|
||||
<ForwardConfig>
|
||||
<TargetGroups>
|
||||
{% for target_group in action.data["forward_config"]["target_groups"] %}
|
||||
{% for target_group in action.data["ForwardConfig"]["TargetGroups"] %}
|
||||
<member>
|
||||
<TargetGroupArn>{{ target_group["target_group_arn"] }}</TargetGroupArn>
|
||||
<Weight>{{ target_group["weight"] }}</Weight>
|
||||
<TargetGroupArn>{{ target_group["TargetGroupArn"] }}</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>
|
||||
{% if action.type == "forward" and "ForwardConfig" not in action.data %}
|
||||
<TargetGroupArn>{{ action.data["TargetGroupArn"] }}</TargetGroupArn>
|
||||
{% elif action.type == "redirect" %}
|
||||
<RedirectConfig>
|
||||
<Protocol>{{ action.data["redirect_config._protocol"] }}</Protocol>
|
||||
<Port>{{ action.data["redirect_config._port"] }}</Port>
|
||||
<StatusCode>{{ action.data["redirect_config._status_code"] }}</StatusCode>
|
||||
<Protocol>{{ action.data["RedirectConfig"]["Protocol"] }}</Protocol>
|
||||
<Port>{{ action.data["RedirectConfig"]["Port"] }}</Port>
|
||||
<StatusCode>{{ action.data["RedirectConfig"]["StatusCode"] }}</StatusCode>
|
||||
</RedirectConfig>
|
||||
{% elif action.type == "authenticate-cognito" %}
|
||||
<AuthenticateCognitoConfig>
|
||||
<UserPoolArn>{{ action.data["authenticate_cognito_config._user_pool_arn"] }}</UserPoolArn>
|
||||
<UserPoolClientId>{{ action.data["authenticate_cognito_config._user_pool_client_id"] }}</UserPoolClientId>
|
||||
<UserPoolDomain>{{ action.data["authenticate_cognito_config._user_pool_domain"] }}</UserPoolDomain>
|
||||
<UserPoolArn>{{ action.data["AuthenticateCognitoConfig"]["UserPoolArn"] }}</UserPoolArn>
|
||||
<UserPoolClientId>{{ action.data["AuthenticateCognitoConfig"]["UserPoolClientId"] }}</UserPoolClientId>
|
||||
<UserPoolDomain>{{ action.data["AuthenticateCognitoConfig"]["UserPoolDomain"] }}</UserPoolDomain>
|
||||
</AuthenticateCognitoConfig>
|
||||
{% elif action.type == "fixed-response" %}
|
||||
<FixedResponseConfig>
|
||||
<ContentType>{{ action.data["fixed_response_config._content_type"] }}</ContentType>
|
||||
<MessageBody>{{ action.data["fixed_response_config._message_body"] }}</MessageBody>
|
||||
<StatusCode>{{ action.data["fixed_response_config._status_code"] }}</StatusCode>
|
||||
<ContentType>{{ action.data["FixedResponseConfig"]["ContentType"] }}</ContentType>
|
||||
<MessageBody>{{ action.data["FixedResponseConfig"]["MessageBody"] }}</MessageBody>
|
||||
<StatusCode>{{ action.data["FixedResponseConfig"]["StatusCode"] }}</StatusCode>
|
||||
</FixedResponseConfig>
|
||||
{% endif %}
|
||||
"""
|
||||
@ -634,45 +632,13 @@ class ELBv2Backend(BaseBackend):
|
||||
default_actions = []
|
||||
for i, action in enumerate(properties["Actions"]):
|
||||
action_type = action["Type"]
|
||||
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(
|
||||
{"type": action_type, "target_group_arn": action["TargetGroupArn"]}
|
||||
)
|
||||
elif action_type in [
|
||||
if action_type in [
|
||||
"redirect",
|
||||
"authenticate-cognito",
|
||||
"fixed-response",
|
||||
"forward",
|
||||
]:
|
||||
redirect_action = {"type": action_type}
|
||||
key = (
|
||||
underscores_to_camelcase(action_type.capitalize().replace("-", "_"))
|
||||
+ "Config"
|
||||
)
|
||||
for redirect_config_key, redirect_config_value in action[key].items():
|
||||
# need to match the output of _get_list_prefix
|
||||
redirect_action[
|
||||
camelcase_to_underscores(key)
|
||||
+ "._"
|
||||
+ camelcase_to_underscores(redirect_config_key)
|
||||
] = redirect_config_value
|
||||
default_actions.append(redirect_action)
|
||||
default_actions.append(action)
|
||||
else:
|
||||
raise InvalidActionTypeError(action_type, i + 1)
|
||||
return default_actions
|
||||
@ -853,8 +819,8 @@ class ELBv2Backend(BaseBackend):
|
||||
for i, action in enumerate(actions):
|
||||
index = i + 1
|
||||
action_type = action.type
|
||||
if action_type == "forward" and "target_group_arn" in action.data:
|
||||
action_target_group_arn = action.data["target_group_arn"]
|
||||
if action_type == "forward" and "TargetGroupArn" in action.data:
|
||||
action_target_group_arn = action.data["TargetGroupArn"]
|
||||
if action_target_group_arn not in target_group_arns:
|
||||
raise ActionTargetGroupNotFoundError(action_target_group_arn)
|
||||
elif action_type == "fixed-response":
|
||||
@ -862,20 +828,13 @@ class ELBv2Backend(BaseBackend):
|
||||
elif action_type in ["redirect", "authenticate-cognito"]:
|
||||
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()
|
||||
):
|
||||
elif action_type == "forward" and "ForwardConfig" in action.data.keys():
|
||||
pass
|
||||
else:
|
||||
raise InvalidActionTypeError(action_type, index)
|
||||
|
||||
def _validate_fixed_response_action(self, action, i, index):
|
||||
status_code = action.data.get("fixed_response_config._status_code")
|
||||
status_code = action.data.get("FixedResponseConfig", {}).get("StatusCode")
|
||||
if status_code is None:
|
||||
raise ParamValidationError(
|
||||
report='Missing required parameter in Actions[%s].FixedResponseConfig: "StatusCode"'
|
||||
@ -889,7 +848,7 @@ Member must satisfy regular expression pattern: {}".format(
|
||||
status_code, index, expression
|
||||
)
|
||||
)
|
||||
content_type = action.data["fixed_response_config._content_type"]
|
||||
content_type = action.data["FixedResponseConfig"].get("ContentType")
|
||||
if content_type and content_type not in [
|
||||
"text/plain",
|
||||
"text/css",
|
||||
@ -977,31 +936,20 @@ Member must satisfy regular expression pattern: {}".format(
|
||||
def convert_and_validate_properties(self, properties):
|
||||
|
||||
# transform default actions to confirm with the rest of the code and XML templates
|
||||
# Caller: CF create/update for type "AWS::ElasticLoadBalancingV2::Listener"
|
||||
default_actions = []
|
||||
for i, action in enumerate(properties["DefaultActions"]):
|
||||
action_type = action["Type"]
|
||||
if action_type == "forward":
|
||||
default_actions.append(
|
||||
{"type": action_type, "target_group_arn": action["TargetGroupArn"]}
|
||||
{"Type": action_type, "TargetGroupArn": action["TargetGroupArn"]}
|
||||
)
|
||||
elif action_type in [
|
||||
"redirect",
|
||||
"authenticate-cognito",
|
||||
"fixed-response",
|
||||
]:
|
||||
redirect_action = {"type": action_type}
|
||||
key = (
|
||||
underscores_to_camelcase(action_type.capitalize().replace("-", "_"))
|
||||
+ "Config"
|
||||
)
|
||||
for redirect_config_key, redirect_config_value in action[key].items():
|
||||
# need to match the output of _get_list_prefix
|
||||
redirect_action[
|
||||
camelcase_to_underscores(key)
|
||||
+ "._"
|
||||
+ camelcase_to_underscores(redirect_config_key)
|
||||
] = redirect_config_value
|
||||
default_actions.append(redirect_action)
|
||||
default_actions.append(action)
|
||||
else:
|
||||
raise InvalidActionTypeError(action_type, i + 1)
|
||||
return default_actions
|
||||
@ -1040,7 +988,7 @@ Member must satisfy regular expression pattern: {}".format(
|
||||
balancer.listeners[listener.arn] = listener
|
||||
for action in default_actions:
|
||||
if action.type == "forward":
|
||||
target_group = self.target_groups[action.data["target_group_arn"]]
|
||||
target_group = self.target_groups[action.data["TargetGroupArn"]]
|
||||
target_group.load_balancer_arns.append(load_balancer_arn)
|
||||
|
||||
return listener
|
||||
@ -1473,7 +1421,7 @@ Member must satisfy regular expression pattern: {}".format(
|
||||
for listener in load_balancer.listeners.values():
|
||||
for rule in listener.rules.values():
|
||||
for action in rule.actions:
|
||||
if action.data.get("target_group_arn") == target_group_arn:
|
||||
if action.data.get("TargetGroupArn") == target_group_arn:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -165,12 +165,11 @@ class ELBV2Response(BaseResponse):
|
||||
@amzn_request_id
|
||||
def create_rule(self):
|
||||
params = self._get_params()
|
||||
actions = self._get_list_prefix("Actions.member")
|
||||
rules = self.elbv2_backend.create_rule(
|
||||
listener_arn=params["ListenerArn"],
|
||||
conditions=params["Conditions"],
|
||||
priority=params["Priority"],
|
||||
actions=actions,
|
||||
actions=params["Actions"],
|
||||
)
|
||||
template = self.response_template(CREATE_RULE_TEMPLATE)
|
||||
return template.render(rules=rules)
|
||||
@ -214,6 +213,7 @@ class ELBV2Response(BaseResponse):
|
||||
|
||||
@amzn_request_id
|
||||
def create_listener(self):
|
||||
params = self._get_params()
|
||||
load_balancer_arn = self._get_param("LoadBalancerArn")
|
||||
protocol = self._get_param("Protocol")
|
||||
port = self._get_param("Port")
|
||||
@ -223,7 +223,7 @@ class ELBV2Response(BaseResponse):
|
||||
certificate = certificates[0].get("certificate_arn")
|
||||
else:
|
||||
certificate = None
|
||||
default_actions = self._get_list_prefix("DefaultActions.member")
|
||||
default_actions = params.get("DefaultActions", [])
|
||||
|
||||
listener = self.elbv2_backend.create_listener(
|
||||
load_balancer_arn=load_balancer_arn,
|
||||
@ -357,7 +357,7 @@ class ELBV2Response(BaseResponse):
|
||||
rule_arn = self._get_param("RuleArn")
|
||||
params = self._get_params()
|
||||
conditions = params["Conditions"]
|
||||
actions = self._get_list_prefix("Actions.member")
|
||||
actions = params.get("Actions", [])
|
||||
rules = self.elbv2_backend.modify_rule(
|
||||
rule_arn=rule_arn, conditions=conditions, actions=actions
|
||||
)
|
||||
|
@ -434,6 +434,83 @@ def test_create_target_group_without_non_required_parameters():
|
||||
target_group.should_not.be.none
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_create_rule_forward_config_as_second_arg():
|
||||
# https://github.com/spulec/moto/issues/4123
|
||||
# Necessary because there was some convoluted way of parsing arguments
|
||||
# Actions with type=forward had to be the first action specified
|
||||
response, vpc, security_group, subnet1, subnet2, elbv2 = create_load_balancer()
|
||||
|
||||
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
|
||||
|
||||
response = elbv2.create_listener(
|
||||
LoadBalancerArn=load_balancer_arn, Protocol="HTTP", Port=80, DefaultActions=[],
|
||||
)
|
||||
http_listener_arn = response.get("Listeners")[0]["ListenerArn"]
|
||||
|
||||
priority = 100
|
||||
|
||||
response = elbv2.create_target_group(
|
||||
Name="a-target",
|
||||
Protocol="HTTP",
|
||||
Port=8080,
|
||||
VpcId=vpc.id,
|
||||
HealthCheckProtocol="HTTP",
|
||||
HealthCheckPort="8080",
|
||||
HealthCheckPath="/",
|
||||
Matcher={"HttpCode": "200"},
|
||||
)
|
||||
target_group = response.get("TargetGroups")[0]
|
||||
|
||||
# No targets registered yet
|
||||
target_group_arn = target_group.get("TargetGroupArn")
|
||||
elbv2.create_rule(
|
||||
ListenerArn=http_listener_arn,
|
||||
Conditions=[
|
||||
{"Field": "path-pattern", "PathPatternConfig": {"Values": [f"/sth*",]},},
|
||||
],
|
||||
Priority=priority,
|
||||
Actions=[
|
||||
{
|
||||
"Type": "authenticate-cognito",
|
||||
"Order": 1,
|
||||
"AuthenticateCognitoConfig": {
|
||||
"UserPoolArn": "?1",
|
||||
"UserPoolClientId": "?2",
|
||||
"UserPoolDomain": "?2",
|
||||
"SessionCookieName": "AWSELBAuthSessionCookie",
|
||||
"Scope": "openid",
|
||||
"SessionTimeout": 604800,
|
||||
"OnUnauthenticatedRequest": "authenticate",
|
||||
},
|
||||
},
|
||||
{
|
||||
"Type": "forward",
|
||||
"Order": 2,
|
||||
"ForwardConfig": {
|
||||
"TargetGroups": [
|
||||
{"TargetGroupArn": target_group_arn, "Weight": 1},
|
||||
],
|
||||
"TargetGroupStickinessConfig": {"Enabled": False,},
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
all_rules = elbv2.describe_rules(ListenerArn=http_listener_arn)["Rules"]
|
||||
our_rule = all_rules[0]
|
||||
actions = our_rule["Actions"]
|
||||
forward_action = [a for a in actions if "ForwardConfig" in a.keys()][0]
|
||||
forward_action.should.equal(
|
||||
{
|
||||
"ForwardConfig": {
|
||||
"TargetGroups": [{"TargetGroupArn": target_group_arn, "Weight": 1}]
|
||||
},
|
||||
"Type": "forward",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@mock_elbv2
|
||||
@mock_ec2
|
||||
def test_create_invalid_target_group():
|
||||
|
@ -1,5 +1,6 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_elbv2, mock_ec2, mock_cloudformation
|
||||
from moto.core import ACCOUNT_ID
|
||||
|
Loading…
Reference in New Issue
Block a user