Merge pull request #1057 from kawasakitoshiya/feature/add_elbv2_listener_rules

Implement methods related to listener rules at ELBv2
This commit is contained in:
Jack Danger 2017-08-16 14:25:24 -07:00 committed by GitHub
commit b75f85690e
4 changed files with 770 additions and 0 deletions

View File

@ -101,3 +101,68 @@ 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
)
class InvalidDescribeRulesRequest(ELBClientError):
def __init__(self, msg):
super(InvalidDescribeRulesRequest, self).__init__(
"ValidationError", msg
)
class RuleNotFoundError(ELBClientError):
def __init__(self):
super(RuleNotFoundError, self).__init__(
"RuleNotFound",
"The specified rule does not exist.")
class DuplicatePriorityError(ELBClientError):
def __init__(self, invalid_value):
super(DuplicatePriorityError, self).__init__(
"ValidationError",
"Priority '%s' was provided multiple times" % invalid_value)

View File

@ -14,6 +14,14 @@ from .exceptions import (
SubnetNotFoundError,
TargetGroupNotFoundError,
TooManyTagsError,
PriorityInUseError,
InvalidConditionFieldError,
InvalidConditionValueError,
InvalidActionTypeError,
ActionTargetGroupNotFoundError,
InvalidDescribeRulesRequest,
RuleNotFoundError,
DuplicatePriorityError
)
@ -92,6 +100,33 @@ 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 +216,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 ListenerNotFoundError()
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 [rule]
def create_target_group(self, name, **kwargs):
for target_group in self.target_groups.values():
if target_group.name == name:
@ -233,6 +315,29 @@ class ELBv2Backend(BaseBackend):
return matched_balancers
def describe_rules(self, listener_arn, rule_arns):
if listener_arn is None and not rule_arns:
raise InvalidDescribeRulesRequest(
"You must specify either listener rule ARNs or a listener ARN"
)
if listener_arn is not None and rule_arns is not None:
raise InvalidDescribeRulesRequest(
'Listener rule ARNs and a listener ARN cannot be specified at the same time'
)
if listener_arn:
listener = self.describe_listeners(None, [listener_arn])[0]
return listener.rules
# search for rule arns
matched_rules = []
for load_balancer_arn in self.load_balancers:
listeners = self.load_balancers.get(load_balancer_arn).listeners.values()
for listener in listeners:
for rule in listener.rules:
if rule.arn in rule_arns:
matched_rules.append(rule)
return matched_rules
def describe_target_groups(self, load_balancer_arn, target_group_arns, names):
if load_balancer_arn:
if load_balancer_arn not in self.load_balancers:
@ -277,6 +382,18 @@ class ELBv2Backend(BaseBackend):
def delete_load_balancer(self, arn):
self.load_balancers.pop(arn, None)
def delete_rule(self, arn):
for load_balancer_arn in self.load_balancers:
listeners = self.load_balancers.get(load_balancer_arn).listeners.values()
for listener in listeners:
for rule in listener.rules:
if rule.arn == arn:
listener.rules.remove(rule)
return
# should raise RuleNotFound Error according to the AWS API doc
# however, boto3 does't raise error even if rule is not found
def delete_target_group(self, target_group_arn):
target_group = self.target_groups.pop(target_group_arn)
if target_group:
@ -290,6 +407,48 @@ class ELBv2Backend(BaseBackend):
return listener
raise ListenerNotFoundError()
def modify_rule(self, rule_arn, conditions, actions):
rules = self.describe_rules(listener_arn=None, rule_arns=[rule_arn])
if not rules:
raise RuleNotFoundError()
rule = rules[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 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'
# modify rule
rule.conditions = conditions
rule.actions = actions
return [rule]
def register_targets(self, target_group_arn, instances):
target_group = self.target_groups.get(target_group_arn)
if target_group is None:
@ -311,6 +470,39 @@ class ELBv2Backend(BaseBackend):
targets = target_group.targets.values()
return [target_group.health_for(target) for target in targets]
def set_rule_priorities(self, rule_priorities):
# validate
priorities = [rule_priority['priority'] for rule_priority in rule_priorities]
for priority in set(priorities):
if priorities.count(priority) > 1:
raise DuplicatePriorityError(priority)
# validate
for rule_priority in rule_priorities:
given_rule_arn = rule_priority['rule_arn']
priority = rule_priority['priority']
_given_rules = self.describe_rules(listener_arn=None, rule_arns=[given_rule_arn])
if not _given_rules:
raise RuleNotFoundError()
given_rule = _given_rules[0]
listeners = self.describe_listeners(None, [given_rule.listener_arn])
listener = listeners[0]
for rule_in_listener in listener.rules:
if rule_in_listener.priority == priority:
raise PriorityInUseError()
# modify
modified_rules = []
for rule_priority in rule_priorities:
given_rule_arn = rule_priority['rule_arn']
priority = rule_priority['priority']
_given_rules = self.describe_rules(listener_arn=None, rule_arns=[given_rule_arn])
if not _given_rules:
raise RuleNotFoundError()
given_rule = _given_rules[0]
given_rule.priority = priority
modified_rules.append(given_rule)
return modified_rules
elbv2_backends = {}
for region in ec2_backends.keys():

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')
@ -100,6 +124,26 @@ class ELBV2Response(BaseResponse):
template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
return template.render(load_balancers=load_balancers_resp, marker=next_marker)
def describe_rules(self):
listener_arn = self._get_param('ListenerArn')
rule_arns = self._get_multi_param('RuleArns.member') if any(k for k in list(self.querystring.keys()) if k.startswith('RuleArns.member')) else None
all_rules = self.elbv2_backend.describe_rules(listener_arn, rule_arns)
all_arns = [rule.arn for rule in all_rules]
page_size = self._get_int_param('PageSize', 50) # set 50 for temporary
marker = self._get_param('Marker')
if marker:
start = all_arns.index(marker) + 1
else:
start = 0
rules_resp = all_rules[start:start + page_size]
next_marker = None
if len(all_rules) > start + page_size:
next_marker = rules_resp[-1].arn
template = self.response_template(DESCRIBE_RULES_TEMPLATE)
return template.render(rules=rules_resp, marker=next_marker)
def describe_target_groups(self):
load_balancer_arn = self._get_param('LoadBalancerArn')
target_group_arns = self._get_multi_param('TargetGroupArns.member')
@ -133,6 +177,12 @@ class ELBV2Response(BaseResponse):
template = self.response_template(DELETE_LOAD_BALANCER_TEMPLATE)
return template.render()
def delete_rule(self):
arn = self._get_param('RuleArn')
self.elbv2_backend.delete_rule(arn)
template = self.response_template(DELETE_RULE_TEMPLATE)
return template.render()
def delete_target_group(self):
arn = self._get_param('TargetGroupArn')
self.elbv2_backend.delete_target_group(arn)
@ -145,6 +195,28 @@ class ELBV2Response(BaseResponse):
template = self.response_template(DELETE_LISTENER_TEMPLATE)
return template.render()
def modify_rule(self):
rule_arn = self._get_param('RuleArn')
_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)
actions = self._get_list_prefix('Actions.member')
rules = self.elbv2_backend.modify_rule(
rule_arn=rule_arn,
conditions=conditions,
actions=actions
)
template = self.response_template(MODIFY_RULE_TEMPLATE)
return template.render(rules=rules)
def modify_target_group_attributes(self):
target_group_arn = self._get_param('TargetGroupArn')
target_group = self.elbv2_backend.target_groups.get(target_group_arn)
@ -182,6 +254,14 @@ class ELBV2Response(BaseResponse):
template = self.response_template(DESCRIBE_TARGET_HEALTH_TEMPLATE)
return template.render(target_health_descriptions=target_health_descriptions)
def set_rule_priorities(self):
rule_priorities = self._get_list_prefix('RulePriorities.member')
for rule_priority in rule_priorities:
rule_priority['priority'] = int(rule_priority['priority'])
rules = self.elbv2_backend.set_rule_priorities(rule_priorities)
template = self.response_template(SET_RULE_PRIORITIES_TEMPLATE)
return template.render(rules=rules)
def add_tags(self):
resource_arns = self._get_multi_param('ResourceArns.member')
@ -321,6 +401,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>
@ -387,6 +504,13 @@ DELETE_LOAD_BALANCER_TEMPLATE = """<DeleteLoadBalancerResponse xmlns="http://ela
</ResponseMetadata>
</DeleteLoadBalancerResponse>"""
DELETE_RULE_TEMPLATE = """<DeleteRuleResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<DeleteRuleResult/>
<ResponseMetadata>
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
</ResponseMetadata>
</DeleteRuleResponse>"""
DELETE_TARGET_GROUP_TEMPLATE = """<DeleteTargetGroupResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<DeleteTargetGroupResult/>
<ResponseMetadata>
@ -442,6 +566,45 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
</ResponseMetadata>
</DescribeLoadBalancersResponse>"""
DESCRIBE_RULES_TEMPLATE = """<DescribeRulesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<DescribeRulesResult>
<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>
{% if marker %}
<NextMarker>{{ marker }}</NextMarker>
{% endif %}
</DescribeRulesResult>
<ResponseMetadata>
<RequestId>74926cf3-f3a3-11e5-b543-9f2c3fbb9bee</RequestId>
</ResponseMetadata>
</DescribeRulesResponse>"""
DESCRIBE_TARGET_GROUPS_TEMPLATE = """<DescribeTargetGroupsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<DescribeTargetGroupsResult>
@ -544,6 +707,43 @@ CONFIGURE_HEALTH_CHECK_TEMPLATE = """<ConfigureHealthCheckResponse xmlns="http:/
</ResponseMetadata>
</ConfigureHealthCheckResponse>"""
MODIFY_RULE_TEMPLATE = """<ModifyRuleResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<ModifyRuleResult>
<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>
</ModifyRuleResult>
<ResponseMetadata>
<RequestId>c5478c83-f397-11e5-bb98-57195a6eb84a</RequestId>
</ResponseMetadata>
</ModifyRuleResponse>"""
MODIFY_TARGET_GROUP_ATTRIBUTES_TEMPLATE = """<ModifyTargetGroupAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<ModifyTargetGroupAttributesResult>
<Attributes>
@ -703,3 +903,40 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
<RequestId>c534f810-f389-11e5-9192-3fff33344cfa</RequestId>
</ResponseMetadata>
</DescribeTargetHealthResponse>"""
SET_RULE_PRIORITIES_TEMPLATE = """<SetRulePrioritiesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<SetRulePrioritiesResult>
<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>
</SetRulePrioritiesResult>
<ResponseMetadata>
<RequestId>4d7a8036-f3a7-11e5-9c02-8fd20490d5a6</RequestId>
</ResponseMetadata>
</SetRulePrioritiesResponse>"""

View File

@ -518,3 +518,279 @@ def test_target_group_attributes():
attributes = {attr['Key']: attr['Value'] for attr in response['Attributes']}
attributes['stickiness.type'].should.equal('lb_cookie')
attributes['stickiness.enabled'].should.equal('true')
@mock_elbv2
@mock_ec2
def test_handle_listener_rules():
conn = boto3.client('elbv2', region_name='us-east-1')
ec2 = boto3.resource('ec2', region_name='us-east-1')
security_group = ec2.create_security_group(GroupName='a-security-group', Description='First One')
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
subnet1 = ec2.create_subnet(VpcId=vpc.id, CidrBlock='172.28.7.192/26', AvailabilityZone='us-east-1a')
subnet2 = ec2.create_subnet(VpcId=vpc.id, CidrBlock='172.28.7.192/26', AvailabilityZone='us-east-1b')
response = conn.create_load_balancer(
Name='my-lb',
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme='internal',
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
load_balancer_arn = response.get('LoadBalancers')[0].get('LoadBalancerArn')
response = conn.create_target_group(
Name='a-target',
Protocol='HTTP',
Port=8080,
VpcId=vpc.id,
HealthCheckProtocol='HTTP',
HealthCheckPort='8080',
HealthCheckPath='/',
HealthCheckIntervalSeconds=5,
HealthCheckTimeoutSeconds=5,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={'HttpCode': '200'})
target_group = response.get('TargetGroups')[0]
# Plain HTTP listener
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol='HTTP',
Port=80,
DefaultActions=[{'Type': 'forward', 'TargetGroupArn': target_group.get('TargetGroupArn')}])
listener = response.get('Listeners')[0]
listener.get('Port').should.equal(80)
listener.get('Protocol').should.equal('HTTP')
listener.get('DefaultActions').should.equal([{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'}])
http_listener_arn = listener.get('ListenerArn')
# create first rule
priority = 100
host = 'xxx.example.com'
path_pattern = 'foobar'
created_rule = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=priority,
Conditions=[{
'Field': 'host-header',
'Values': [ host ]
},
{
'Field': 'path-pattern',
'Values': [ path_pattern ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)['Rules'][0]
created_rule['Priority'].should.equal('100')
# check if rules is sorted by priority
priority = 50
host = 'yyy.example.com'
path_pattern = 'foobar'
rules = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=priority,
Conditions=[{
'Field': 'host-header',
'Values': [ host ]
},
{
'Field': 'path-pattern',
'Values': [ path_pattern ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)
# test for PriorityInUse
host2 = 'yyy.example.com'
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=priority,
Conditions=[{
'Field': 'host-header',
'Values': [ host ]
},
{
'Field': 'path-pattern',
'Values': [ path_pattern ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)
# test for describe listeners
obtained_rules = conn.describe_rules(ListenerArn=http_listener_arn)
len(obtained_rules['Rules']).should.equal(3)
priorities = [rule['Priority'] for rule in obtained_rules['Rules']]
priorities.should.equal(['50', '100', 'default'])
first_rule = obtained_rules['Rules'][0]
second_rule = obtained_rules['Rules'][1]
obtained_rules = conn.describe_rules(RuleArns=[first_rule['RuleArn']])
obtained_rules['Rules'].should.equal([first_rule])
# test for pagination
obtained_rules = conn.describe_rules(ListenerArn=http_listener_arn, PageSize=1)
len(obtained_rules['Rules']).should.equal(1)
obtained_rules.should.have.key('NextMarker')
next_marker = obtained_rules['NextMarker']
following_rules = conn.describe_rules(ListenerArn=http_listener_arn, PageSize=1, Marker=next_marker)
len(following_rules['Rules']).should.equal(1)
following_rules.should.have.key('NextMarker')
following_rules['Rules'][0]['RuleArn'].should_not.equal(obtained_rules['Rules'][0]['RuleArn'])
# test for invalid describe rule request
with assert_raises(ClientError):
conn.describe_rules()
with assert_raises(ClientError):
conn.describe_rules(RuleArns=[])
with assert_raises(ClientError):
conn.describe_rules(
ListenerArn=http_listener_arn,
RuleArns=[first_rule['RuleArn']]
)
# modify rule
new_host = 'new.example.com'
new_path_pattern = 'new_path'
modified_rule = conn.modify_rule(
RuleArn=first_rule['RuleArn'],
Conditions=[{
'Field': 'host-header',
'Values': [ new_host ]
},
{
'Field': 'path-pattern',
'Values': [ new_path_pattern ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)['Rules'][0]
rules = conn.describe_rules(ListenerArn=http_listener_arn)
modified_rule.should.equal(rules['Rules'][0])
# modify priority
conn.set_rule_priorities(
RulePriorities=[
{'RuleArn': first_rule['RuleArn'], 'Priority': int(first_rule['Priority']) - 1}
]
)
with assert_raises(ClientError):
conn.set_rule_priorities(
RulePriorities=[
{'RuleArn': first_rule['RuleArn'], 'Priority': 999},
{'RuleArn': second_rule['RuleArn'], 'Priority': 999}
]
)
# delete
arn = first_rule['RuleArn']
conn.delete_rule(RuleArn=arn)
# test for invalid action type
safe_priority = 2
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=safe_priority,
Conditions=[{
'Field': 'host-header',
'Values': [ host ]
},
{
'Field': 'path-pattern',
'Values': [ path_pattern ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward2'
}]
)
# test for invalid action type
safe_priority = 2
invalid_target_group_arn = target_group.get('TargetGroupArn') + 'x'
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=safe_priority,
Conditions=[{
'Field': 'host-header',
'Values': [ host ]
},
{
'Field': 'path-pattern',
'Values': [ path_pattern ]
}],
Actions=[{
'TargetGroupArn': invalid_target_group_arn,
'Type': 'forward'
}]
)
# test for invalid condition field_name
safe_priority = 2
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=safe_priority,
Conditions=[{
'Field': 'xxxxxxx',
'Values': [ host ]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)
# test for emptry condition value
safe_priority = 2
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=safe_priority,
Conditions=[{
'Field': 'host-header',
'Values': []
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)
# test for multiple condition value
safe_priority = 2
with assert_raises(ClientError):
r = conn.create_rule(
ListenerArn=http_listener_arn,
Priority=safe_priority,
Conditions=[{
'Field': 'host-header',
'Values': [host, host]
}],
Actions=[{
'TargetGroupArn': target_group.get('TargetGroupArn'),
'Type': 'forward'
}]
)