add create_rule to elbv2

This commit is contained in:
Toshiya Kawasaki 2017-08-16 21:09:14 +09:00
commit 05a2715f4b
4 changed files with 386 additions and 0 deletions

View file

@ -101,3 +101,44 @@ class EmptyListenersError(ELBClientError):
super(EmptyListenersError, self).__init__(
"ValidationError",
"Listeners cannot be empty")
class PriorityInUseError(ELBClientError):
def __init__(self):
super(PriorityInUseError, self).__init__(
"PriorityInUse",
"The specified priority is in use.")
class InvalidConditionFieldError(ELBClientError):
def __init__(self, invalid_name):
super(InvalidConditionFieldError, self).__init__(
"ValidationError",
"Condition field '%s' must be one of '[path-pattern, host-header]" % (invalid_name))
class InvalidConditionValueError(ELBClientError):
def __init__(self, msg):
super(InvalidConditionValueError, self).__init__(
"ValidationError", msg)
class InvalidActionTypeError(ELBClientError):
def __init__(self, invalid_name, index):
super(InvalidActionTypeError, self).__init__(
"ValidationError",
"1 validation error detected: Value '%s' at 'actions.%s.member.type' failed to satisfy constraint: Member must satisfy enum value set: [forward]" % (invalid_name, index)
)
class ActionTargetGroupNotFoundError(ELBClientError):
def __init__(self, arn):
super(ActionTargetGroupNotFoundError, self).__init__(
"TargetGroupNotFound",
"Target group '%s' not found" % arn
)

View file

@ -14,6 +14,11 @@ from .exceptions import (
SubnetNotFoundError,
TargetGroupNotFoundError,
TooManyTagsError,
PriorityInUseError,
InvalidConditionFieldError,
InvalidConditionValueError,
InvalidActionTypeError,
ActionTargetGroupNotFoundError,
)
@ -92,6 +97,34 @@ class FakeListener(BaseModel):
self.ssl_policy = ssl_policy
self.certificate = certificate
self.default_actions = default_actions
self._non_default_rules = []
self._default_rule = FakeRule(
listener_arn=self.arn,
conditions=[],
priority='default',
actions=default_actions,
is_default=True
)
@property
def rules(self):
return self._non_default_rules + [self._default_rule]
def register(self, rule):
self._non_default_rules.append(rule)
self._non_default_rules = sorted(self._non_default_rules, key=lambda x: x.priority)
class FakeRule(BaseModel):
def __init__(self, listener_arn, conditions, priority, actions, is_default):
self.listener_arn = listener_arn
self.arn = listener_arn.replace(':listener/', ':listener-rule/') + "/%s" % (id(self))
self.conditions = conditions
self.priority = priority # int or 'default'
self.actions = actions
self.is_default = is_default
class FakeBackend(BaseModel):
@ -181,6 +214,53 @@ class ELBv2Backend(BaseBackend):
self.load_balancers[arn] = new_load_balancer
return new_load_balancer
def create_rule(self, listener_arn, conditions, priority, actions):
listeners = self.describe_listeners(None, [listener_arn])
if not listeners:
raise ListenerNotFound()
listener = listeners[0]
# validate conditions
for condition in conditions:
field = condition['field']
if field not in ['path-pattern', 'host-header']:
raise InvalidConditionFieldError(field)
values = condition['values']
if len(values) == 0:
raise InvalidConditionValueError('A condition value must be specified')
if len(values) > 1:
raise InvalidConditionValueError(
"The '%s' field contains too many values; the limit is '1'" % field
)
# TODO: check pattern of value for 'host-header'
# TODO: check pattern of value for 'path-pattern'
# validate Priority
for rule in listener.rules:
if rule.priority == priority:
raise PriorityInUseError()
# validate Actions
target_group_arns = [target_group.arn for target_group in self.target_groups.values()]
for i, action in enumerate(actions):
index = i + 1
action_type = action['type']
if action_type not in ['forward']:
raise InvalidActionTypeError(action_type, index)
action_target_group_arn = action['target_group_arn']
if action_target_group_arn not in target_group_arns:
raise ActionTargetGroupNotFoundError(action_target_group_arn)
# TODO: check for error 'TooManyRegistrationsForTargetId'
# TODO: check for error 'TooManyRules'
# create rule
rule = FakeRule(listener.arn, conditions, priority, actions, is_default=False)
listener.register(rule)
return listener.rules
def create_target_group(self, name, **kwargs):
for target_group in self.target_groups.values():
if target_group.name == name:

View file

@ -28,6 +28,30 @@ class ELBV2Response(BaseResponse):
template = self.response_template(CREATE_LOAD_BALANCER_TEMPLATE)
return template.render(load_balancer=load_balancer)
def create_rule(self):
lister_arn = self._get_param('ListenerArn')
_conditions = self._get_list_prefix('Conditions.member')
conditions = []
for _condition in _conditions:
condition = {}
condition['field'] = _condition['field']
values = sorted(
[e for e in _condition.items() if e[0].startswith('values.member')],
key=lambda x: x[0]
)
condition['values'] = [e[1] for e in values]
conditions.append(condition)
priority = self._get_int_param('Priority')
actions = self._get_list_prefix('Actions.member')
rules = self.elbv2_backend.create_rule(
listener_arn=lister_arn,
conditions=conditions,
priority=priority,
actions=actions
)
template = self.response_template(CREATE_RULE_TEMPLATE)
return template.render(rules=rules)
def create_target_group(self):
name = self._get_param('Name')
vpc_id = self._get_param('VpcId')
@ -321,6 +345,43 @@ CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://ela
</ResponseMetadata>
</CreateLoadBalancerResponse>"""
CREATE_RULE_TEMPLATE = """<CreateRuleResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<CreateRuleResult>
<Rules>
{% for rule in rules %}
<member>
<IsDefault>{{ "true" if rule.is_default else "false" }}</IsDefault>
<Conditions>
{% for condition in rule.conditions %}
<member>
<Field>{{ condition["field"] }}</Field>
<Values>
{% for value in condition["values"] %}
<member>{{ value }}</member>
{% endfor %}
</Values>
</member>
{% endfor %}
</Conditions>
<Priority>{{ rule.priority }}</Priority>
<Actions>
{% for action in rule.actions %}
<member>
<Type>{{ action["type"] }}</Type>
<TargetGroupArn>{{ action["target_group_arn"] }}</TargetGroupArn>
</member>
{% endfor %}
</Actions>
<RuleArn>{{ rule.arn }}</RuleArn>
</member>
{% endfor %}
</Rules>
</CreateRuleResult>
<ResponseMetadata>
<RequestId>c5478c83-f397-11e5-bb98-57195a6eb84a</RequestId>
</ResponseMetadata>
</CreateRuleResponse>"""
CREATE_TARGET_GROUP_TEMPLATE = """<CreateTargetGroupResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<CreateTargetGroupResult>
<TargetGroups>