ELB/ELBv2 improvements (#4956)

This commit is contained in:
Bert Blommers 2022-03-21 19:55:19 -01:00 committed by GitHub
parent 2d5ae58120
commit 47ce689cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1779 additions and 573 deletions

View File

@ -224,7 +224,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: [ 3.8 ] python-version: [ 3.8 ]
part: ["aa", "ab", "ac", "ad", "ae"] part: ["aa", "ab", "ac", "ad", "ae", "af"]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -259,7 +259,7 @@ jobs:
run: | run: |
cd moto-terraform-tests cd moto-terraform-tests
bin/list-tests -i ../tests/terraform-tests.success.txt -e ../tests/terraform-tests.failures.txt > tftestlist.txt bin/list-tests -i ../tests/terraform-tests.success.txt -e ../tests/terraform-tests.failures.txt > tftestlist.txt
split -n l/5 tftestlist.txt tf-split- split -n l/6 tftestlist.txt tf-split-
cd .. cd ..
- name: Run Terraform Tests - name: Run Terraform Tests
run: | run: |

View File

@ -2274,11 +2274,11 @@
## elb ## elb
<details> <details>
<summary>41% implemented</summary> <summary>62% implemented</summary>
- [ ] add_tags - [ ] add_tags
- [X] apply_security_groups_to_load_balancer - [X] apply_security_groups_to_load_balancer
- [ ] attach_load_balancer_to_subnets - [X] attach_load_balancer_to_subnets
- [X] configure_health_check - [X] configure_health_check
- [X] create_app_cookie_stickiness_policy - [X] create_app_cookie_stickiness_policy
- [X] create_lb_cookie_stickiness_policy - [X] create_lb_cookie_stickiness_policy
@ -2287,18 +2287,18 @@
- [ ] create_load_balancer_policy - [ ] create_load_balancer_policy
- [X] delete_load_balancer - [X] delete_load_balancer
- [X] delete_load_balancer_listeners - [X] delete_load_balancer_listeners
- [ ] delete_load_balancer_policy - [X] delete_load_balancer_policy
- [ ] deregister_instances_from_load_balancer - [ ] deregister_instances_from_load_balancer
- [ ] describe_account_limits - [ ] describe_account_limits
- [ ] describe_instance_health - [ ] describe_instance_health
- [ ] describe_load_balancer_attributes - [ ] describe_load_balancer_attributes
- [ ] describe_load_balancer_policies - [X] describe_load_balancer_policies
- [ ] describe_load_balancer_policy_types - [ ] describe_load_balancer_policy_types
- [X] describe_load_balancers - [X] describe_load_balancers
- [ ] describe_tags - [ ] describe_tags
- [ ] detach_load_balancer_from_subnets - [X] detach_load_balancer_from_subnets
- [ ] disable_availability_zones_for_load_balancer - [X] disable_availability_zones_for_load_balancer
- [ ] enable_availability_zones_for_load_balancer - [X] enable_availability_zones_for_load_balancer
- [X] modify_load_balancer_attributes - [X] modify_load_balancer_attributes
- [ ] register_instances_with_load_balancer - [ ] register_instances_with_load_balancer
- [ ] remove_tags - [ ] remove_tags
@ -2309,9 +2309,9 @@
## elbv2 ## elbv2
<details> <details>
<summary>73% implemented</summary> <summary>82% implemented</summary>
- [ ] add_listener_certificates - [X] add_listener_certificates
- [ ] add_tags - [ ] add_tags
- [X] create_listener - [X] create_listener
- [X] create_load_balancer - [X] create_load_balancer
@ -2323,7 +2323,7 @@
- [X] delete_target_group - [X] delete_target_group
- [X] deregister_targets - [X] deregister_targets
- [ ] describe_account_limits - [ ] describe_account_limits
- [ ] describe_listener_certificates - [X] describe_listener_certificates
- [X] describe_listeners - [X] describe_listeners
- [X] describe_load_balancer_attributes - [X] describe_load_balancer_attributes
- [X] describe_load_balancers - [X] describe_load_balancers
@ -2339,7 +2339,7 @@
- [X] modify_target_group - [X] modify_target_group
- [X] modify_target_group_attributes - [X] modify_target_group_attributes
- [X] register_targets - [X] register_targets
- [ ] remove_listener_certificates - [X] remove_listener_certificates
- [ ] remove_tags - [ ] remove_tags
- [X] set_ip_address_type - [X] set_ip_address_type
- [X] set_rule_priorities - [X] set_rule_priorities

View File

@ -27,7 +27,7 @@ elb
- [ ] add_tags - [ ] add_tags
- [X] apply_security_groups_to_load_balancer - [X] apply_security_groups_to_load_balancer
- [ ] attach_load_balancer_to_subnets - [X] attach_load_balancer_to_subnets
- [X] configure_health_check - [X] configure_health_check
- [X] create_app_cookie_stickiness_policy - [X] create_app_cookie_stickiness_policy
- [X] create_lb_cookie_stickiness_policy - [X] create_lb_cookie_stickiness_policy
@ -36,18 +36,18 @@ elb
- [ ] create_load_balancer_policy - [ ] create_load_balancer_policy
- [X] delete_load_balancer - [X] delete_load_balancer
- [X] delete_load_balancer_listeners - [X] delete_load_balancer_listeners
- [ ] delete_load_balancer_policy - [X] delete_load_balancer_policy
- [ ] deregister_instances_from_load_balancer - [ ] deregister_instances_from_load_balancer
- [ ] describe_account_limits - [ ] describe_account_limits
- [ ] describe_instance_health - [ ] describe_instance_health
- [ ] describe_load_balancer_attributes - [ ] describe_load_balancer_attributes
- [ ] describe_load_balancer_policies - [X] describe_load_balancer_policies
- [ ] describe_load_balancer_policy_types - [ ] describe_load_balancer_policy_types
- [X] describe_load_balancers - [X] describe_load_balancers
- [ ] describe_tags - [ ] describe_tags
- [ ] detach_load_balancer_from_subnets - [X] detach_load_balancer_from_subnets
- [ ] disable_availability_zones_for_load_balancer - [X] disable_availability_zones_for_load_balancer
- [ ] enable_availability_zones_for_load_balancer - [X] enable_availability_zones_for_load_balancer
- [X] modify_load_balancer_attributes - [X] modify_load_balancer_attributes
- [ ] register_instances_with_load_balancer - [ ] register_instances_with_load_balancer
- [ ] remove_tags - [ ] remove_tags

View File

@ -25,7 +25,7 @@ elbv2
|start-h3| Implemented features for this service |end-h3| |start-h3| Implemented features for this service |end-h3|
- [ ] add_listener_certificates - [X] add_listener_certificates
- [ ] add_tags - [ ] add_tags
- [X] create_listener - [X] create_listener
- [X] create_load_balancer - [X] create_load_balancer
@ -37,7 +37,7 @@ elbv2
- [X] delete_target_group - [X] delete_target_group
- [X] deregister_targets - [X] deregister_targets
- [ ] describe_account_limits - [ ] describe_account_limits
- [ ] describe_listener_certificates - [X] describe_listener_certificates
- [X] describe_listeners - [X] describe_listeners
- [X] describe_load_balancer_attributes - [X] describe_load_balancer_attributes
- [X] describe_load_balancers - [X] describe_load_balancers
@ -53,7 +53,7 @@ elbv2
- [X] modify_target_group - [X] modify_target_group
- [X] modify_target_group_attributes - [X] modify_target_group_attributes
- [X] register_targets - [X] register_targets
- [ ] remove_listener_certificates - [X] remove_listener_certificates
- [ ] remove_tags - [ ] remove_tags
- [X] set_ip_address_type - [X] set_ip_address_type
- [X] set_rule_priorities - [X] set_rule_priorities

View File

@ -1031,13 +1031,8 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
subnet = self.ec2_backend.get_subnet(nic["SubnetId"]) subnet = self.ec2_backend.get_subnet(nic["SubnetId"])
else: else:
# Get default Subnet # Get default Subnet
subnet = [ zone = self._placement.zone
subnet subnet = self.ec2_backend.get_default_subnet(availability_zone=zone)
for subnet in self.ec2_backend.get_all_subnets(
filters={"availabilityZone": self._placement.zone}
)
if subnet.default_for_az
][0]
group_id = nic.get("SecurityGroupId") group_id = nic.get("SecurityGroupId")
group_ids = [group_id] if group_id else [] group_ids = [group_id] if group_id else []
@ -4702,6 +4697,15 @@ class SubnetBackend(object):
return subnets[subnet_id] return subnets[subnet_id]
raise InvalidSubnetIdError(subnet_id) raise InvalidSubnetIdError(subnet_id)
def get_default_subnet(self, availability_zone):
return [
subnet
for subnet in self.get_all_subnets(
filters={"availabilityZone": availability_zone}
)
if subnet.default_for_az
][0]
def create_subnet( def create_subnet(
self, self,
vpc_id, vpc_id,

View File

@ -4,6 +4,9 @@ from moto.core.exceptions import RESTError
class ELBClientError(RESTError): class ELBClientError(RESTError):
code = 400 code = 400
def __init__(self, error_type, message):
super().__init__(error_type, message, template="wrapped_single_error")
class DuplicateTagKeysError(ELBClientError): class DuplicateTagKeysError(ELBClientError):
def __init__(self, cidr): def __init__(self, cidr):
@ -27,6 +30,13 @@ class LoadBalancerNotFoundError(ELBClientError):
) )
class PolicyNotFoundError(ELBClientError):
def __init__(self):
super().__init__(
"PolicyNotFound", "There is no policy with name . for load balancer ."
)
class TooManyTagsError(ELBClientError): class TooManyTagsError(ELBClientError):
def __init__(self): def __init__(self):
super().__init__( super().__init__(

View File

@ -2,11 +2,11 @@ import datetime
import pytz import pytz
from moto.packages.boto.ec2.elb.policies import Policies, OtherPolicy
from collections import OrderedDict from collections import OrderedDict
from moto.core import BaseBackend, BaseModel, CloudFormationModel from moto.core import BaseBackend, BaseModel, CloudFormationModel
from moto.core.utils import BackendDict from moto.core.utils import BackendDict
from moto.ec2.models import ec2_backends from moto.ec2.models import ec2_backends
from uuid import uuid4
from .exceptions import ( from .exceptions import (
BadHealthCheckDefinition, BadHealthCheckDefinition,
DuplicateLoadBalancerName, DuplicateLoadBalancerName,
@ -14,9 +14,11 @@ from .exceptions import (
EmptyListenersError, EmptyListenersError,
InvalidSecurityGroupError, InvalidSecurityGroupError,
LoadBalancerNotFoundError, LoadBalancerNotFoundError,
PolicyNotFoundError,
TooManyTagsError, TooManyTagsError,
CertificateNotFoundException, CertificateNotFoundException,
) )
from .policies import AppCookieStickinessPolicy, LbCookieStickinessPolicy, OtherPolicy
class FakeHealthCheck(BaseModel): class FakeHealthCheck(BaseModel):
@ -84,13 +86,10 @@ class FakeLoadBalancer(CloudFormationModel):
self.created_time = datetime.datetime.now(pytz.utc) self.created_time = datetime.datetime.now(pytz.utc)
self.scheme = scheme or "internet-facing" self.scheme = scheme or "internet-facing"
self.attributes = FakeLoadBalancer.get_default_attributes() self.attributes = FakeLoadBalancer.get_default_attributes()
self.policies = Policies() self.policies = []
self.policies.other_policies = []
self.policies.app_cookie_stickiness_policies = []
self.policies.lb_cookie_stickiness_policies = []
self.security_groups = security_groups or [] self.security_groups = security_groups or []
self.subnets = subnets or [] self.subnets = subnets or []
self.vpc_id = vpc_id or "vpc-56e10e3d" self.vpc_id = vpc_id
self.tags = {} self.tags = {}
self.dns_name = "%s.us-east-1.elb.amazonaws.com" % (name) self.dns_name = "%s.us-east-1.elb.amazonaws.com" % (name)
@ -105,7 +104,10 @@ class FakeLoadBalancer(CloudFormationModel):
"ssl_certificate_id", port.get("SSLCertificateId") "ssl_certificate_id", port.get("SSLCertificateId")
), ),
) )
if listener.ssl_certificate_id: if (
listener.ssl_certificate_id
and not listener.ssl_certificate_id.startswith("arn:aws:iam:")
):
elb_backend._register_certificate( elb_backend._register_certificate(
listener.ssl_certificate_id, self.dns_name listener.ssl_certificate_id, self.dns_name
) )
@ -290,12 +292,24 @@ class ELBBackend(BaseBackend):
if subnets: if subnets:
subnet = ec2_backend.get_subnet(subnets[0]) subnet = ec2_backend.get_subnet(subnets[0])
vpc_id = subnet.vpc_id vpc_id = subnet.vpc_id
elif zones:
subnets = [
ec2_backend.get_default_subnet(availability_zone=zone).id
for zone in zones
]
subnet = ec2_backend.get_subnet(subnets[0])
vpc_id = subnet.vpc_id
if name in self.load_balancers: if name in self.load_balancers:
raise DuplicateLoadBalancerName(name) raise DuplicateLoadBalancerName(name)
if not ports: if not ports:
raise EmptyListenersError() raise EmptyListenersError()
if not security_groups: if not security_groups:
security_groups = [] sg = ec2_backend.create_security_group(
name=f"default_elb_{uuid4()}",
description="ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs",
vpc_id=vpc_id,
)
security_groups = [sg.id]
for security_group in security_groups: for security_group in security_groups:
if ec2_backend.get_security_group_from_id(security_group) is None: if ec2_backend.get_security_group_from_id(security_group) is None:
raise InvalidSecurityGroupError() raise InvalidSecurityGroupError()
@ -322,7 +336,7 @@ class ELBBackend(BaseBackend):
ssl_certificate_id = port.get("ssl_certificate_id") ssl_certificate_id = port.get("ssl_certificate_id")
for listener in balancer.listeners: for listener in balancer.listeners:
if lb_port == listener.load_balancer_port: if lb_port == listener.load_balancer_port:
if protocol != listener.protocol: if protocol.lower() != listener.protocol.lower():
raise DuplicateListenerError(name, lb_port) raise DuplicateListenerError(name, lb_port)
if instance_port != listener.instance_port: if instance_port != listener.instance_port:
raise DuplicateListenerError(name, lb_port) raise DuplicateListenerError(name, lb_port)
@ -330,7 +344,9 @@ class ELBBackend(BaseBackend):
raise DuplicateListenerError(name, lb_port) raise DuplicateListenerError(name, lb_port)
break break
else: else:
if ssl_certificate_id: if ssl_certificate_id and not ssl_certificate_id.startswith(
"arn:aws:iam::"
):
self._register_certificate( self._register_certificate(
ssl_certificate_id, balancer.dns_name ssl_certificate_id, balancer.dns_name
) )
@ -355,6 +371,15 @@ class ELBBackend(BaseBackend):
else: else:
return balancers return balancers
def describe_load_balancer_policies(self, lb_name, policy_names):
lb = self.describe_load_balancers([lb_name])[0]
policies = lb.policies
if policy_names:
policies = [p for p in policies if p.policy_name in policy_names]
if len(policy_names) != len(policies):
raise PolicyNotFoundError()
return policies
def delete_load_balancer_listeners(self, name, ports): def delete_load_balancer_listeners(self, name, ports):
balancer = self.load_balancers.get(name, None) balancer = self.load_balancers.get(name, None)
listeners = [] listeners = []
@ -371,6 +396,10 @@ class ELBBackend(BaseBackend):
def delete_load_balancer(self, load_balancer_name): def delete_load_balancer(self, load_balancer_name):
self.load_balancers.pop(load_balancer_name, None) self.load_balancers.pop(load_balancer_name, None)
def delete_load_balancer_policy(self, lb_name, policy_name):
lb = self.get_load_balancer(lb_name)
lb.policies = [p for p in lb.policies if p.policy_name != policy_name]
def get_load_balancer(self, load_balancer_name): def get_load_balancer(self, load_balancer_name):
return self.load_balancers.get(load_balancer_name) return self.load_balancers.get(load_balancer_name)
@ -471,23 +500,31 @@ class ELBBackend(BaseBackend):
if access_log: if access_log:
load_balancer.attributes["access_log"] = access_log load_balancer.attributes["access_log"] = access_log
def create_lb_other_policy(self, load_balancer_name, other_policy): def create_lb_other_policy(
self, load_balancer_name, policy_name, policy_type_name, policy_attrs
):
load_balancer = self.get_load_balancer(load_balancer_name) load_balancer = self.get_load_balancer(load_balancer_name)
if other_policy.policy_name not in [ if policy_name not in [p.policy_name for p in load_balancer.policies]:
p.policy_name for p in load_balancer.policies.other_policies load_balancer.policies.append(
]: OtherPolicy(policy_name, policy_type_name, policy_attrs)
load_balancer.policies.other_policies.append(other_policy) )
return load_balancer return load_balancer
def create_app_cookie_stickiness_policy(self, load_balancer_name, policy): def create_app_cookie_stickiness_policy(
self, load_balancer_name, policy_name, cookie_name
):
load_balancer = self.get_load_balancer(load_balancer_name) load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.policies.app_cookie_stickiness_policies.append(policy) policy = AppCookieStickinessPolicy(policy_name, cookie_name)
load_balancer.policies.append(policy)
return load_balancer return load_balancer
def create_lb_cookie_stickiness_policy(self, load_balancer_name, policy): def create_lb_cookie_stickiness_policy(
self, load_balancer_name, policy_name, cookie_expiration_period
):
load_balancer = self.get_load_balancer(load_balancer_name) load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.policies.lb_cookie_stickiness_policies.append(policy) policy = LbCookieStickinessPolicy(policy_name, cookie_expiration_period)
load_balancer.policies.append(policy)
return load_balancer return load_balancer
def set_load_balancer_policies_of_backend_server( def set_load_balancer_policies_of_backend_server(
@ -525,6 +562,36 @@ class ELBBackend(BaseBackend):
except AWSResourceNotFoundException: except AWSResourceNotFoundException:
raise CertificateNotFoundException() raise CertificateNotFoundException()
def enable_availability_zones_for_load_balancer(
self, load_balancer_name, availability_zones
):
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.zones = sorted(
list(set(load_balancer.zones + availability_zones))
)
return load_balancer.zones
def disable_availability_zones_for_load_balancer(
self, load_balancer_name, availability_zones
):
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.zones = sorted(
list(
set([az for az in load_balancer.zones if az not in availability_zones])
)
)
return load_balancer.zones
def attach_load_balancer_to_subnets(self, load_balancer_name, subnets):
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.subnets = list(set(load_balancer.subnets + subnets))
return load_balancer.subnets
def detach_load_balancer_from_subnets(self, load_balancer_name, subnets):
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.subnets = [s for s in load_balancer.subnets if s not in subnets]
return load_balancer.subnets
# Use the same regions as EC2 # Use the same regions as EC2
elb_backends = BackendDict(ELBBackend, "ec2") elb_backends = BackendDict(ELBBackend, "ec2")

24
moto/elb/policies.py Normal file
View File

@ -0,0 +1,24 @@
class Policy(object):
def __init__(self, policy_type_name):
self.policy_type_name = policy_type_name
class AppCookieStickinessPolicy(Policy):
def __init__(self, policy_name, cookie_name):
super().__init__(policy_type_name="AppCookieStickinessPolicy")
self.policy_name = policy_name
self.cookie_name = cookie_name
class LbCookieStickinessPolicy(Policy):
def __init__(self, policy_name, cookie_expiration_period):
super().__init__(policy_type_name="LbCookieStickinessPolicy")
self.policy_name = policy_name
self.cookie_expiration_period = cookie_expiration_period
class OtherPolicy(Policy):
def __init__(self, policy_name, policy_type_name, policy_attrs):
super().__init__(policy_type_name=policy_type_name)
self.policy_name = policy_name
self.attributes = policy_attrs or []

View File

@ -1,5 +1,4 @@
from moto.packages.boto.ec2.elb.policies import AppCookieStickinessPolicy, OtherPolicy from moto.core import ACCOUNT_ID
from moto.core.responses import BaseResponse from moto.core.responses import BaseResponse
from .models import elb_backends from .models import elb_backends
from .exceptions import DuplicateTagKeysError, LoadBalancerNotFoundError from .exceptions import DuplicateTagKeysError, LoadBalancerNotFoundError
@ -59,7 +58,11 @@ class ELBResponse(BaseResponse):
next_marker = load_balancers_resp[-1].name next_marker = load_balancers_resp[-1].name
template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE) template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
return template.render(load_balancers=load_balancers_resp, marker=next_marker) return template.render(
ACCOUNT_ID=ACCOUNT_ID,
load_balancers=load_balancers_resp,
marker=next_marker,
)
def delete_load_balancer_listeners(self): def delete_load_balancer_listeners(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
@ -76,6 +79,16 @@ class ELBResponse(BaseResponse):
template = self.response_template(DELETE_LOAD_BALANCER_TEMPLATE) template = self.response_template(DELETE_LOAD_BALANCER_TEMPLATE)
return template.render() return template.render()
def delete_load_balancer_policy(self):
load_balancer_name = self.querystring.get("LoadBalancerName")[0]
names = self._get_param("PolicyName")
self.elb_backend.delete_load_balancer_policy(
lb_name=load_balancer_name, policy_name=names
)
template = self.response_template(DELETE_LOAD_BALANCER_POLICY)
return template.render()
def apply_security_groups_to_load_balancer(self): def apply_security_groups_to_load_balancer(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
security_group_ids = self._get_multi_param("SecurityGroups.member") security_group_ids = self._get_multi_param("SecurityGroups.member")
@ -181,11 +194,13 @@ class ELBResponse(BaseResponse):
def create_load_balancer_policy(self): def create_load_balancer_policy(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
other_policy = OtherPolicy()
policy_name = self._get_param("PolicyName") policy_name = self._get_param("PolicyName")
other_policy.policy_name = policy_name policy_type_name = self._get_param("PolicyTypeName")
policy_attrs = self._get_multi_param("PolicyAttributes.member.")
self.elb_backend.create_lb_other_policy(load_balancer_name, other_policy) self.elb_backend.create_lb_other_policy(
load_balancer_name, policy_name, policy_type_name, policy_attrs
)
template = self.response_template(CREATE_LOAD_BALANCER_POLICY_TEMPLATE) template = self.response_template(CREATE_LOAD_BALANCER_POLICY_TEMPLATE)
return template.render() return template.render()
@ -193,11 +208,12 @@ class ELBResponse(BaseResponse):
def create_app_cookie_stickiness_policy(self): def create_app_cookie_stickiness_policy(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
policy = AppCookieStickinessPolicy() policy_name = self._get_param("PolicyName")
policy.policy_name = self._get_param("PolicyName") cookie_name = self._get_param("CookieName")
policy.cookie_name = self._get_param("CookieName")
self.elb_backend.create_app_cookie_stickiness_policy(load_balancer_name, policy) self.elb_backend.create_app_cookie_stickiness_policy(
load_balancer_name, policy_name, cookie_name
)
template = self.response_template(CREATE_APP_COOKIE_STICKINESS_POLICY_TEMPLATE) template = self.response_template(CREATE_APP_COOKIE_STICKINESS_POLICY_TEMPLATE)
return template.render() return template.render()
@ -205,15 +221,16 @@ class ELBResponse(BaseResponse):
def create_lb_cookie_stickiness_policy(self): def create_lb_cookie_stickiness_policy(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
policy = AppCookieStickinessPolicy() policy_name = self._get_param("PolicyName")
policy.policy_name = self._get_param("PolicyName")
cookie_expirations = self._get_param("CookieExpirationPeriod") cookie_expirations = self._get_param("CookieExpirationPeriod")
if cookie_expirations: if cookie_expirations:
policy.cookie_expiration_period = int(cookie_expirations) cookie_expiration_period = int(cookie_expirations)
else: else:
policy.cookie_expiration_period = None cookie_expiration_period = None
self.elb_backend.create_lb_cookie_stickiness_policy(load_balancer_name, policy) self.elb_backend.create_lb_cookie_stickiness_policy(
load_balancer_name, policy_name, cookie_expiration_period
)
template = self.response_template(CREATE_LB_COOKIE_STICKINESS_POLICY_TEMPLATE) template = self.response_template(CREATE_LB_COOKIE_STICKINESS_POLICY_TEMPLATE)
return template.render() return template.render()
@ -260,6 +277,16 @@ class ELBResponse(BaseResponse):
) )
return template.render() return template.render()
def describe_load_balancer_policies(self):
load_balancer_name = self.querystring.get("LoadBalancerName")[0]
names = self._get_multi_param("PolicyNames.member.")
policies = self.elb_backend.describe_load_balancer_policies(
lb_name=load_balancer_name, policy_names=names
)
template = self.response_template(DESCRIBE_LOAD_BALANCER_POLICIES_TEMPLATE)
return template.render(policies=policies)
def describe_instance_health(self): def describe_instance_health(self):
load_balancer_name = self._get_param("LoadBalancerName") load_balancer_name = self._get_param("LoadBalancerName")
provided_instance_ids = [ provided_instance_ids = [
@ -351,6 +378,58 @@ class ELBResponse(BaseResponse):
for tag_key, tag_value in zip(tag_keys, tag_values): for tag_key, tag_value in zip(tag_keys, tag_values):
elb.add_tag(tag_key, tag_value) elb.add_tag(tag_key, tag_value)
def enable_availability_zones_for_load_balancer(self):
params = self._get_params()
load_balancer_name = params.get("LoadBalancerName")
availability_zones = params.get("AvailabilityZones")
availability_zones = (
self.elb_backend.enable_availability_zones_for_load_balancer(
load_balancer_name=load_balancer_name,
availability_zones=availability_zones,
)
)
template = self.response_template(
ENABLE_AVAILABILITY_ZONES_FOR_LOAD_BALANCER_TEMPLATE
)
return template.render(availability_zones=availability_zones)
def disable_availability_zones_for_load_balancer(self):
params = self._get_params()
load_balancer_name = params.get("LoadBalancerName")
availability_zones = params.get("AvailabilityZones")
availability_zones = (
self.elb_backend.disable_availability_zones_for_load_balancer(
load_balancer_name=load_balancer_name,
availability_zones=availability_zones,
)
)
template = self.response_template(
DISABLE_AVAILABILITY_ZONES_FOR_LOAD_BALANCER_TEMPLATE
)
return template.render(availability_zones=availability_zones)
def attach_load_balancer_to_subnets(self):
params = self._get_params()
load_balancer_name = params.get("LoadBalancerName")
subnets = params.get("Subnets")
all_subnets = self.elb_backend.attach_load_balancer_to_subnets(
load_balancer_name, subnets
)
template = self.response_template(ATTACH_LB_TO_SUBNETS_TEMPLATE)
return template.render(subnets=all_subnets)
def detach_load_balancer_from_subnets(self):
params = self._get_params()
load_balancer_name = params.get("LoadBalancerName")
subnets = params.get("Subnets")
all_subnets = self.elb_backend.detach_load_balancer_from_subnets(
load_balancer_name, subnets
)
template = self.response_template(DETACH_LB_FROM_SUBNETS_TEMPLATE)
return template.render(subnets=all_subnets)
ADD_TAGS_TEMPLATE = """<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/"> ADD_TAGS_TEMPLATE = """<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<AddTagsResult/> <AddTagsResult/>
@ -390,6 +469,31 @@ DESCRIBE_TAGS_TEMPLATE = """<DescribeTagsResponse xmlns="http://elasticloadbalan
</DescribeTagsResponse>""" </DescribeTagsResponse>"""
DESCRIBE_LOAD_BALANCER_POLICIES_TEMPLATE = """<DescribeLoadBalancerPoliciesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DescribeLoadBalancerPoliciesResult>
<PolicyDescriptions>
{% for policy in policies %}
<member>
<PolicyName>{{ policy.policy_name }}</PolicyName>
<PolicyTypeName>{{ policy.policy_type_name }}</PolicyTypeName>
<PolicyAttributeDescriptions>
{% for attr in policy.attributes %}
<member>
<AttributeName>{{ attr["AttributeName"] }}</AttributeName>
<AttributeValue>{{ attr["AttributeValue"] }}</AttributeValue>
</member>
{% endfor %}
</PolicyAttributeDescriptions>
</member>
{% endfor %}
</PolicyDescriptions>
</DescribeLoadBalancerPoliciesResult>
<ResponseMetadata>
<RequestId>360e81f7-1100-11e4-b6ed-0f30EXAMPLE</RequestId>
</ResponseMetadata>
</DescribeLoadBalancerPoliciesResponse>"""
CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/"> CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<CreateLoadBalancerResult> <CreateLoadBalancerResult>
<DNSName>{{ load_balancer.dns_name }}</DNSName> <DNSName>{{ load_balancer.dns_name }}</DNSName>
@ -423,6 +527,12 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
<member>{{ security_group_id }}</member> <member>{{ security_group_id }}</member>
{% endfor %} {% endfor %}
</SecurityGroups> </SecurityGroups>
{% if load_balancer.vpc_id %}
<SourceSecurityGroup>
<OwnerAlias>{{ ACCOUNT_ID }}</OwnerAlias>
<GroupName>default</GroupName>
</SourceSecurityGroup>
{% endif %}
<LoadBalancerName>{{ load_balancer.name }}</LoadBalancerName> <LoadBalancerName>{{ load_balancer.name }}</LoadBalancerName>
<CreatedTime>{{ load_balancer.created_time.isoformat() }}</CreatedTime> <CreatedTime>{{ load_balancer.created_time.isoformat() }}</CreatedTime>
<HealthCheck> <HealthCheck>
@ -432,6 +542,8 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
<HealthyThreshold>{{ load_balancer.health_check.healthy_threshold }}</HealthyThreshold> <HealthyThreshold>{{ load_balancer.health_check.healthy_threshold }}</HealthyThreshold>
<Timeout>{{ load_balancer.health_check.timeout }}</Timeout> <Timeout>{{ load_balancer.health_check.timeout }}</Timeout>
<UnhealthyThreshold>{{ load_balancer.health_check.unhealthy_threshold }}</UnhealthyThreshold> <UnhealthyThreshold>{{ load_balancer.health_check.unhealthy_threshold }}</UnhealthyThreshold>
{% else %}
<Target></Target>
{% endif %} {% endif %}
</HealthCheck> </HealthCheck>
{% if load_balancer.vpc_id %} {% if load_balancer.vpc_id %}
@ -466,33 +578,33 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
</Instances> </Instances>
<Policies> <Policies>
<AppCookieStickinessPolicies> <AppCookieStickinessPolicies>
{% if load_balancer.policies.app_cookie_stickiness_policies %} {% for policy in load_balancer.policies %}
{% for policy in load_balancer.policies.app_cookie_stickiness_policies %} {% if policy.policy_type_name == "AppCookieStickinessPolicy" %}
<member> <member>
<CookieName>{{ policy.cookie_name }}</CookieName> <CookieName>{{ policy.cookie_name }}</CookieName>
<PolicyName>{{ policy.policy_name }}</PolicyName> <PolicyName>{{ policy.policy_name }}</PolicyName>
</member> </member>
{% endfor %} {% endif %}
{% endif %} {% endfor %}
</AppCookieStickinessPolicies> </AppCookieStickinessPolicies>
<LBCookieStickinessPolicies> <LBCookieStickinessPolicies>
{% if load_balancer.policies.lb_cookie_stickiness_policies %} {% for policy in load_balancer.policies %}
{% for policy in load_balancer.policies.lb_cookie_stickiness_policies %} {% if policy.policy_type_name == "LbCookieStickinessPolicy" %}
<member> <member>
{% if policy.cookie_expiration_period %} {% if policy.cookie_expiration_period %}
<CookieExpirationPeriod>{{ policy.cookie_expiration_period }}</CookieExpirationPeriod> <CookieExpirationPeriod>{{ policy.cookie_expiration_period }}</CookieExpirationPeriod>
{% endif %} {% endif %}
<PolicyName>{{ policy.policy_name }}</PolicyName> <PolicyName>{{ policy.policy_name }}</PolicyName>
</member> </member>
{% endfor %} {% endif %}
{% endif %} {% endfor %}
</LBCookieStickinessPolicies> </LBCookieStickinessPolicies>
<OtherPolicies> <OtherPolicies>
{% if load_balancer.policies.other_policies %} {% for policy in load_balancer.policies %}
{% for policy in load_balancer.policies.other_policies %} {% if policy.policy_type_name not in ["AppCookieStickinessPolicy", "LbCookieStickinessPolicy"] %}
<member>{{ policy.policy_name }}</member> <member>{{ policy.policy_name }}</member>
{% endfor %} {% endif %}
{% endif %} {% endfor %}
</OtherPolicies> </OtherPolicies>
</Policies> </Policies>
<AvailabilityZones> <AvailabilityZones>
@ -593,7 +705,7 @@ DEREGISTER_INSTANCES_TEMPLATE = """<DeregisterInstancesFromLoadBalancerResponse
</ResponseMetadata> </ResponseMetadata>
</DeregisterInstancesFromLoadBalancerResponse>""" </DeregisterInstancesFromLoadBalancerResponse>"""
SET_LOAD_BALANCER_SSL_CERTIFICATE = """<SetLoadBalancerListenerSSLCertificateResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2012-06-01/"> SET_LOAD_BALANCER_SSL_CERTIFICATE = """<SetLoadBalancerListenerSSLCertificateResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<SetLoadBalancerListenerSSLCertificateResult/> <SetLoadBalancerListenerSSLCertificateResult/>
<ResponseMetadata> <ResponseMetadata>
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId> <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
@ -601,13 +713,21 @@ SET_LOAD_BALANCER_SSL_CERTIFICATE = """<SetLoadBalancerListenerSSLCertificateRes
</SetLoadBalancerListenerSSLCertificateResponse>""" </SetLoadBalancerListenerSSLCertificateResponse>"""
DELETE_LOAD_BALANCER_LISTENERS = """<DeleteLoadBalancerListenersResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2012-06-01/"> DELETE_LOAD_BALANCER_LISTENERS = """<DeleteLoadBalancerListenersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DeleteLoadBalancerListenersResult/> <DeleteLoadBalancerListenersResult/>
<ResponseMetadata> <ResponseMetadata>
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId> <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
</ResponseMetadata> </ResponseMetadata>
</DeleteLoadBalancerListenersResponse>""" </DeleteLoadBalancerListenersResponse>"""
DELETE_LOAD_BALANCER_POLICY = """<DeleteLoadBalancerPolicyResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DeleteLoadBalancerPolicyResult/>
<ResponseMetadata>
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
</ResponseMetadata>
</DeleteLoadBalancerPolicyResponse>"""
DESCRIBE_ATTRIBUTES_TEMPLATE = """<DescribeLoadBalancerAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/"> DESCRIBE_ATTRIBUTES_TEMPLATE = """<DescribeLoadBalancerAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DescribeLoadBalancerAttributesResult> <DescribeLoadBalancerAttributesResult>
<LoadBalancerAttributes> <LoadBalancerAttributes>
@ -626,11 +746,9 @@ DESCRIBE_ATTRIBUTES_TEMPLATE = """<DescribeLoadBalancerAttributesResponse xmlns
<Enabled>{{ attributes.cross_zone_load_balancing.enabled }}</Enabled> <Enabled>{{ attributes.cross_zone_load_balancing.enabled }}</Enabled>
</CrossZoneLoadBalancing> </CrossZoneLoadBalancing>
<ConnectionDraining> <ConnectionDraining>
{% if attributes["connection_draining"]["enabled"] == 'true' %} <Enabled>{{ attributes["connection_draining"]["enabled"] }}</Enabled>
<Enabled>true</Enabled> {% if attributes["connection_draining"]["timeout"] %}
<Timeout>{{ attributes["connection_draining"]["timeout"] }}</Timeout> <Timeout>{{ attributes["connection_draining"]["timeout"] }}</Timeout>
{% else %}
<Enabled>false</Enabled>
{% endif %} {% endif %}
</ConnectionDraining> </ConnectionDraining>
</LoadBalancerAttributes> </LoadBalancerAttributes>
@ -732,3 +850,55 @@ DESCRIBE_INSTANCE_HEALTH_TEMPLATE = """<DescribeInstanceHealthResponse xmlns="ht
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId> <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
</ResponseMetadata> </ResponseMetadata>
</DescribeInstanceHealthResponse>""" </DescribeInstanceHealthResponse>"""
ENABLE_AVAILABILITY_ZONES_FOR_LOAD_BALANCER_TEMPLATE = """<EnableAvailabilityZonesForLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<ResponseMetadata>
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
</ResponseMetadata>
<EnableAvailabilityZonesForLoadBalancerResult>
<AvailabilityZones>
{% for az in availability_zones %}
<AvailabilityZone>{{ az }}</AvailabilityZone>
{% endfor %}
</AvailabilityZones>
</EnableAvailabilityZonesForLoadBalancerResult>
</EnableAvailabilityZonesForLoadBalancerResponse>"""
DISABLE_AVAILABILITY_ZONES_FOR_LOAD_BALANCER_TEMPLATE = """<DisableAvailabilityZonesForLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<ResponseMetadata>
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
</ResponseMetadata>
<DisableAvailabilityZonesForLoadBalancerResult>
<AvailabilityZones>
{% for az in availability_zones %}
<AvailabilityZone>{{ az }}</AvailabilityZone>
{% endfor %}
</AvailabilityZones>
</DisableAvailabilityZonesForLoadBalancerResult>
</DisableAvailabilityZonesForLoadBalancerResponse>"""
ATTACH_LB_TO_SUBNETS_TEMPLATE = """<AttachLoadBalancerToSubnetsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<AttachLoadBalancerToSubnetsResult>
<Subnets>
{% for subnet in subnets %}
<member>{{ subnet }}</member>
{% endfor %}
</Subnets>
</AttachLoadBalancerToSubnetsResult>
<ResponseMetadata>
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
</ResponseMetadata>
</AttachLoadBalancerToSubnetsResponse>"""
DETACH_LB_FROM_SUBNETS_TEMPLATE = """<DetachLoadBalancerFromSubnetsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DetachLoadBalancerFromSubnetsResult>
<Subnets>
{% for subnet in subnets %}
<member>{{ subnet }}</member>
{% endfor %}
</Subnets>
</DetachLoadBalancerFromSubnetsResult>
<ResponseMetadata>
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
</ResponseMetadata>
</DetachLoadBalancerFromSubnetsResponse>"""

View File

@ -4,6 +4,9 @@ from moto.core.exceptions import RESTError
class ELBClientError(RESTError): class ELBClientError(RESTError):
code = 400 code = 400
def __init__(self, error_type, message):
super().__init__(error_type, message, template="wrapped_single_error")
class DuplicateTagKeysError(ELBClientError): class DuplicateTagKeysError(ELBClientError):
def __init__(self, cidr): def __init__(self, cidr):
@ -149,8 +152,9 @@ class ResourceInUseError(ELBClientError):
class RuleNotFoundError(ELBClientError): class RuleNotFoundError(ELBClientError):
def __init__(self): def __init__(self, msg=None):
super().__init__("RuleNotFound", "The specified rule does not exist.") msg = msg or "The specified rule does not exist."
super().__init__("RuleNotFound", msg)
class DuplicatePriorityError(ELBClientError): class DuplicatePriorityError(ELBClientError):

View File

@ -38,6 +38,14 @@ from .exceptions import (
InvalidLoadBalancerActionException, InvalidLoadBalancerActionException,
) )
ALLOWED_ACTIONS = [
"redirect",
"authenticate-cognito",
"authenticate-oidc",
"fixed-response",
"forward",
]
class FakeHealthStatus(BaseModel): class FakeHealthStatus(BaseModel):
def __init__( def __init__(
@ -85,15 +93,22 @@ class FakeTargetGroup(CloudFormationModel):
self.healthcheck_port = healthcheck_port self.healthcheck_port = healthcheck_port
self.healthcheck_path = healthcheck_path self.healthcheck_path = healthcheck_path
self.healthcheck_interval_seconds = healthcheck_interval_seconds or 30 self.healthcheck_interval_seconds = healthcheck_interval_seconds or 30
self.healthcheck_timeout_seconds = healthcheck_timeout_seconds or 5 self.healthcheck_timeout_seconds = healthcheck_timeout_seconds
if not healthcheck_timeout_seconds:
# Default depends on protocol
if protocol in ["TCP", "TLS"]:
self.healthcheck_timeout_seconds = 6
elif protocol in ["HTTP", "HTTPS", "GENEVE"]:
self.healthcheck_timeout_seconds = 5
else:
self.healthcheck_timeout_seconds = 30
self.healthcheck_enabled = healthcheck_enabled self.healthcheck_enabled = healthcheck_enabled
self.healthy_threshold_count = healthy_threshold_count or 5 self.healthy_threshold_count = healthy_threshold_count or 5
self.unhealthy_threshold_count = unhealthy_threshold_count or 2 self.unhealthy_threshold_count = unhealthy_threshold_count or 2
self.load_balancer_arns = [] self.load_balancer_arns = []
self.tags = {} self.tags = {}
self.matcher = matcher if self.healthcheck_protocol != "TCP":
if self.protocol != "TCP": self.matcher = matcher or {"HttpCode": "200"}
self.matcher = self.matcher or {"HttpCode": "200"}
self.healthcheck_path = self.healthcheck_path or "/" self.healthcheck_path = self.healthcheck_path or "/"
self.healthcheck_port = self.healthcheck_port or str(self.port) self.healthcheck_port = self.healthcheck_port or str(self.port)
self.target_type = target_type self.target_type = target_type
@ -132,6 +147,9 @@ class FakeTargetGroup(CloudFormationModel):
raise TooManyTagsError() raise TooManyTagsError()
self.tags[key] = value self.tags[key] = value
def remove_tag(self, key):
self.tags.pop(key, None)
def health_for(self, target, ec2_backend): def health_for(self, target, ec2_backend):
t = self.targets.get(target["id"]) t = self.targets.get(target["id"])
if t is None: if t is None:
@ -207,6 +225,7 @@ class FakeListener(CloudFormationModel):
ssl_policy, ssl_policy,
certificate, certificate,
default_actions, default_actions,
alpn_policy,
): ):
self.load_balancer_arn = load_balancer_arn self.load_balancer_arn = load_balancer_arn
self.arn = arn self.arn = arn
@ -216,6 +235,7 @@ class FakeListener(CloudFormationModel):
self.certificate = certificate self.certificate = certificate
self.certificates = [certificate] if certificate is not None else [] self.certificates = [certificate] if certificate is not None else []
self.default_actions = default_actions self.default_actions = default_actions
self.alpn_policy = alpn_policy or []
self._non_default_rules = OrderedDict() self._non_default_rules = OrderedDict()
self._default_rule = OrderedDict() self._default_rule = OrderedDict()
self._default_rule[0] = FakeRule( self._default_rule[0] = FakeRule(
@ -244,6 +264,14 @@ class FakeListener(CloudFormationModel):
self._non_default_rules[arn] = rule self._non_default_rules[arn] = rule
sorted(self._non_default_rules.values(), key=lambda x: x.priority) sorted(self._non_default_rules.values(), key=lambda x: x.priority)
def add_tag(self, key, value):
if len(self.tags) >= 10 and key not in self.tags:
raise TooManyTagsError()
self.tags[key] = value
def remove_tag(self, key):
self.tags.pop(key, None)
@staticmethod @staticmethod
def cloudformation_name_type(): def cloudformation_name_type():
return None return None
@ -366,9 +394,18 @@ class FakeAction(BaseModel):
self.data = data self.data = data
self.type = data.get("Type") self.type = data.get("Type")
if "ForwardConfig" in self.data:
if "TargetGroupStickinessConfig" not in self.data["ForwardConfig"]:
self.data["ForwardConfig"]["TargetGroupStickinessConfig"] = {
"Enabled": "false"
}
def to_xml(self): def to_xml(self):
template = Template( template = Template(
"""<Type>{{ action.type }}</Type> """<Type>{{ action.type }}</Type>
{% if "Order" in action.data %}
<Order>{{ action.data["Order"] }}</Order>
{% endif %}
{% if action.type == "forward" and "ForwardConfig" in action.data %} {% if action.type == "forward" and "ForwardConfig" in action.data %}
<ForwardConfig> <ForwardConfig>
<TargetGroups> <TargetGroups>
@ -379,6 +416,12 @@ class FakeAction(BaseModel):
</member> </member>
{% endfor %} {% endfor %}
</TargetGroups> </TargetGroups>
<TargetGroupStickinessConfig>
<Enabled>{{ action.data["ForwardConfig"]["TargetGroupStickinessConfig"]["Enabled"] }}</Enabled>
{% if "DurationSeconds" in action.data["ForwardConfig"]["TargetGroupStickinessConfig"] %}
<DurationSeconds>{{ action.data["ForwardConfig"]["TargetGroupStickinessConfig"]["DurationSeconds"] }}</DurationSeconds>
{% endif %}
</TargetGroupStickinessConfig>
</ForwardConfig> </ForwardConfig>
{% endif %} {% endif %}
{% if action.type == "forward" and "ForwardConfig" not in action.data %} {% if action.type == "forward" and "ForwardConfig" not in action.data %}
@ -388,13 +431,59 @@ class FakeAction(BaseModel):
<Protocol>{{ action.data["RedirectConfig"]["Protocol"] }}</Protocol> <Protocol>{{ action.data["RedirectConfig"]["Protocol"] }}</Protocol>
<Port>{{ action.data["RedirectConfig"]["Port"] }}</Port> <Port>{{ action.data["RedirectConfig"]["Port"] }}</Port>
<StatusCode>{{ action.data["RedirectConfig"]["StatusCode"] }}</StatusCode> <StatusCode>{{ action.data["RedirectConfig"]["StatusCode"] }}</StatusCode>
{% if action.data["RedirectConfig"]["Host"] %}<Host>{{ action.data["RedirectConfig"]["Host"] }}</Host>{% endif %}
{% if action.data["RedirectConfig"]["Path"] %}<Path>{{ action.data["RedirectConfig"]["Path"] }}</Path>{% endif %}
{% if action.data["RedirectConfig"]["Query"] %}<Query>{{ action.data["RedirectConfig"]["Query"] }}</Query>{% endif %}
</RedirectConfig> </RedirectConfig>
{% elif action.type == "authenticate-cognito" %} {% elif action.type == "authenticate-cognito" %}
<AuthenticateCognitoConfig> <AuthenticateCognitoConfig>
<UserPoolArn>{{ action.data["AuthenticateCognitoConfig"]["UserPoolArn"] }}</UserPoolArn> <UserPoolArn>{{ action.data["AuthenticateCognitoConfig"]["UserPoolArn"] }}</UserPoolArn>
<UserPoolClientId>{{ action.data["AuthenticateCognitoConfig"]["UserPoolClientId"] }}</UserPoolClientId> <UserPoolClientId>{{ action.data["AuthenticateCognitoConfig"]["UserPoolClientId"] }}</UserPoolClientId>
<UserPoolDomain>{{ action.data["AuthenticateCognitoConfig"]["UserPoolDomain"] }}</UserPoolDomain> <UserPoolDomain>{{ action.data["AuthenticateCognitoConfig"]["UserPoolDomain"] }}</UserPoolDomain>
{% if action.data["AuthenticateCognitoConfig"].get("AuthenticationRequestExtraParams") %}
<AuthenticationRequestExtraParams>
{% for entry in action.data["AuthenticateCognitoConfig"].get("AuthenticationRequestExtraParams", {}).get("entry", {}).values() %}
<member>
<key>{{ entry["key"] }}</key>
<value>{{ entry["value"] }}</value>
</member>
{% endfor %}
</AuthenticationRequestExtraParams>
{% endif %}
</AuthenticateCognitoConfig> </AuthenticateCognitoConfig>
{% elif action.type == "authenticate-oidc" %}
<AuthenticateOidcConfig>
<AuthorizationEndpoint>{{ action.data["AuthenticateOidcConfig"]["AuthorizationEndpoint"] }}</AuthorizationEndpoint>
<ClientId>{{ action.data["AuthenticateOidcConfig"]["ClientId"] }}</ClientId>
{% if "ClientSecret" in action.data["AuthenticateOidcConfig"] %}
<ClientSecret>{{ action.data["AuthenticateOidcConfig"]["ClientSecret"] }}</ClientSecret>
{% endif %}
<Issuer>{{ action.data["AuthenticateOidcConfig"]["Issuer"] }}</Issuer>
<TokenEndpoint>{{ action.data["AuthenticateOidcConfig"]["TokenEndpoint"] }}</TokenEndpoint>
<UserInfoEndpoint>{{ action.data["AuthenticateOidcConfig"]["UserInfoEndpoint"] }}</UserInfoEndpoint>
{% if "OnUnauthenticatedRequest" in action.data["AuthenticateOidcConfig"] %}
<OnUnauthenticatedRequest>{{ action.data["AuthenticateOidcConfig"]["OnUnauthenticatedRequest"] }}</OnUnauthenticatedRequest>
{% endif %}
{% if "UseExistingClientSecret" in action.data["AuthenticateOidcConfig"] %}
<UseExistingClientSecret>{{ action.data["AuthenticateOidcConfig"]["UseExistingClientSecret"] }}</UseExistingClientSecret>
{% endif %}
{% if "SessionTimeout" in action.data["AuthenticateOidcConfig"] %}
<SessionTimeout>{{ action.data["AuthenticateOidcConfig"]["SessionTimeout"] }}</SessionTimeout>
{% endif %}
{% if "SessionCookieName" in action.data["AuthenticateOidcConfig"] %}
<SessionCookieName>{{ action.data["AuthenticateOidcConfig"]["SessionCookieName"] }}</SessionCookieName>
{% endif %}
{% if "Scope" in action.data["AuthenticateOidcConfig"] %}
<Scope>{{ action.data["AuthenticateOidcConfig"]["Scope"] }}</Scope>
{% endif %}
{% if action.data["AuthenticateOidcConfig"].get("AuthenticationRequestExtraParams") %}
<AuthenticationRequestExtraParams>
{% for entry in action.data["AuthenticateOidcConfig"].get("AuthenticationRequestExtraParams", {}).get("entry", {}).values() %}
<member><key>{{ entry["key"] }}</key><value>{{ entry["value"] }}</value></member>
{% endfor %}
</AuthenticationRequestExtraParams>
{% endif %}
</AuthenticateOidcConfig>
{% elif action.type == "fixed-response" %} {% elif action.type == "fixed-response" %}
<FixedResponseConfig> <FixedResponseConfig>
<ContentType>{{ action.data["FixedResponseConfig"]["ContentType"] }}</ContentType> <ContentType>{{ action.data["FixedResponseConfig"]["ContentType"] }}</ContentType>
@ -590,6 +679,7 @@ class ELBv2Backend(BaseBackend):
name, name,
security_groups, security_groups,
subnet_ids, subnet_ids,
subnet_mappings=None,
scheme="internet-facing", scheme="internet-facing",
loadbalancer_type=None, loadbalancer_type=None,
): ):
@ -597,13 +687,19 @@ class ELBv2Backend(BaseBackend):
subnets = [] subnets = []
state = "provisioning" state = "provisioning"
if not subnet_ids: if not subnet_ids and not subnet_mappings:
raise SubnetNotFoundError() raise SubnetNotFoundError()
for subnet_id in subnet_ids: for subnet_id in subnet_ids:
subnet = self.ec2_backend.get_subnet(subnet_id) subnet = self.ec2_backend.get_subnet(subnet_id)
if subnet is None: if subnet is None:
raise SubnetNotFoundError() raise SubnetNotFoundError()
subnets.append(subnet) subnets.append(subnet)
for subnet in subnet_mappings or []:
subnet_id = subnet["SubnetId"]
subnet = self.ec2_backend.get_subnet(subnet_id)
if subnet is None:
raise SubnetNotFoundError()
subnets.append(subnet)
vpc_id = subnets[0].vpc_id vpc_id = subnets[0].vpc_id
arn = make_arn_for_load_balancer( arn = make_arn_for_load_balancer(
@ -634,12 +730,7 @@ class ELBv2Backend(BaseBackend):
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 in [ if action_type in ALLOWED_ACTIONS:
"redirect",
"authenticate-cognito",
"fixed-response",
"forward",
]:
default_actions.append(action) default_actions.append(action)
else: else:
raise InvalidActionTypeError(action_type, i + 1) raise InvalidActionTypeError(action_type, i + 1)
@ -839,7 +930,11 @@ class ELBv2Backend(BaseBackend):
raise ActionTargetGroupNotFoundError(target_group_arn) raise ActionTargetGroupNotFoundError(target_group_arn)
elif action_type == "fixed-response": elif action_type == "fixed-response":
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",
"authenticate-oidc",
]:
pass pass
# pass if listener rule has forward_config as an Action property # pass if listener rule has forward_config as an Action property
elif action_type == "forward" and "ForwardConfig" in action.data.keys(): elif action_type == "forward" and "ForwardConfig" in action.data.keys():
@ -924,6 +1019,7 @@ Member must satisfy regular expression pattern: {}".format(
if ( if (
kwargs.get("matcher") kwargs.get("matcher")
and kwargs["matcher"].get("HttpCode")
and FakeTargetGroup.HTTP_CODE_REGEX.match(kwargs["matcher"]["HttpCode"]) and FakeTargetGroup.HTTP_CODE_REGEX.match(kwargs["matcher"]["HttpCode"])
is None is None
): ):
@ -965,11 +1061,7 @@ Member must satisfy regular expression pattern: {}".format(
default_actions.append( default_actions.append(
{"Type": action_type, "TargetGroupArn": action["TargetGroupArn"]} {"Type": action_type, "TargetGroupArn": action["TargetGroupArn"]}
) )
elif action_type in [ elif action_type in ALLOWED_ACTIONS:
"redirect",
"authenticate-cognito",
"fixed-response",
]:
default_actions.append(action) default_actions.append(action)
else: else:
raise InvalidActionTypeError(action_type, i + 1) raise InvalidActionTypeError(action_type, i + 1)
@ -983,6 +1075,7 @@ Member must satisfy regular expression pattern: {}".format(
ssl_policy, ssl_policy,
certificate, certificate,
default_actions, default_actions,
alpn_policy=None,
): ):
default_actions = [FakeAction(action) for action in default_actions] default_actions = [FakeAction(action) for action in default_actions]
balancer = self.load_balancers.get(load_balancer_arn) balancer = self.load_balancers.get(load_balancer_arn)
@ -1005,6 +1098,7 @@ Member must satisfy regular expression pattern: {}".format(
ssl_policy, ssl_policy,
certificate, certificate,
default_actions, default_actions,
alpn_policy,
) )
balancer.listeners[listener.arn] = listener balancer.listeners[listener.arn] = listener
for action in default_actions: for action in default_actions:
@ -1071,6 +1165,8 @@ Member must satisfy regular expression pattern: {}".format(
for rule in listener.rules.values(): for rule in listener.rules.values():
if rule.arn in rule_arns: if rule.arn in rule_arns:
matched_rules.append(rule) matched_rules.append(rule)
if len(matched_rules) != len(rule_arns):
raise RuleNotFoundError("One or more rules not found")
return matched_rules return matched_rules
def describe_target_groups(self, load_balancer_arn, target_group_arns, names): def describe_target_groups(self, load_balancer_arn, target_group_arns, names):
@ -1274,7 +1370,7 @@ Member must satisfy regular expression pattern: {}".format(
balancer.security_groups = sec_groups balancer.security_groups = sec_groups
def set_subnets(self, arn, subnets): def set_subnets(self, arn, subnets, subnet_mappings):
balancer = self.load_balancers.get(arn) balancer = self.load_balancers.get(arn)
if balancer is None: if balancer is None:
raise LoadBalancerNotFoundError() raise LoadBalancerNotFoundError()
@ -1283,19 +1379,20 @@ Member must satisfy regular expression pattern: {}".format(
sub_zone_list = {} sub_zone_list = {}
for subnet in subnets: for subnet in subnets:
try: try:
subnet = self.ec2_backend.get_subnet(subnet) subnet = self._get_subnet(sub_zone_list, subnet)
if subnet.availability_zone in sub_zone_list:
raise RESTError(
"InvalidConfigurationRequest",
"More than 1 subnet cannot be specified for 1 availability zone",
)
sub_zone_list[subnet.availability_zone] = subnet.id sub_zone_list[subnet.availability_zone] = subnet.id
subnet_objects.append(subnet) subnet_objects.append(subnet)
except Exception: except Exception:
raise SubnetNotFoundError() raise SubnetNotFoundError()
for subnet_mapping in subnet_mappings:
subnet_id = subnet_mapping["SubnetId"]
subnet = self._get_subnet(sub_zone_list, subnet_id)
sub_zone_list[subnet.availability_zone] = subnet.id
subnet_objects.append(subnet)
if len(sub_zone_list) < 2: if len(sub_zone_list) < 2:
raise RESTError( raise RESTError(
"InvalidConfigurationRequest", "InvalidConfigurationRequest",
@ -1306,6 +1403,15 @@ Member must satisfy regular expression pattern: {}".format(
return sub_zone_list.items() return sub_zone_list.items()
def _get_subnet(self, sub_zone_list, subnet):
subnet = self.ec2_backend.get_subnet(subnet)
if subnet.availability_zone in sub_zone_list:
raise RESTError(
"InvalidConfigurationRequest",
"More than 1 subnet cannot be specified for 1 availability zone",
)
return subnet
def modify_load_balancer_attributes(self, arn, attrs): def modify_load_balancer_attributes(self, arn, attrs):
balancer = self.load_balancers.get(arn) balancer = self.load_balancers.get(arn)
if balancer is None: if balancer is None:
@ -1384,13 +1490,9 @@ Member must satisfy regular expression pattern: {}".format(
default_actions=None, default_actions=None,
): ):
default_actions = [FakeAction(action) for action in default_actions] default_actions = [FakeAction(action) for action in default_actions]
for load_balancer in self.load_balancers.values(): listener = self.describe_listeners(load_balancer_arn=None, listener_arns=[arn])[
if arn in load_balancer.listeners: 0
break ]
else:
raise ListenerNotFoundError()
listener = load_balancer.listeners[arn]
if port is not None: if port is not None:
listener.port = port listener.port = port
@ -1415,11 +1517,13 @@ Member must satisfy regular expression pattern: {}".format(
) )
listener.certificate = default_cert_arn listener.certificate = default_cert_arn
listener.certificates = certificates listener.certificates = certificates
else: elif len(certificates) == 0 and len(listener.certificates) == 0:
raise RESTError( raise RESTError(
"CertificateWereNotPassed", "CertificateWereNotPassed",
"You must provide a list containing exactly one certificate if the listener protocol is HTTPS.", "You must provide a list containing exactly one certificate if the listener protocol is HTTPS.",
) )
# else:
# The list was not provided, meaning we just keep the existing certificates (if any)
if protocol is not None: if protocol is not None:
listener.protocol = protocol listener.protocol = protocol
@ -1475,5 +1579,25 @@ Member must satisfy regular expression pattern: {}".format(
for target_group in self.target_groups.values(): for target_group in self.target_groups.values():
target_group.deregister_terminated_instances(instance_ids) target_group.deregister_terminated_instances(instance_ids)
def add_listener_certificates(self, arn, certificates):
listener = self.describe_listeners(load_balancer_arn=None, listener_arns=[arn])[
0
]
listener.certificates.extend([c["certificate_arn"] for c in certificates])
return listener.certificates
def describe_listener_certificates(self, arn):
listener = self.describe_listeners(load_balancer_arn=None, listener_arns=[arn])[
0
]
return listener.certificates
def remove_listener_certificates(self, arn, certificates):
listener = self.describe_listeners(load_balancer_arn=None, listener_arns=[arn])[
0
]
cert_arns = [c["certificate_arn"] for c in certificates]
listener.certificates = [c for c in listener.certificates if c not in cert_arns]
elbv2_backends = BackendDict(ELBv2Backend, "ec2") elbv2_backends = BackendDict(ELBv2Backend, "ec2")

View File

@ -146,6 +146,7 @@ class ELBV2Response(BaseResponse):
def create_load_balancer(self): def create_load_balancer(self):
load_balancer_name = self._get_param("Name") load_balancer_name = self._get_param("Name")
subnet_ids = self._get_multi_param("Subnets.member") subnet_ids = self._get_multi_param("Subnets.member")
subnet_mappings = self._get_params().get("SubnetMappings", [])
security_groups = self._get_multi_param("SecurityGroups.member") security_groups = self._get_multi_param("SecurityGroups.member")
scheme = self._get_param("Scheme") scheme = self._get_param("Scheme")
loadbalancer_type = self._get_param("Type") loadbalancer_type = self._get_param("Type")
@ -154,6 +155,7 @@ class ELBV2Response(BaseResponse):
name=load_balancer_name, name=load_balancer_name,
security_groups=security_groups, security_groups=security_groups,
subnet_ids=subnet_ids, subnet_ids=subnet_ids,
subnet_mappings=subnet_mappings,
scheme=scheme, scheme=scheme,
loadbalancer_type=loadbalancer_type, loadbalancer_type=loadbalancer_type,
) )
@ -225,6 +227,7 @@ class ELBV2Response(BaseResponse):
else: else:
certificate = None certificate = None
default_actions = params.get("DefaultActions", []) default_actions = params.get("DefaultActions", [])
alpn_policy = params.get("AlpnPolicy", [])
listener = self.elbv2_backend.create_listener( listener = self.elbv2_backend.create_listener(
load_balancer_arn=load_balancer_arn, load_balancer_arn=load_balancer_arn,
@ -233,7 +236,9 @@ class ELBV2Response(BaseResponse):
ssl_policy=ssl_policy, ssl_policy=ssl_policy,
certificate=certificate, certificate=certificate,
default_actions=default_actions, default_actions=default_actions,
alpn_policy=alpn_policy,
) )
self._add_tags(listener)
template = self.response_template(CREATE_LISTENER_TEMPLATE) template = self.response_template(CREATE_LISTENER_TEMPLATE)
return template.render(listener=listener) return template.render(listener=listener)
@ -418,16 +423,7 @@ class ELBV2Response(BaseResponse):
resource_arns = self._get_multi_param("ResourceArns.member") resource_arns = self._get_multi_param("ResourceArns.member")
for arn in resource_arns: for arn in resource_arns:
if ":targetgroup" in arn: resource = self._get_resource_by_arn(arn)
resource = self.elbv2_backend.target_groups.get(arn)
if not resource:
raise TargetGroupNotFoundError()
elif ":loadbalancer" in arn:
resource = self.elbv2_backend.load_balancers.get(arn)
if not resource:
raise LoadBalancerNotFoundError()
else:
raise LoadBalancerNotFoundError()
self._add_tags(resource) self._add_tags(resource)
template = self.response_template(ADD_TAGS_TEMPLATE) template = self.response_template(ADD_TAGS_TEMPLATE)
@ -439,16 +435,7 @@ class ELBV2Response(BaseResponse):
tag_keys = self._get_multi_param("TagKeys.member") tag_keys = self._get_multi_param("TagKeys.member")
for arn in resource_arns: for arn in resource_arns:
if ":targetgroup" in arn: resource = self._get_resource_by_arn(arn)
resource = self.elbv2_backend.target_groups.get(arn)
if not resource:
raise TargetGroupNotFoundError()
elif ":loadbalancer" in arn:
resource = self.elbv2_backend.load_balancers.get(arn)
if not resource:
raise LoadBalancerNotFoundError()
else:
raise LoadBalancerNotFoundError()
[resource.remove_tag(key) for key in tag_keys] [resource.remove_tag(key) for key in tag_keys]
template = self.response_template(REMOVE_TAGS_TEMPLATE) template = self.response_template(REMOVE_TAGS_TEMPLATE)
@ -459,45 +446,45 @@ class ELBV2Response(BaseResponse):
resource_arns = self._get_multi_param("ResourceArns.member") resource_arns = self._get_multi_param("ResourceArns.member")
resources = [] resources = []
for arn in resource_arns: for arn in resource_arns:
if ":targetgroup" in arn: resource = self._get_resource_by_arn(arn)
resource = self.elbv2_backend.target_groups.get(arn)
if not resource:
raise TargetGroupNotFoundError()
elif ":loadbalancer" in arn:
resource = self.elbv2_backend.load_balancers.get(arn)
if not resource:
raise LoadBalancerNotFoundError()
elif ":listener-rule" in arn:
lb_arn = arn.replace(":listener-rule", ":loadbalancer").rsplit("/", 2)[
0
]
balancer = self.elbv2_backend.load_balancers.get(lb_arn)
if not balancer:
raise LoadBalancerNotFoundError()
listener_arn = arn.replace(":listener-rule", ":listener").rsplit(
"/", 1
)[0]
listener = balancer.listeners.get(listener_arn)
if not listener:
raise ListenerNotFoundError()
resource = listener.rules.get(arn)
if not resource:
raise RuleNotFoundError()
elif ":listener" in arn:
lb_arn, _, _ = arn.replace(":listener", ":loadbalancer").rpartition("/")
balancer = self.elbv2_backend.load_balancers.get(lb_arn)
if not balancer:
raise LoadBalancerNotFoundError()
resource = balancer.listeners.get(arn)
if not resource:
raise ListenerNotFoundError()
else:
raise LoadBalancerNotFoundError()
resources.append(resource) resources.append(resource)
template = self.response_template(DESCRIBE_TAGS_TEMPLATE) template = self.response_template(DESCRIBE_TAGS_TEMPLATE)
return template.render(resources=resources) return template.render(resources=resources)
def _get_resource_by_arn(self, arn):
if ":targetgroup" in arn:
resource = self.elbv2_backend.target_groups.get(arn)
if not resource:
raise TargetGroupNotFoundError()
elif ":loadbalancer" in arn:
resource = self.elbv2_backend.load_balancers.get(arn)
if not resource:
raise LoadBalancerNotFoundError()
elif ":listener-rule" in arn:
lb_arn = arn.replace(":listener-rule", ":loadbalancer").rsplit("/", 2)[0]
balancer = self.elbv2_backend.load_balancers.get(lb_arn)
if not balancer:
raise LoadBalancerNotFoundError()
listener_arn = arn.replace(":listener-rule", ":listener").rsplit("/", 1)[0]
listener = balancer.listeners.get(listener_arn)
if not listener:
raise ListenerNotFoundError()
resource = listener.rules.get(arn)
if not resource:
raise RuleNotFoundError()
elif ":listener" in arn:
lb_arn, _, _ = arn.replace(":listener", ":loadbalancer").rpartition("/")
balancer = self.elbv2_backend.load_balancers.get(lb_arn)
if not balancer:
raise LoadBalancerNotFoundError()
resource = balancer.listeners.get(arn)
if not resource:
raise ListenerNotFoundError()
else:
raise LoadBalancerNotFoundError()
return resource
@amzn_request_id @amzn_request_id
def describe_account_limits(self): def describe_account_limits(self):
# Supports paging but not worth implementing yet # Supports paging but not worth implementing yet
@ -556,8 +543,9 @@ class ELBV2Response(BaseResponse):
def set_subnets(self): def set_subnets(self):
arn = self._get_param("LoadBalancerArn") arn = self._get_param("LoadBalancerArn")
subnets = self._get_multi_param("Subnets.member.") subnets = self._get_multi_param("Subnets.member.")
subnet_mappings = self._get_params().get("SubnetMappings", [])
subnet_zone_list = self.elbv2_backend.set_subnets(arn, subnets) subnet_zone_list = self.elbv2_backend.set_subnets(arn, subnets, subnet_mappings)
template = self.response_template(SET_SUBNETS_TEMPLATE) template = self.response_template(SET_SUBNETS_TEMPLATE)
return template.render(subnets=subnet_zone_list) return template.render(subnets=subnet_zone_list)
@ -638,6 +626,34 @@ class ELBV2Response(BaseResponse):
template = self.response_template(MODIFY_LISTENER_TEMPLATE) template = self.response_template(MODIFY_LISTENER_TEMPLATE)
return template.render(listener=listener) return template.render(listener=listener)
@amzn_request_id
def add_listener_certificates(self):
arn = self._get_param("ListenerArn")
certificates = self._get_list_prefix("Certificates.member")
certificates = self.elbv2_backend.add_listener_certificates(arn, certificates)
template = self.response_template(ADD_LISTENER_CERTIFICATES_TEMPLATE)
return template.render(certificates=certificates)
@amzn_request_id
def describe_listener_certificates(self):
arn = self._get_param("ListenerArn")
certificates = self.elbv2_backend.describe_listener_certificates(arn)
template = self.response_template(DESCRIBE_LISTENER_CERTIFICATES_TEMPLATE)
return template.render(certificates=certificates)
@amzn_request_id
def remove_listener_certificates(self):
arn = self._get_param("ListenerArn")
certificates = self._get_list_prefix("Certificates.member")
certificates = self.elbv2_backend.remove_listener_certificates(
arn, certificates
)
template = self.response_template(REMOVE_LISTENER_CERTIFICATES_TEMPLATE)
return template.render(certificates=certificates)
def _add_tags(self, resource): def _add_tags(self, resource):
tag_values = [] tag_values = []
tag_keys = [] tag_keys = []
@ -863,7 +879,7 @@ CREATE_TARGET_GROUP_TEMPLATE = """<CreateTargetGroupResponse xmlns="http://elast
<VpcId>{{ target_group.vpc_id }}</VpcId> <VpcId>{{ target_group.vpc_id }}</VpcId>
{% endif %} {% endif %}
<HealthCheckProtocol>{{ target_group.health_check_protocol }}</HealthCheckProtocol> <HealthCheckProtocol>{{ target_group.health_check_protocol }}</HealthCheckProtocol>
<HealthCheckPort>{{ target_group.healthcheck_port or '' }}</HealthCheckPort> {% if target_group.healthcheck_port %}<HealthCheckPort>{{ target_group.healthcheck_port }}</HealthCheckPort>{% endif %}
<HealthCheckPath>{{ target_group.healthcheck_path or '' }}</HealthCheckPath> <HealthCheckPath>{{ target_group.healthcheck_path or '' }}</HealthCheckPath>
<HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds> <HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds>
<HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds> <HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds>
@ -913,6 +929,11 @@ CREATE_LISTENER_TEMPLATE = """<CreateListenerResponse xmlns="http://elasticloadb
</member> </member>
{% endfor %} {% endfor %}
</DefaultActions> </DefaultActions>
<AlpnPolicy>
{% for policy in listener.alpn_policy %}
<member>{{ policy }}</member>
{% endfor %}
</AlpnPolicy>
</member> </member>
</Listeners> </Listeners>
</CreateListenerResult> </CreateListenerResult>
@ -1108,7 +1129,7 @@ DESCRIBE_TARGET_GROUPS_TEMPLATE = """<DescribeTargetGroupsResponse xmlns="http:/
<VpcId>{{ target_group.vpc_id }}</VpcId> <VpcId>{{ target_group.vpc_id }}</VpcId>
{% endif %} {% endif %}
<HealthCheckProtocol>{{ target_group.healthcheck_protocol }}</HealthCheckProtocol> <HealthCheckProtocol>{{ target_group.healthcheck_protocol }}</HealthCheckProtocol>
<HealthCheckPort>{{ target_group.healthcheck_port or '' }}</HealthCheckPort> {% if target_group.healthcheck_port %}<HealthCheckPort>{{ target_group.healthcheck_port }}</HealthCheckPort>{% endif %}
<HealthCheckPath>{{ target_group.healthcheck_path or '' }}</HealthCheckPath> <HealthCheckPath>{{ target_group.healthcheck_path or '' }}</HealthCheckPath>
<HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds> <HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds>
<HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds> <HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds>
@ -1167,7 +1188,7 @@ DESCRIBE_LISTENERS_TEMPLATE = """<DescribeListenersResponse xmlns="http://elasti
</member> </member>
</Certificates> </Certificates>
{% endif %} {% endif %}
<Port>{{ listener.port }}</Port> {% if listener.port %}<Port>{{ listener.port }}</Port>{% endif %}
<SslPolicy>{{ listener.ssl_policy }}</SslPolicy> <SslPolicy>{{ listener.ssl_policy }}</SslPolicy>
<ListenerArn>{{ listener.arn }}</ListenerArn> <ListenerArn>{{ listener.arn }}</ListenerArn>
<DefaultActions> <DefaultActions>
@ -1177,6 +1198,11 @@ DESCRIBE_LISTENERS_TEMPLATE = """<DescribeListenersResponse xmlns="http://elasti
</member> </member>
{% endfor %} {% endfor %}
</DefaultActions> </DefaultActions>
<AlpnPolicy>
{% for policy in listener.alpn_policy %}
<member>{{ policy }}</member>
{% endfor %}
</AlpnPolicy>
</member> </member>
{% endfor %} {% endfor %}
</Listeners> </Listeners>
@ -1437,7 +1463,7 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
<TargetHealthDescriptions> <TargetHealthDescriptions>
{% for target_health in target_health_descriptions %} {% for target_health in target_health_descriptions %}
<member> <member>
<HealthCheckPort>{{ target_health.health_port }}</HealthCheckPort> {% if target_health.health_port %}<HealthCheckPort>{{ target_health.health_port }}</HealthCheckPort>{% endif %}
<TargetHealth> <TargetHealth>
<State>{{ target_health.status }}</State> <State>{{ target_health.status }}</State>
{% if target_health.reason %} {% if target_health.reason %}
@ -1448,7 +1474,9 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
{% endif %} {% endif %}
</TargetHealth> </TargetHealth>
<Target> <Target>
{% if target_health.port %}
<Port>{{ target_health.port }}</Port> <Port>{{ target_health.port }}</Port>
{% endif %}
<Id>{{ target_health.instance_id }}</Id> <Id>{{ target_health.instance_id }}</Id>
</Target> </Target>
</member> </member>
@ -1631,18 +1659,20 @@ MODIFY_TARGET_GROUP_TEMPLATE = """<ModifyTargetGroupResponse xmlns="http://elast
<TargetGroupArn>{{ target_group.arn }}</TargetGroupArn> <TargetGroupArn>{{ target_group.arn }}</TargetGroupArn>
<TargetGroupName>{{ target_group.name }}</TargetGroupName> <TargetGroupName>{{ target_group.name }}</TargetGroupName>
<Protocol>{{ target_group.protocol }}</Protocol> <Protocol>{{ target_group.protocol }}</Protocol>
<Port>{{ target_group.port }}</Port> {% if target_group.port %}<Port>{{ target_group.port }}</Port>{% endif %}
<VpcId>{{ target_group.vpc_id }}</VpcId> <VpcId>{{ target_group.vpc_id }}</VpcId>
<HealthCheckProtocol>{{ target_group.healthcheck_protocol }}</HealthCheckProtocol> <HealthCheckProtocol>{{ target_group.healthcheck_protocol }}</HealthCheckProtocol>
<HealthCheckPort>{{ target_group.healthcheck_port }}</HealthCheckPort> {% if target_group.healthcheck_port %}<HealthCheckPort>{{ target_group.healthcheck_port }}</HealthCheckPort>{% endif %}
<HealthCheckPath>{{ target_group.healthcheck_path }}</HealthCheckPath> <HealthCheckPath>{{ target_group.healthcheck_path }}</HealthCheckPath>
<HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds> <HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds>
<HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds> <HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds>
<HealthyThresholdCount>{{ target_group.healthy_threshold_count }}</HealthyThresholdCount> <HealthyThresholdCount>{{ target_group.healthy_threshold_count }}</HealthyThresholdCount>
<UnhealthyThresholdCount>{{ target_group.unhealthy_threshold_count }}</UnhealthyThresholdCount> <UnhealthyThresholdCount>{{ target_group.unhealthy_threshold_count }}</UnhealthyThresholdCount>
{% if target_group.protocol in ["HTTP", "HTTPS"] %}
<Matcher> <Matcher>
<HttpCode>{{ target_group.matcher['HttpCode'] }}</HttpCode> <HttpCode>{{ target_group.matcher['HttpCode'] }}</HttpCode>
</Matcher> </Matcher>
{% endif %}
<LoadBalancerArns> <LoadBalancerArns>
{% for load_balancer_arn in target_group.load_balancer_arns %} {% for load_balancer_arn in target_group.load_balancer_arns %}
<member>{{ load_balancer_arn }}</member> <member>{{ load_balancer_arn }}</member>
@ -1688,3 +1718,40 @@ MODIFY_LISTENER_TEMPLATE = """<ModifyListenerResponse xmlns="http://elasticloadb
<RequestId>{{ request_id }}</RequestId> <RequestId>{{ request_id }}</RequestId>
</ResponseMetadata> </ResponseMetadata>
</ModifyListenerResponse>""" </ModifyListenerResponse>"""
ADD_LISTENER_CERTIFICATES_TEMPLATE = """<AddListenerCertificatesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<AddListenerCertificatesResult>
<Certificates>
{% for cert in certificates %}
<member>
<CertificateArn>{{ cert }}</CertificateArn>
</member>
{% endfor %}
</Certificates>
</AddListenerCertificatesResult>
<ResponseMetadata>
<RequestId>{{ request_id }}</RequestId>
</ResponseMetadata>
</AddListenerCertificatesResponse>"""
DESCRIBE_LISTENER_CERTIFICATES_TEMPLATE = """<DescribeListenerCertificatesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<DescribeListenerCertificatesResult>
<Certificates>
{% for cert in certificates %}
<member>
<CertificateArn>{{ cert }}</CertificateArn>
</member>
{% endfor %}
</Certificates>
</DescribeListenerCertificatesResult>
<ResponseMetadata>
<RequestId>{{ request_id }}</RequestId>
</ResponseMetadata>
</DescribeListenerCertificatesResponse>"""
REMOVE_LISTENER_CERTIFICATES_TEMPLATE = """<RemoveListenerCertificatesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
<RemoveListenerCertificatesResult />
<ResponseMetadata>
<RequestId>{{ request_id }}</RequestId>
</ResponseMetadata>
</RemoveListenerCertificatesResponse>"""

View File

@ -1,5 +1,5 @@
def make_arn_for_load_balancer(account_id, name, region_name): def make_arn_for_load_balancer(account_id, name, region_name):
return "arn:aws:elasticloadbalancing:{}:{}:loadbalancer/{}/50dc6c495c0c9188".format( return "arn:aws:elasticloadbalancing:{}:{}:loadbalancer/app/{}/50dc6c495c0c9188".format(
region_name, account_id, name region_name, account_id, name
) )

View File

@ -829,6 +829,8 @@ class InstanceProfile(CloudFormationModel):
class Certificate(BaseModel): class Certificate(BaseModel):
def __init__(self, cert_name, cert_body, private_key, cert_chain=None, path=None): def __init__(self, cert_name, cert_body, private_key, cert_chain=None, path=None):
self.cert_name = cert_name self.cert_name = cert_name
if cert_body:
cert_body = cert_body.rstrip()
self.cert_body = cert_body self.cert_body = cert_body
self.private_key = private_key self.private_key = private_key
self.path = path if path else "/" self.path = path if path else "/"

View File

@ -1,55 +0,0 @@
# Copyright (c) 2010 Reza Lotun http://reza.lotun.name
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
class AppCookieStickinessPolicy(object):
def __init__(self, connection=None):
self.cookie_name = None
self.policy_name = None
def __repr__(self):
return "AppCookieStickiness(%s, %s)" % (self.policy_name, self.cookie_name)
class OtherPolicy(object):
def __init__(self, connection=None):
self.policy_name = None
def __repr__(self):
return "OtherPolicy(%s)" % (self.policy_name)
class Policies(object):
"""
ELB Policies
"""
def __init__(self, connection=None):
self.connection = connection
self.app_cookie_stickiness_policies = None
self.lb_cookie_stickiness_policies = None
self.other_policies = None
def __repr__(self):
app = "AppCookieStickiness%s" % self.app_cookie_stickiness_policies
lb = "LBCookieStickiness%s" % self.lb_cookie_stickiness_policies
other = "Other%s" % self.other_policies
return "Policies(%s,%s,%s)" % (app, lb, other)

View File

@ -73,6 +73,7 @@ TestAccAWSEFSAccessPoint
TestAccAWSEFSMountTarget TestAccAWSEFSMountTarget
TestAccAWSEgressOnlyInternetGateway TestAccAWSEgressOnlyInternetGateway
TestAccAWSElasticBeanstalkSolutionStackDataSource TestAccAWSElasticBeanstalkSolutionStackDataSource
TestAccAWSELBAttachment
TestAccAWSElbHostedZoneId TestAccAWSElbHostedZoneId
TestAccAWSElbServiceAccount TestAccAWSElbServiceAccount
TestAccAWSENI_basic TestAccAWSENI_basic
@ -98,6 +99,12 @@ TestAccAWSIPRanges
TestAccAWSKinesisStream TestAccAWSKinesisStream
TestAccAWSKmsAlias TestAccAWSKmsAlias
TestAccAWSKmsSecretDataSource TestAccAWSKmsSecretDataSource
TestAccAwsLbListenerCertificate
TestAccAWSLBSSLNegotiationPolicy
TestAccAWSLBTargetGroupAttachment
TestAccAWSLoadBalancerBackendServerPolicy
TestAccAWSLoadBalancerListenerPolicy
TestAccAWSLoadBalancerPolicy
TestAccAWSLambdaAlias TestAccAWSLambdaAlias
TestAccAWSLambdaLayerVersion TestAccAWSLambdaLayerVersion
TestAccAWSMq TestAccAWSMq
@ -138,4 +145,5 @@ TestAccDataSourceAwsEfsMountTarget
TestAccDataSourceAWSLambdaLayerVersion TestAccDataSourceAWSLambdaLayerVersion
TestAccDataSourceAwsLambdaInvocation TestAccDataSourceAwsLambdaInvocation
TestAccDataSourceAwsNetworkInterface_ TestAccDataSourceAwsNetworkInterface_
TestAccDataSourceAWSELB
TestValidateSSMDocumentPermissions TestValidateSSMDocumentPermissions

View File

@ -953,7 +953,8 @@ def test_stack_elbv2_resources_integration():
"TargetGroupArn": target_groups[0]["TargetGroupArn"], "TargetGroupArn": target_groups[0]["TargetGroupArn"],
"Weight": 2, "Weight": 2,
}, },
] ],
"TargetGroupStickinessConfig": {"Enabled": False},
}, },
} }
], ],

View File

@ -4,23 +4,18 @@ from botocore.exceptions import ClientError
import pytest import pytest
import sure # noqa # pylint: disable=unused-import import sure # noqa # pylint: disable=unused-import
from moto import mock_acm, mock_elb, mock_ec2 from moto import mock_acm, mock_elb, mock_ec2, mock_iam
from moto.core import ACCOUNT_ID
from tests import EXAMPLE_AMI_ID from tests import EXAMPLE_AMI_ID
from uuid import uuid4 from uuid import uuid4
@pytest.mark.parametrize("region_name", ["us-east-1", "ap-south-1"]) @pytest.mark.parametrize("region_name", ["us-east-1", "ap-south-1"])
@pytest.mark.parametrize( @pytest.mark.parametrize("zones", [["a"], ["a", "b"]])
"zones",
[
["us-east-1a"],
["us-east-1a", "us-east-1b"],
["eu-north-1a", "eu-north-1b", "eu-north-1c"],
],
)
@mock_elb @mock_elb
@mock_ec2 @mock_ec2
def test_create_load_balancer_boto3(zones, region_name): def test_create_load_balancer(zones, region_name):
zones = [f"{region_name}{z}" for z in zones]
# Both regions and availability zones are parametrized # Both regions and availability zones are parametrized
# This does not seem to have an effect on the DNS name # This does not seem to have an effect on the DNS name
client = boto3.client("elb", region_name=region_name) client = boto3.client("elb", region_name=region_name)
@ -52,6 +47,7 @@ def test_create_load_balancer_boto3(zones, region_name):
) )
describe.should.have.key("AvailabilityZones").equal(zones) describe.should.have.key("AvailabilityZones").equal(zones)
describe.should.have.key("VPCId") describe.should.have.key("VPCId")
describe.should.have.key("Subnets").length_of(zones) # Default subnet for each zone
describe.should.have.key("SecurityGroups").equal([security_group.id]) describe.should.have.key("SecurityGroups").equal([security_group.id])
describe.should.have.key("Scheme").equal("internal") describe.should.have.key("Scheme").equal("internal")
@ -89,7 +85,7 @@ def test_create_load_balancer_boto3(zones, region_name):
@mock_elb @mock_elb
def test_get_missing_elb_boto3(): def test_get_missing_elb():
client = boto3.client("elb", region_name="us-west-2") client = boto3.client("elb", region_name="us-west-2")
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.describe_load_balancers(LoadBalancerNames=["unknown-lb"]) client.describe_load_balancers(LoadBalancerNames=["unknown-lb"])
@ -101,7 +97,7 @@ def test_get_missing_elb_boto3():
@mock_elb @mock_elb
def test_create_elb_in_multiple_region_boto3(): def test_create_elb_in_multiple_region():
client_east = boto3.client("elb", region_name="us-east-2") client_east = boto3.client("elb", region_name="us-east-2")
client_west = boto3.client("elb", region_name="us-west-2") client_west = boto3.client("elb", region_name="us-west-2")
@ -111,12 +107,12 @@ def test_create_elb_in_multiple_region_boto3():
client_east.create_load_balancer( client_east.create_load_balancer(
LoadBalancerName=name_east, LoadBalancerName=name_east,
Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}], Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"], AvailabilityZones=["us-east-2a"],
) )
client_west.create_load_balancer( client_west.create_load_balancer(
LoadBalancerName=name_west, LoadBalancerName=name_west,
Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}], Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"], AvailabilityZones=["us-west-2a"],
) )
east_names = [ east_names = [
@ -136,7 +132,7 @@ def test_create_elb_in_multiple_region_boto3():
@mock_acm @mock_acm
@mock_elb @mock_elb
def test_create_load_balancer_with_certificate_boto3(): def test_create_load_balancer_with_certificate():
acm_client = boto3.client("acm", region_name="us-east-2") acm_client = boto3.client("acm", region_name="us-east-2")
acm_request_response = acm_client.request_certificate( acm_request_response = acm_client.request_certificate(
DomainName="fake.domain.com", DomainName="fake.domain.com",
@ -160,7 +156,7 @@ def test_create_load_balancer_with_certificate_boto3():
"SSLCertificateId": certificate_arn, "SSLCertificateId": certificate_arn,
} }
], ],
AvailabilityZones=["us-east-1a"], AvailabilityZones=["us-east-2a"],
) )
describe = client.describe_load_balancers(LoadBalancerNames=[name])[ describe = client.describe_load_balancers(LoadBalancerNames=[name])[
"LoadBalancerDescriptions" "LoadBalancerDescriptions"
@ -189,14 +185,14 @@ def test_create_load_balancer_with_invalid_certificate():
"SSLCertificateId": "invalid_arn", "SSLCertificateId": "invalid_arn",
} }
], ],
AvailabilityZones=["us-east-1a"], AvailabilityZones=["us-east-2a"],
) )
err = exc.value.response["Error"] err = exc.value.response["Error"]
err["Code"].should.equal("CertificateNotFoundException") err["Code"].should.equal("CertificateNotFoundException")
@mock_elb @mock_elb
def test_create_and_delete_boto3_support(): def test_create_and_delete_load_balancer():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer( client.create_load_balancer(
@ -226,6 +222,26 @@ def test_create_load_balancer_with_no_listeners_defined():
) )
@mock_ec2
@mock_elb
def test_create_load_balancer_without_security_groups():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
ec2 = boto3.client("ec2", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
AvailabilityZones=["us-east-1a"],
Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}],
)
describe = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
describe.should.have.key("SecurityGroups").length_of(1)
sec_group_id = describe["SecurityGroups"][0]
sg = ec2.describe_security_groups(GroupIds=[sec_group_id])["SecurityGroups"][0]
assert sg["GroupName"].startswith("default_elb_")
@mock_elb @mock_elb
def test_describe_paginated_balancers(): def test_describe_paginated_balancers():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -285,7 +301,7 @@ def test_apply_security_groups_to_load_balancer():
@mock_elb @mock_elb
def test_create_and_delete_listener_boto3_support(): def test_create_and_delete_listener():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer( client.create_load_balancer(
@ -312,15 +328,6 @@ def test_create_and_delete_listener_boto3_support():
) )
balancer["ListenerDescriptions"][1]["Listener"]["InstancePort"].should.equal(8443) balancer["ListenerDescriptions"][1]["Listener"]["InstancePort"].should.equal(8443)
# Creating this listener with an conflicting definition throws error
with pytest.raises(ClientError):
client.create_load_balancer_listeners(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 443, "InstancePort": 1234}
],
)
client.delete_load_balancer_listeners( client.delete_load_balancer_listeners(
LoadBalancerName="my-lb", LoadBalancerPorts=[443] LoadBalancerName="my-lb", LoadBalancerPorts=[443]
) )
@ -329,9 +336,59 @@ def test_create_and_delete_listener_boto3_support():
list(balancer["ListenerDescriptions"]).should.have.length_of(1) list(balancer["ListenerDescriptions"]).should.have.length_of(1)
@mock_elb
@pytest.mark.parametrize("first,second", [["tcp", "http"], ["http", "TCP"]])
def test_create_duplicate_listener_different_protocols(first, second):
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": first, "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a", "us-east-1b"],
)
# Creating this listener with an conflicting definition throws error
with pytest.raises(ClientError) as exc:
client.create_load_balancer_listeners(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": second, "LoadBalancerPort": 80, "InstancePort": 8080}
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("DuplicateListener")
err["Message"].should.equal(
"A listener already exists for my-lb with LoadBalancerPort 80, but with a different InstancePort, Protocol, or SSLCertificateId"
)
@mock_elb
@pytest.mark.parametrize(
"first,second", [["tcp", "tcp"], ["tcp", "TcP"], ["http", "HTTP"]]
)
def test_create_duplicate_listener_same_details(first, second):
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": first, "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a", "us-east-1b"],
)
# Creating this listener with the same definition succeeds
client.create_load_balancer_listeners(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": second, "LoadBalancerPort": 80, "InstancePort": 8080}],
)
# We still only have one though
balancer = client.describe_load_balancers()["LoadBalancerDescriptions"][0]
list(balancer["ListenerDescriptions"]).should.have.length_of(1)
@mock_acm @mock_acm
@mock_elb @mock_elb
def test_create_lb_listener_with_ssl_certificate(): def test_create_lb_listener_with_ssl_certificate_from_acm():
acm_client = boto3.client("acm", region_name="eu-west-1") acm_client = boto3.client("acm", region_name="eu-west-1")
acm_request_response = acm_client.request_certificate( acm_request_response = acm_client.request_certificate(
DomainName="fake.domain.com", DomainName="fake.domain.com",
@ -346,7 +403,49 @@ def test_create_lb_listener_with_ssl_certificate():
client.create_load_balancer( client.create_load_balancer(
LoadBalancerName="my-lb", LoadBalancerName="my-lb",
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}], Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a", "us-east-1b"], AvailabilityZones=["eu-west-1a", "eu-west-1b"],
)
client.create_load_balancer_listeners(
LoadBalancerName="my-lb",
Listeners=[
{
"Protocol": "tcp",
"LoadBalancerPort": 443,
"InstancePort": 8443,
"SSLCertificateId": certificate_arn,
}
],
)
balancer = client.describe_load_balancers()["LoadBalancerDescriptions"][0]
listeners = balancer["ListenerDescriptions"]
listeners.should.have.length_of(2)
listeners[0]["Listener"]["Protocol"].should.equal("HTTP")
listeners[0]["Listener"]["SSLCertificateId"].should.equal("None")
listeners[1]["Listener"]["Protocol"].should.equal("TCP")
listeners[1]["Listener"]["SSLCertificateId"].should.equal(certificate_arn)
@mock_iam
@mock_elb
def test_create_lb_listener_with_ssl_certificate_from_iam():
iam_client = boto3.client("iam", region_name="eu-west-2")
iam_cert_response = iam_client.upload_server_certificate(
ServerCertificateName="test-cert",
CertificateBody="cert-body",
PrivateKey="private-key",
)
print(iam_cert_response)
certificate_arn = iam_cert_response["ServerCertificateMetadata"]["Arn"]
client = boto3.client("elb", region_name="eu-west-1")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["eu-west-1a", "eu-west-1b"],
) )
client.create_load_balancer_listeners( client.create_load_balancer_listeners(
@ -379,7 +478,7 @@ def test_create_lb_listener_with_invalid_ssl_certificate():
client.create_load_balancer( client.create_load_balancer(
LoadBalancerName="my-lb", LoadBalancerName="my-lb",
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}], Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a", "us-east-1b"], AvailabilityZones=["eu-west-1a", "eu-west-1b"],
) )
with pytest.raises(ClientError) as exc: with pytest.raises(ClientError) as exc:
@ -400,7 +499,7 @@ def test_create_lb_listener_with_invalid_ssl_certificate():
@mock_acm @mock_acm
@mock_elb @mock_elb
def test_set_sslcertificate_boto3(): def test_set_sslcertificate():
acm_client = boto3.client("acm", region_name="us-east-1") acm_client = boto3.client("acm", region_name="us-east-1")
acm_request_response = acm_client.request_certificate( acm_request_response = acm_client.request_certificate(
DomainName="fake.domain.com", DomainName="fake.domain.com",
@ -438,7 +537,7 @@ def test_set_sslcertificate_boto3():
@mock_elb @mock_elb
def test_get_load_balancers_by_name_boto3(): def test_get_load_balancers_by_name():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
lb_name1 = str(uuid4())[0:6] lb_name1 = str(uuid4())[0:6]
lb_name2 = str(uuid4())[0:6] lb_name2 = str(uuid4())[0:6]
@ -481,7 +580,7 @@ def test_get_load_balancers_by_name_boto3():
@mock_elb @mock_elb
def test_delete_load_balancer_boto3(): def test_delete_load_balancer():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
lb_name1 = str(uuid4())[0:6] lb_name1 = str(uuid4())[0:6]
lb_name2 = str(uuid4())[0:6] lb_name2 = str(uuid4())[0:6]
@ -512,7 +611,7 @@ def test_delete_load_balancer_boto3():
@mock_elb @mock_elb
def test_create_health_check_boto3(): def test_create_health_check():
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer( client.create_load_balancer(
@ -541,7 +640,7 @@ def test_create_health_check_boto3():
@mock_ec2 @mock_ec2
@mock_elb @mock_elb
def test_register_instances_boto3(): def test_register_instances():
ec2 = boto3.resource("ec2", region_name="us-east-1") ec2 = boto3.resource("ec2", region_name="us-east-1")
response = ec2.create_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2) response = ec2.create_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2)
instance_id1 = response[0].id instance_id1 = response[0].id
@ -564,7 +663,7 @@ def test_register_instances_boto3():
@mock_ec2 @mock_ec2
@mock_elb @mock_elb
def test_deregister_instances_boto3(): def test_deregister_instances():
ec2 = boto3.resource("ec2", region_name="us-east-1") ec2 = boto3.resource("ec2", region_name="us-east-1")
response = ec2.create_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2) response = ec2.create_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2)
instance_id1 = response[0].id instance_id1 = response[0].id
@ -594,7 +693,7 @@ def test_deregister_instances_boto3():
@mock_elb @mock_elb
def test_default_attributes_boto3(): def test_default_attributes():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -614,7 +713,7 @@ def test_default_attributes_boto3():
@mock_elb @mock_elb
def test_cross_zone_load_balancing_attribute_boto3(): def test_cross_zone_load_balancing_attribute():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -649,7 +748,7 @@ def test_cross_zone_load_balancing_attribute_boto3():
@mock_elb @mock_elb
def test_connection_draining_attribute_boto3(): def test_connection_draining_attribute():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -679,11 +778,13 @@ def test_connection_draining_attribute_boto3():
attributes = client.describe_load_balancer_attributes(LoadBalancerName=lb_name)[ attributes = client.describe_load_balancer_attributes(LoadBalancerName=lb_name)[
"LoadBalancerAttributes" "LoadBalancerAttributes"
] ]
attributes.should.have.key("ConnectionDraining").equal({"Enabled": False}) attributes.should.have.key("ConnectionDraining").equal(
{"Enabled": False, "Timeout": 300}
)
@mock_elb @mock_elb
def test_access_log_attribute_boto3(): def test_access_log_attribute():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -737,7 +838,7 @@ def test_access_log_attribute_boto3():
@mock_elb @mock_elb
def test_connection_settings_attribute_boto3(): def test_connection_settings_attribute():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
@ -765,196 +866,9 @@ def test_connection_settings_attribute_boto3():
conn_settings.should.equal({"IdleTimeout": 123}) conn_settings.should.equal({"IdleTimeout": 123})
@mock_elb
def test_create_lb_cookie_stickiness_policy_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_lb_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieExpirationPeriod=42
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"PolicyName": "pname", "CookieExpirationPeriod": 42})
@mock_elb
def test_create_lb_cookie_stickiness_policy_no_expiry_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_lb_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname"
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"PolicyName": "pname"})
@mock_elb
def test_create_app_cookie_stickiness_policy_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["AppCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["AppCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"CookieName": "cname", "PolicyName": "pname"})
@mock_elb
def test_create_lb_policy_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="ProxyPolicy",
PolicyTypeName="ProxyProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "ProxyProtocol", "AttributeValue": "true"}],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
policies.should.have.key("OtherPolicies").equal(["ProxyPolicy"])
@mock_elb
def test_set_policies_of_listener_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[
{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 81, "InstancePort": 8081},
],
AvailabilityZones=["us-east-1a"],
)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
client.set_load_balancer_policies_of_listener(
LoadBalancerName=lb_name, LoadBalancerPort=81, PolicyNames=["pname"]
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
http_l = [
l
for l in balancer["ListenerDescriptions"]
if l["Listener"]["Protocol"] == "HTTP"
][0]
http_l.should.have.key("PolicyNames").should.equal([])
https_l = [
l
for l in balancer["ListenerDescriptions"]
if l["Listener"]["Protocol"] == "HTTPS"
][0]
https_l.should.have.key("PolicyNames").should.equal(["pname"])
@mock_elb
def test_set_policies_of_backend_server_boto3():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[
{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 81, "InstancePort": 8081},
],
AvailabilityZones=["us-east-1a"],
)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
client.set_load_balancer_policies_for_backend_server(
LoadBalancerName=lb_name, InstancePort=8081, PolicyNames=["pname"]
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
balancer.should.have.key("BackendServerDescriptions")
desc = balancer["BackendServerDescriptions"]
desc.should.have.length_of(1)
desc[0].should.equal({"InstancePort": 8081, "PolicyNames": ["pname"]})
@mock_ec2 @mock_ec2
@mock_elb @mock_elb
def test_describe_instance_health_boto3(): def test_describe_instance_health():
elb = boto3.client("elb", region_name="us-east-1") elb = boto3.client("elb", region_name="us-east-1")
ec2 = boto3.client("ec2", region_name="us-east-1") ec2 = boto3.client("ec2", region_name="us-east-1")
instances = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2)[ instances = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2)[
@ -1173,14 +1087,18 @@ def test_subnets():
) )
lb = client.describe_load_balancers()["LoadBalancerDescriptions"][0] lb = client.describe_load_balancers()["LoadBalancerDescriptions"][0]
lb.should.have.key("Subnets").which.should.have.length_of(1) lb.should.have.key("Subnets").which.should.have.length_of(1)
lb["Subnets"][0].should.equal(subnet.id) lb["Subnets"][0].should.equal(subnet.id)
lb.should.have.key("VPCId").which.should.equal(vpc.id) lb.should.have.key("VPCId").which.should.equal(vpc.id)
lb.should.have.key("SourceSecurityGroup").equals(
{"OwnerAlias": f"{ACCOUNT_ID}", "GroupName": "default"}
)
@mock_elb @mock_elb
def test_create_load_balancer_duplicate_boto3(): def test_create_load_balancer_duplicate():
lb_name = str(uuid4())[0:6] lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1") client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer( client.create_load_balancer(

View File

@ -0,0 +1,55 @@
import boto3
import sure # noqa # pylint: disable=unused-import
from moto import mock_elb, mock_ec2
@mock_elb
@mock_ec2
def test_enable_and_disable_availability_zones():
client = boto3.client("elb", region_name="eu-north-1")
ec2 = boto3.resource("ec2", region_name="eu-north-1")
security_group = ec2.create_security_group(GroupName="sg01", Description="desc")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=["eu-north-1a", "eu-north-1b"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
describe = client.describe_load_balancers(LoadBalancerNames=["my-lb"])[
"LoadBalancerDescriptions"
][0]
describe["AvailabilityZones"].should.equal(["eu-north-1a", "eu-north-1b"])
# enable more az's
resp = client.enable_availability_zones_for_load_balancer(
LoadBalancerName="my-lb", AvailabilityZones=["eu-north-1c", "eu-north-1d"]
)
resp.should.have.key("AvailabilityZones").equals(
["eu-north-1a", "eu-north-1b", "eu-north-1c", "eu-north-1d"]
)
describe = client.describe_load_balancers(LoadBalancerNames=["my-lb"])[
"LoadBalancerDescriptions"
][0]
describe["AvailabilityZones"].should.equal(
["eu-north-1a", "eu-north-1b", "eu-north-1c", "eu-north-1d"]
)
# disable some az's
resp = client.disable_availability_zones_for_load_balancer(
LoadBalancerName="my-lb", AvailabilityZones=["eu-north-1b", "eu-north-1c"]
)
resp.should.have.key("AvailabilityZones").equals(["eu-north-1a", "eu-north-1d"])
describe = client.describe_load_balancers(LoadBalancerNames=["my-lb"])[
"LoadBalancerDescriptions"
][0]
describe["AvailabilityZones"].should.equal(["eu-north-1a", "eu-north-1d"])

View File

@ -18,7 +18,7 @@ def test_stack_elb_integration_with_attached_ec2_instances():
"Properties": { "Properties": {
"Instances": [{"Ref": "Ec2Instance1"}], "Instances": [{"Ref": "Ec2Instance1"}],
"LoadBalancerName": "test-elb", "LoadBalancerName": "test-elb",
"AvailabilityZones": ["us-east-1"], "AvailabilityZones": ["us-west-1a"],
"Listeners": [ "Listeners": [
{ {
"InstancePort": "80", "InstancePort": "80",
@ -47,7 +47,7 @@ def test_stack_elb_integration_with_attached_ec2_instances():
ec2_instance = reservations["Instances"][0] ec2_instance = reservations["Instances"][0]
load_balancer["Instances"][0]["InstanceId"].should.equal(ec2_instance["InstanceId"]) load_balancer["Instances"][0]["InstanceId"].should.equal(ec2_instance["InstanceId"])
load_balancer["AvailabilityZones"].should.equal(["us-east-1"]) load_balancer["AvailabilityZones"].should.equal(["us-west-1a"])
@mock_elb @mock_elb
@ -60,7 +60,7 @@ def test_stack_elb_integration_with_health_check():
"Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": { "Properties": {
"LoadBalancerName": "test-elb", "LoadBalancerName": "test-elb",
"AvailabilityZones": ["us-west-1"], "AvailabilityZones": ["us-west-1b"],
"HealthCheck": { "HealthCheck": {
"HealthyThreshold": "3", "HealthyThreshold": "3",
"Interval": "5", "Interval": "5",

View File

@ -0,0 +1,304 @@
import boto3
from botocore.exceptions import ClientError
import pytest
import sure # noqa # pylint: disable=unused-import
from moto import mock_elb
from uuid import uuid4
@mock_elb
def test_create_lb_cookie_stickiness_policy():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_lb_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieExpirationPeriod=42
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"PolicyName": "pname", "CookieExpirationPeriod": 42})
@mock_elb
def test_create_lb_cookie_stickiness_policy_no_expiry():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_lb_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname"
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["LBCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"PolicyName": "pname"})
@mock_elb
def test_create_app_cookie_stickiness_policy():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
lbc_policies = balancer["Policies"]["AppCookieStickinessPolicies"]
lbc_policies.should.have.length_of(0)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
lbc_policies = policies["AppCookieStickinessPolicies"]
lbc_policies.should.have.length_of(1)
lbc_policies[0].should.equal({"CookieName": "cname", "PolicyName": "pname"})
@mock_elb
def test_create_lb_policy():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="ProxyPolicy",
PolicyTypeName="ProxyProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "ProxyProtocol", "AttributeValue": "true"}],
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
policies = balancer["Policies"]
policies.should.have.key("OtherPolicies").equal(["ProxyPolicy"])
@mock_elb
def test_set_policies_of_listener():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[
{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 81, "InstancePort": 8081},
],
AvailabilityZones=["us-east-1a"],
)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
client.set_load_balancer_policies_of_listener(
LoadBalancerName=lb_name, LoadBalancerPort=81, PolicyNames=["pname"]
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
http_l = [
l
for l in balancer["ListenerDescriptions"]
if l["Listener"]["Protocol"] == "HTTP"
][0]
http_l.should.have.key("PolicyNames").should.equal([])
https_l = [
l
for l in balancer["ListenerDescriptions"]
if l["Listener"]["Protocol"] == "HTTPS"
][0]
https_l.should.have.key("PolicyNames").should.equal(["pname"])
@mock_elb
def test_set_policies_of_backend_server():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[
{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 81, "InstancePort": 8081},
],
AvailabilityZones=["us-east-1a"],
)
client.create_app_cookie_stickiness_policy(
LoadBalancerName=lb_name, PolicyName="pname", CookieName="cname"
)
client.set_load_balancer_policies_for_backend_server(
LoadBalancerName=lb_name, InstancePort=8081, PolicyNames=["pname"]
)
balancer = client.describe_load_balancers(LoadBalancerNames=[lb_name])[
"LoadBalancerDescriptions"
][0]
balancer.should.have.key("BackendServerDescriptions")
desc = balancer["BackendServerDescriptions"]
desc.should.have.length_of(1)
desc[0].should.equal({"InstancePort": 8081, "PolicyNames": ["pname"]})
@mock_elb
def test_describe_load_balancer_policies__initial():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
resp = client.describe_load_balancer_policies(LoadBalancerName=lb_name)
resp.should.have.key("PolicyDescriptions").equals([])
@mock_elb
def test_describe_load_balancer_policies():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="ProxyPolicy",
PolicyTypeName="ProxyProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "ProxyProtocol", "AttributeValue": "true"}],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="DifferentPolicy",
PolicyTypeName="DifferentProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "DiffProtocol", "AttributeValue": "true"}],
)
resp = client.describe_load_balancer_policies(LoadBalancerName=lb_name)
resp.should.have.key("PolicyDescriptions").length_of(2)
resp = client.describe_load_balancer_policies(
LoadBalancerName=lb_name, PolicyNames=["DifferentPolicy"]
)
resp.should.have.key("PolicyDescriptions").length_of(1)
resp["PolicyDescriptions"][0].should.equal(
{
"PolicyName": "DifferentPolicy",
"PolicyTypeName": "DifferentProtocolPolicyType",
"PolicyAttributeDescriptions": [
{"AttributeName": "DiffProtocol", "AttributeValue": "true"}
],
}
)
@mock_elb
def test_describe_unknown_load_balancer_policy():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
with pytest.raises(ClientError) as exc:
client.describe_load_balancer_policies(
LoadBalancerName=lb_name, PolicyNames=["unknown"]
)
err = exc.value.response["Error"]
err["Code"].should.equal("PolicyNotFound")
@mock_elb
def test_delete_load_balancer_policies():
lb_name = str(uuid4())[0:6]
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName=lb_name,
Listeners=[{"Protocol": "http", "LoadBalancerPort": 80, "InstancePort": 8080}],
AvailabilityZones=["us-east-1a"],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="ProxyPolicy",
PolicyTypeName="ProxyProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "ProxyProtocol", "AttributeValue": "true"}],
)
client.create_load_balancer_policy(
LoadBalancerName=lb_name,
PolicyName="DifferentPolicy",
PolicyTypeName="DifferentProtocolPolicyType",
PolicyAttributes=[{"AttributeName": "DiffProtocol", "AttributeValue": "true"}],
)
client.delete_load_balancer_policy(
LoadBalancerName=lb_name, PolicyName="ProxyPolicy"
)
resp = client.describe_load_balancer_policies(LoadBalancerName=lb_name)
resp.should.have.key("PolicyDescriptions").length_of(1)

View File

@ -0,0 +1,53 @@
import boto3
import sure # noqa # pylint: disable=unused-import
from moto import mock_ec2, mock_elb
@mock_ec2
@mock_elb
def test_elb_attach_load_balancer_to_subnets():
ec2 = boto3.resource("ec2", region_name="us-east-1")
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")
subnet2 = ec2.create_subnet(VpcId=vpc.id, CidrBlock="172.28.7.191/26")
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}],
Subnets=[subnet1.id],
)
client.attach_load_balancer_to_subnets(
LoadBalancerName="my-lb", Subnets=[subnet2.id]
)
lb = client.describe_load_balancers()["LoadBalancerDescriptions"][0]
lb.should.have.key("Subnets").which.should.have.length_of(2)
lb["Subnets"].should.contain(subnet1.id)
lb["Subnets"].should.contain(subnet2.id)
@mock_ec2
@mock_elb
def test_elb_detach_load_balancer_to_subnets():
ec2 = boto3.resource("ec2", region_name="us-east-1")
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")
subnet2 = ec2.create_subnet(VpcId=vpc.id, CidrBlock="172.28.7.191/26")
client = boto3.client("elb", region_name="us-east-1")
client.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}],
Subnets=[subnet1.id, subnet2.id],
)
client.detach_load_balancer_from_subnets(
LoadBalancerName="my-lb", Subnets=[subnet1.id]
)
lb = client.describe_load_balancers()["LoadBalancerDescriptions"][0]
lb.should.have.key("Subnets").which.should.have.length_of(1)
lb["Subnets"].should.contain(subnet2.id)

View File

@ -1,3 +1,4 @@
import copy
import os import os
import boto3 import boto3
import botocore import botocore
@ -19,7 +20,7 @@ def test_create_load_balancer():
lb = response.get("LoadBalancers")[0] lb = response.get("LoadBalancers")[0]
lb.get("DNSName").should.equal("my-lb-1.us-east-1.elb.amazonaws.com") lb.get("DNSName").should.equal("my-lb-1.us-east-1.elb.amazonaws.com")
lb.get("LoadBalancerArn").should.equal( lb.get("LoadBalancerArn").should.equal(
f"arn:aws:elasticloadbalancing:us-east-1:{ACCOUNT_ID}:loadbalancer/my-lb/50dc6c495c0c9188" f"arn:aws:elasticloadbalancing:us-east-1:{ACCOUNT_ID}:loadbalancer/app/my-lb/50dc6c495c0c9188"
) )
lb.get("SecurityGroups").should.equal([security_group.id]) lb.get("SecurityGroups").should.equal([security_group.id])
lb.get("AvailabilityZones").should.equal( lb.get("AvailabilityZones").should.equal(
@ -62,6 +63,42 @@ def create_load_balancer():
return response, vpc, security_group, subnet1, subnet2, conn return response, vpc, security_group, subnet1, subnet2, conn
@mock_elbv2
@mock_ec2
def test_create_elb_using_subnetmapping():
region = "us-west-1"
conn = boto3.client("elbv2", region_name=region)
ec2 = boto3.resource("ec2", region_name=region)
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.0/26", AvailabilityZone=region + "a"
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone=region + "b"
)
conn.create_load_balancer(
Name="my-lb",
SubnetMappings=[{"SubnetId": subnet1.id}, {"SubnetId": subnet2.id}],
SecurityGroups=[security_group.id],
Scheme="internal",
Tags=[{"Key": "key_name", "Value": "a_value"}],
)
lb = conn.describe_load_balancers()["LoadBalancers"][0]
lb.should.have.key("AvailabilityZones").length_of(2)
lb["AvailabilityZones"].should.contain(
{"ZoneName": "us-west-1a", "SubnetId": subnet1.id}
)
lb["AvailabilityZones"].should.contain(
{"ZoneName": "us-west-1b", "SubnetId": subnet2.id}
)
@mock_elbv2 @mock_elbv2
@mock_ec2 @mock_ec2
def test_describe_load_balancers(): def test_describe_load_balancers():
@ -330,9 +367,11 @@ def test_create_rule_forward_config_as_second_arg():
forward_action.should.equal( forward_action.should.equal(
{ {
"ForwardConfig": { "ForwardConfig": {
"TargetGroups": [{"TargetGroupArn": target_group_arn, "Weight": 1}] "TargetGroups": [{"TargetGroupArn": target_group_arn, "Weight": 1}],
"TargetGroupStickinessConfig": {"Enabled": False},
}, },
"Type": "forward", "Type": "forward",
"Order": 2,
} }
) )
@ -1142,57 +1181,6 @@ def test_set_security_groups():
client.set_security_groups(LoadBalancerArn=arn, SecurityGroups=["non_existent"]) client.set_security_groups(LoadBalancerArn=arn, SecurityGroups=["non_existent"])
@mock_elbv2
@mock_ec2
def test_set_subnets_errors():
client = 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.0/26", AvailabilityZone="us-east-1a"
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.64/26", AvailabilityZone="us-east-1b"
)
subnet3 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone="us-east-1c"
)
response = client.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme="internal",
Tags=[{"Key": "key_name", "Value": "a_value"}],
)
arn = response["LoadBalancers"][0]["LoadBalancerArn"]
client.set_subnets(
LoadBalancerArn=arn, Subnets=[subnet1.id, subnet2.id, subnet3.id]
)
resp = client.describe_load_balancers(LoadBalancerArns=[arn])
len(resp["LoadBalancers"][0]["AvailabilityZones"]).should.equal(3)
# Only 1 AZ
with pytest.raises(ClientError) as ex:
client.set_subnets(LoadBalancerArn=arn, Subnets=[subnet1.id])
err = ex.value.response["Error"]
err["Message"].should.equal("More than 1 availability zone must be specified")
# Multiple subnets in same AZ
with pytest.raises(ClientError) as ex:
client.set_subnets(
LoadBalancerArn=arn, Subnets=[subnet1.id, subnet2.id, subnet2.id]
)
err = ex.value.response["Error"]
err["Message"].should.equal("The specified subnet does not exist.")
@mock_elbv2 @mock_elbv2
@mock_ec2 @mock_ec2
def test_modify_load_balancer_attributes_idle_timeout(): def test_modify_load_balancer_attributes_idle_timeout():
@ -1333,7 +1321,23 @@ def test_modify_listener_http_to_https():
) )
listener_arn = response["Listeners"][0]["ListenerArn"] listener_arn = response["Listeners"][0]["ListenerArn"]
response = acm.request_certificate( # No default cert
with pytest.raises(ClientError) as ex:
client.modify_listener(
ListenerArn=listener_arn,
Port=443,
Protocol="HTTPS",
SslPolicy="ELBSecurityPolicy-TLS-1-2-2017-01",
Certificates=[],
DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
)
err = ex.value.response["Error"]
err["Code"].should.equal("CertificateWereNotPassed")
err["Message"].should.equal(
"You must provide a list containing exactly one certificate if the listener protocol is HTTPS."
)
acm.request_certificate(
DomainName="google.com", DomainName="google.com",
SubjectAlternativeNames=["google.com", "www.google.com", "mail.google.com"], SubjectAlternativeNames=["google.com", "www.google.com", "mail.google.com"],
) )
@ -1367,22 +1371,6 @@ def test_modify_listener_http_to_https():
) )
listener.certificate.should.equal(yahoo_arn) listener.certificate.should.equal(yahoo_arn)
# No default cert
with pytest.raises(ClientError) as ex:
client.modify_listener(
ListenerArn=listener_arn,
Port=443,
Protocol="HTTPS",
SslPolicy="ELBSecurityPolicy-TLS-1-2-2017-01",
Certificates=[],
DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
)
err = ex.value.response["Error"]
err["Code"].should.equal("CertificateWereNotPassed")
err["Message"].should.equal(
"You must provide a list containing exactly one certificate if the listener protocol is HTTPS."
)
# Bad cert # Bad cert
with pytest.raises(ClientError) as exc: with pytest.raises(ClientError) as exc:
client.modify_listener( client.modify_listener(
@ -1475,17 +1463,136 @@ def test_modify_listener_of_https_target_group():
@mock_elbv2 @mock_elbv2
def test_add_unknown_listener_certificate():
client = boto3.client("elbv2", region_name="eu-central-1")
with pytest.raises(ClientError) as exc:
client.add_listener_certificates(
ListenerArn="unknown", Certificates=[{"CertificateArn": "google_arn"}]
)
err = exc.value.response["Error"]
err["Code"].should.equal("ListenerNotFound")
@mock_elbv2
def test_describe_unknown_listener_certificate():
client = boto3.client("elbv2", region_name="eu-central-1")
with pytest.raises(ClientError) as exc:
client.describe_listener_certificates(ListenerArn="unknown")
err = exc.value.response["Error"]
err["Code"].should.equal("ListenerNotFound")
@mock_acm
@mock_ec2 @mock_ec2
def test_redirect_action_listener_rule(): @mock_elbv2
def test_add_listener_certificate():
# Verify we can add a listener for a TargetGroup that is already HTTPS
client = boto3.client("elbv2", region_name="eu-central-1")
acm = boto3.client("acm", region_name="eu-central-1")
ec2 = boto3.resource("ec2", region_name="eu-central-1")
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="eu-central-1a"
)
response = client.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id],
Scheme="internal",
Tags=[{"Key": "key_name", "Value": "a_value"}],
)
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = client.create_target_group(Name="a-target", Protocol="HTTPS", Port=8443)
target_group_arn = response.get("TargetGroups")[0]["TargetGroupArn"]
# HTTPS listener
response = acm.request_certificate(
DomainName="google.com", SubjectAlternativeNames=["google.com"]
)
google_arn = response["CertificateArn"]
response = client.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTPS",
Port=443,
DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
)
listener_arn = response["Listeners"][0]["ListenerArn"]
certs = client.add_listener_certificates(
ListenerArn=listener_arn, Certificates=[{"CertificateArn": google_arn}]
)["Certificates"]
certs.should.have.length_of(1)
certs[0].should.have.key("CertificateArn").equals(google_arn)
certs = client.describe_listener_certificates(ListenerArn=listener_arn)[
"Certificates"
]
certs.should.have.length_of(1)
certs[0].should.have.key("CertificateArn").equals(google_arn)
client.remove_listener_certificates(
ListenerArn=listener_arn, Certificates=[{"CertificateArn": google_arn}]
)
certs = client.describe_listener_certificates(ListenerArn=listener_arn)[
"Certificates"
]
certs.should.have.length_of(0)
@mock_elbv2
@mock_ec2
def test_forward_config_action():
response, _, _, _, _, conn = create_load_balancer() response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn") load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = conn.create_target_group(Name="a-target", Protocol="HTTPS", Port=8443)
target_group_arn = response.get("TargetGroups")[0]["TargetGroupArn"]
action = { action = {
"Type": "redirect", "Type": "forward",
"RedirectConfig": { "ForwardConfig": {
"Protocol": "HTTPS", "TargetGroups": [{"TargetGroupArn": target_group_arn, "Weight": 1}],
"Port": "443", },
"StatusCode": "HTTP_301", }
expected_action = copy.deepcopy(action)
expected_action["ForwardConfig"]["TargetGroupStickinessConfig"] = {"Enabled": False}
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[action],
)
listener = response.get("Listeners")[0]
listener.get("DefaultActions").should.equal([expected_action])
listener_arn = listener.get("ListenerArn")
describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn])
describe_listener_actions = describe_listener_response["Listeners"][0][
"DefaultActions"
]
describe_listener_actions.should.equal([expected_action])
@mock_elbv2
@mock_ec2
def test_forward_config_action__with_stickiness():
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = conn.create_target_group(Name="a-target", Protocol="HTTPS", Port=8443)
target_group_arn = response.get("TargetGroups")[0]["TargetGroupArn"]
action = {
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [{"TargetGroupArn": target_group_arn, "Weight": 1}],
"TargetGroupStickinessConfig": {"Enabled": True},
}, },
} }
@ -1497,17 +1604,44 @@ def test_redirect_action_listener_rule():
) )
listener = response.get("Listeners")[0] listener = response.get("Listeners")[0]
expected_default_actions = [ listener.get("DefaultActions").should.equal([action])
{ listener_arn = listener.get("ListenerArn")
"Type": "redirect",
"RedirectConfig": { describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn])
"Protocol": "HTTPS", describe_listener_actions = describe_listener_response["Listeners"][0][
"Port": "443", "DefaultActions"
"StatusCode": "HTTP_301",
},
}
] ]
listener.get("DefaultActions").should.equal(expected_default_actions) describe_listener_actions.should.equal([action])
@mock_elbv2
@mock_ec2
def test_redirect_action_listener_rule():
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
action = {
"Type": "redirect",
"RedirectConfig": {
"Protocol": "HTTPS",
"Port": "443",
"StatusCode": "HTTP_301",
"Host": "h",
"Path": "p",
"Query": "q",
},
"Order": 1,
}
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[action],
)
listener = response.get("Listeners")[0]
listener.get("DefaultActions").should.equal([action])
listener_arn = listener.get("ListenerArn") listener_arn = listener.get("ListenerArn")
conn.create_rule( conn.create_rule(
@ -1517,19 +1651,17 @@ def test_redirect_action_listener_rule():
Actions=[action], Actions=[action],
) )
describe_rules_response = conn.describe_rules(ListenerArn=listener_arn) describe_rules_response = conn.describe_rules(ListenerArn=listener_arn)
describe_rules_response["Rules"][0]["Actions"].should.equal( describe_rules_response["Rules"][0]["Actions"].should.equal([action])
expected_default_actions
)
describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn]) describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn])
describe_listener_actions = describe_listener_response["Listeners"][0][ describe_listener_actions = describe_listener_response["Listeners"][0][
"DefaultActions" "DefaultActions"
] ]
describe_listener_actions.should.equal(expected_default_actions) describe_listener_actions.should.equal([action])
modify_listener_response = conn.modify_listener(ListenerArn=listener_arn, Port=81) modify_listener_response = conn.modify_listener(ListenerArn=listener_arn, Port=81)
modify_listener_actions = modify_listener_response["Listeners"][0]["DefaultActions"] modify_listener_actions = modify_listener_response["Listeners"][0]["DefaultActions"]
modify_listener_actions.should.equal(expected_default_actions) modify_listener_actions.should.equal([action])
@mock_elbv2 @mock_elbv2
@ -1546,6 +1678,101 @@ def test_cognito_action_listener_rule():
), ),
"UserPoolClientId": "abcd1234abcd", "UserPoolClientId": "abcd1234abcd",
"UserPoolDomain": "testpool", "UserPoolDomain": "testpool",
"AuthenticationRequestExtraParams": {"param": "test"},
},
}
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[action],
)
listener = response.get("Listeners")[0]
listener.get("DefaultActions")[0].should.equal(action)
listener_arn = listener.get("ListenerArn")
conn.create_rule(
ListenerArn=listener_arn,
Conditions=[{"Field": "path-pattern", "Values": ["/*"]}],
Priority=3,
Actions=[action],
)
describe_rules_response = conn.describe_rules(ListenerArn=listener_arn)
describe_rules_response["Rules"][0]["Actions"][0].should.equal(action)
describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn])
describe_listener_actions = describe_listener_response["Listeners"][0][
"DefaultActions"
][0]
describe_listener_actions.should.equal(action)
@mock_elbv2
@mock_ec2
def test_oidc_action_listener__simple():
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
action = {
"Type": "authenticate-oidc",
"AuthenticateOidcConfig": {
"AuthorizationEndpoint": "ae",
"ClientId": "ci",
"TokenEndpoint": "te",
"UserInfoEndpoint": "uie",
"Issuer": "is",
},
}
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[action],
)
listener = response.get("Listeners")[0]
listener.get("DefaultActions")[0].should.equal(action)
listener_arn = listener.get("ListenerArn")
conn.create_rule(
ListenerArn=listener_arn,
Conditions=[{"Field": "path-pattern", "Values": ["/*"]}],
Priority=3,
Actions=[action],
)
describe_rules_response = conn.describe_rules(ListenerArn=listener_arn)
describe_rules_response["Rules"][0]["Actions"][0].should.equal(action)
describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn])
describe_listener_actions = describe_listener_response["Listeners"][0][
"DefaultActions"
][0]
describe_listener_actions.should.equal(action)
@mock_elbv2
@mock_ec2
@pytest.mark.parametrize("use_secret", [True, False])
def test_oidc_action_listener(use_secret):
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
action = {
"Type": "authenticate-oidc",
"AuthenticateOidcConfig": {
"Issuer": "is",
"AuthorizationEndpoint": "ae",
"TokenEndpoint": "te",
"UserInfoEndpoint": "uie",
"ClientId": "ci",
"ClientSecret": "cs",
"SessionCookieName": "scn",
"Scope": "s",
"SessionTimeout": 42,
"AuthenticationRequestExtraParams": {"param": "test"},
"OnUnauthenticatedRequest": "our",
"UseExistingClientSecret": use_secret,
}, },
} }
response = conn.create_listener( response = conn.create_listener(
@ -1668,3 +1895,25 @@ def test_fixed_response_action_listener_rule_validates_content_type():
invalid_content_type_exception.value.response["Error"]["Code"].should.equal( invalid_content_type_exception.value.response["Error"]["Code"].should.equal(
"InvalidLoadBalancerAction" "InvalidLoadBalancerAction"
) )
@mock_elbv2
@mock_ec2
def test_create_listener_with_alpn_policy():
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[],
AlpnPolicy=["pol1", "pol2"],
)
listener = response.get("Listeners")[0]
listener_arn = listener["ListenerArn"]
listener.get("AlpnPolicy").should.equal(["pol1", "pol2"])
describe = conn.describe_listeners(ListenerArns=[listener_arn])["Listeners"][0]
describe.should.have.key("AlpnPolicy").should.equal(["pol1", "pol2"])

View File

@ -296,3 +296,15 @@ def test_create_rule_validate_condition(condition, expected_message):
err = ex.value.response["Error"] err = ex.value.response["Error"]
err["Code"].should.equal("ValidationError") err["Code"].should.equal("ValidationError")
err["Message"].should.equal(expected_message) err["Message"].should.equal(expected_message)
@mock_elbv2
@mock_ec2
def test_describe_unknown_rule():
conn = boto3.client("elbv2", region_name="us-east-1")
with pytest.raises(ClientError) as exc:
conn.describe_rules(RuleArns=["unknown_arn"])
err = exc.value.response["Error"]
err["Code"].should.equal("RuleNotFound")
err["Message"].should.equal("One or more rules not found")

View File

@ -0,0 +1,83 @@
import sure # noqa # pylint: disable=unused-import
from moto import mock_elbv2, mock_ec2
from .test_elbv2 import create_load_balancer
@mock_elbv2
@mock_ec2
def test_create_listener_with_tags():
response, _, _, _, _, elbv2 = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
listener_arn = elbv2.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[],
Tags=[{"Key": "k1", "Value": "v1"}],
)["Listeners"][0]["ListenerArn"]
# Ensure the tags persisted
response = elbv2.describe_tags(ResourceArns=[listener_arn])
tags = {d["Key"]: d["Value"] for d in response["TagDescriptions"][0]["Tags"]}
tags.should.equal({"k1": "v1"})
@mock_elbv2
@mock_ec2
def test_listener_add_remove_tags():
response, _, _, _, _, elbv2 = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
listener_arn = elbv2.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[],
Tags=[{"Key": "k1", "Value": "v1"}],
)["Listeners"][0]["ListenerArn"]
elbv2.add_tags(ResourceArns=[listener_arn], Tags=[{"Key": "a", "Value": "b"}])
tags = elbv2.describe_tags(ResourceArns=[listener_arn])["TagDescriptions"][0][
"Tags"
]
tags.should.equal([{"Key": "k1", "Value": "v1"}, {"Key": "a", "Value": "b"}])
elbv2.add_tags(
ResourceArns=[listener_arn],
Tags=[
{"Key": "a", "Value": "b"},
{"Key": "b", "Value": "b"},
{"Key": "c", "Value": "b"},
],
)
tags = elbv2.describe_tags(ResourceArns=[listener_arn])["TagDescriptions"][0][
"Tags"
]
tags.should.equal(
[
{"Key": "k1", "Value": "v1"},
{"Key": "a", "Value": "b"},
{"Key": "b", "Value": "b"},
{"Key": "c", "Value": "b"},
]
)
elbv2.remove_tags(ResourceArns=[listener_arn], TagKeys=["a"])
tags = elbv2.describe_tags(ResourceArns=[listener_arn])["TagDescriptions"][0][
"Tags"
]
tags.should.equal(
[
{"Key": "k1", "Value": "v1"},
{"Key": "b", "Value": "b"},
{"Key": "c", "Value": "b"},
]
)

View File

@ -0,0 +1,79 @@
import boto3
import sure # noqa # pylint: disable=unused-import
from moto import mock_elbv2, mock_ec2
@mock_elbv2
@mock_ec2
def test_set_subnets_errors():
client = 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.0/26", AvailabilityZone="us-east-1a"
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.64/26", AvailabilityZone="us-east-1b"
)
subnet3 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.192/26", AvailabilityZone="us-east-1c"
)
response = client.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme="internal",
Tags=[{"Key": "key_name", "Value": "a_value"}],
)
arn = response["LoadBalancers"][0]["LoadBalancerArn"]
client.set_subnets(
LoadBalancerArn=arn, Subnets=[subnet1.id, subnet2.id, subnet3.id]
)
resp = client.describe_load_balancers(LoadBalancerArns=[arn])
len(resp["LoadBalancers"][0]["AvailabilityZones"]).should.equal(3)
@mock_elbv2
@mock_ec2
def test_set_subnets__mapping():
client = 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.0/26", AvailabilityZone="us-east-1a"
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="172.28.7.64/26", AvailabilityZone="us-east-1b"
)
response = client.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme="internal",
Tags=[{"Key": "key_name", "Value": "a_value"}],
)
arn = response["LoadBalancers"][0]["LoadBalancerArn"]
client.set_subnets(
LoadBalancerArn=arn,
SubnetMappings=[{"SubnetId": subnet1.id}, {"SubnetId": subnet2.id}],
)
resp = client.describe_load_balancers(LoadBalancerArns=[arn])
a_zones = resp["LoadBalancers"][0]["AvailabilityZones"]
a_zones.should.have.length_of(2)
a_zones.should.contain({"ZoneName": "us-east-1a", "SubnetId": subnet1.id})
a_zones.should.contain({"ZoneName": "us-east-1b", "SubnetId": subnet2.id})

View File

@ -38,11 +38,9 @@ def test_create_target_group_with_invalid_healthcheck_protocol():
@mock_elbv2 @mock_elbv2
@mock_ec2 @mock_ec2
def test_create_target_group_and_listeners(): def test_create_target_group_with_tags():
response, vpc, _, _, _, conn = create_load_balancer() response, vpc, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = conn.create_target_group( response = conn.create_target_group(
Name="a-target", Name="a-target",
Protocol="HTTP", Protocol="HTTP",
@ -62,11 +60,42 @@ def test_create_target_group_and_listeners():
# Add tags to the target group # Add tags to the target group
conn.add_tags( conn.add_tags(
ResourceArns=[target_group_arn], Tags=[{"Key": "target", "Value": "group"}] ResourceArns=[target_group_arn],
Tags=[{"Key": "key1", "Value": "val1"}, {"Key": "key2", "Value": "val2"}],
) )
conn.describe_tags(ResourceArns=[target_group_arn])["TagDescriptions"][0][ conn.describe_tags(ResourceArns=[target_group_arn])["TagDescriptions"][0][
"Tags" "Tags"
].should.equal([{"Key": "target", "Value": "group"}]) ].should.equal([{"Key": "key1", "Value": "val1"}, {"Key": "key2", "Value": "val2"}])
# Verify they can be removed
conn.remove_tags(ResourceArns=[target_group_arn], TagKeys=["key1"])
conn.describe_tags(ResourceArns=[target_group_arn])["TagDescriptions"][0][
"Tags"
].should.equal([{"Key": "key2", "Value": "val2"}])
@mock_elbv2
@mock_ec2
def test_create_target_group_and_listeners():
response, vpc, _, _, _, conn = create_load_balancer()
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_arn = response.get("TargetGroups")[0]["TargetGroupArn"]
# Check it's in the describe_target_groups response # Check it's in the describe_target_groups response
response = conn.describe_target_groups() response = conn.describe_target_groups()
@ -77,15 +106,13 @@ def test_create_target_group_and_listeners():
LoadBalancerArn=load_balancer_arn, LoadBalancerArn=load_balancer_arn,
Protocol="HTTP", Protocol="HTTP",
Port=80, Port=80,
DefaultActions=[ DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
{"Type": "forward", "TargetGroupArn": target_group.get("TargetGroupArn")}
],
) )
listener = response.get("Listeners")[0] listener = response.get("Listeners")[0]
listener.get("Port").should.equal(80) listener.get("Port").should.equal(80)
listener.get("Protocol").should.equal("HTTP") listener.get("Protocol").should.equal("HTTP")
listener.get("DefaultActions").should.equal( listener.get("DefaultActions").should.equal(
[{"TargetGroupArn": target_group.get("TargetGroupArn"), "Type": "forward"}] [{"TargetGroupArn": target_group_arn, "Type": "forward"}]
) )
http_listener_arn = listener.get("ListenerArn") http_listener_arn = listener.get("ListenerArn")
@ -95,7 +122,7 @@ def test_create_target_group_and_listeners():
response.get("TargetGroups").should.have.length_of(1) response.get("TargetGroups").should.have.length_of(1)
# And another with SSL # And another with SSL
actions = {"Type": "forward", "TargetGroupArn": target_group.get("TargetGroupArn")} actions = {"Type": "forward", "TargetGroupArn": target_group_arn}
response = conn.create_listener( response = conn.create_listener(
LoadBalancerArn=load_balancer_arn, LoadBalancerArn=load_balancer_arn,
Protocol="HTTPS", Protocol="HTTPS",
@ -122,7 +149,7 @@ def test_create_target_group_and_listeners():
] ]
) )
listener.get("DefaultActions").should.equal( listener.get("DefaultActions").should.equal(
[{"TargetGroupArn": target_group.get("TargetGroupArn"), "Type": "forward"}] [{"TargetGroupArn": target_group_arn, "Type": "forward"}]
) )
https_listener_arn = listener.get("ListenerArn") https_listener_arn = listener.get("ListenerArn")
@ -149,7 +176,7 @@ def test_create_target_group_and_listeners():
# Try to delete the target group and it fails because there's a # Try to delete the target group and it fails because there's a
# listener referencing it # listener referencing it
with pytest.raises(ClientError) as e: with pytest.raises(ClientError) as e:
conn.delete_target_group(TargetGroupArn=target_group.get("TargetGroupArn")) conn.delete_target_group(TargetGroupArn=target_group_arn)
e.value.operation_name.should.equal("DeleteTargetGroup") e.value.operation_name.should.equal("DeleteTargetGroup")
e.value.args.should.equal( e.value.args.should.equal(
( (
@ -181,7 +208,7 @@ def test_create_target_group_and_listeners():
response.get("TargetGroups").should.have.length_of(1) response.get("TargetGroups").should.have.length_of(1)
# Which we'll now delete # Which we'll now delete
conn.delete_target_group(TargetGroupArn=target_group.get("TargetGroupArn")) conn.delete_target_group(TargetGroupArn=target_group_arn)
response = conn.describe_target_groups() response = conn.describe_target_groups()
response.get("TargetGroups").should.have.length_of(0) response.get("TargetGroups").should.have.length_of(0)