Merge pull request #2324 from acsbendi/elbv2-stopped-instance-target
ELBv2 DescribeTargetHealth returns correct response for stopped instance
This commit is contained in:
commit
2dabb629f7
@ -35,12 +35,13 @@ from .exceptions import (
|
|||||||
|
|
||||||
class FakeHealthStatus(BaseModel):
|
class FakeHealthStatus(BaseModel):
|
||||||
|
|
||||||
def __init__(self, instance_id, port, health_port, status, reason=None):
|
def __init__(self, instance_id, port, health_port, status, reason=None, description=None):
|
||||||
self.instance_id = instance_id
|
self.instance_id = instance_id
|
||||||
self.port = port
|
self.port = port
|
||||||
self.health_port = health_port
|
self.health_port = health_port
|
||||||
self.status = status
|
self.status = status
|
||||||
self.reason = reason
|
self.reason = reason
|
||||||
|
self.description = description
|
||||||
|
|
||||||
|
|
||||||
class FakeTargetGroup(BaseModel):
|
class FakeTargetGroup(BaseModel):
|
||||||
@ -69,7 +70,7 @@ class FakeTargetGroup(BaseModel):
|
|||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
self.port = port
|
self.port = port
|
||||||
self.healthcheck_protocol = healthcheck_protocol or 'HTTP'
|
self.healthcheck_protocol = healthcheck_protocol or 'HTTP'
|
||||||
self.healthcheck_port = healthcheck_port or 'traffic-port'
|
self.healthcheck_port = healthcheck_port or str(self.port)
|
||||||
self.healthcheck_path = healthcheck_path or '/'
|
self.healthcheck_path = healthcheck_path or '/'
|
||||||
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 or 5
|
||||||
@ -112,10 +113,14 @@ class FakeTargetGroup(BaseModel):
|
|||||||
raise TooManyTagsError()
|
raise TooManyTagsError()
|
||||||
self.tags[key] = value
|
self.tags[key] = value
|
||||||
|
|
||||||
def health_for(self, target):
|
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:
|
||||||
raise InvalidTargetError()
|
raise InvalidTargetError()
|
||||||
|
if t['id'].startswith("i-"): # EC2 instance ID
|
||||||
|
instance = ec2_backend.get_instance_by_id(t['id'])
|
||||||
|
if instance.state == "stopped":
|
||||||
|
return FakeHealthStatus(t['id'], t['port'], self.healthcheck_port, 'unused', 'Target.InvalidState', 'Target is in the stopped state')
|
||||||
return FakeHealthStatus(t['id'], t['port'], self.healthcheck_port, 'healthy')
|
return FakeHealthStatus(t['id'], t['port'], self.healthcheck_port, 'healthy')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -712,7 +717,7 @@ class ELBv2Backend(BaseBackend):
|
|||||||
|
|
||||||
if not targets:
|
if not targets:
|
||||||
targets = target_group.targets.values()
|
targets = target_group.targets.values()
|
||||||
return [target_group.health_for(target) for target in targets]
|
return [target_group.health_for(target, self.ec2_backend) for target in targets]
|
||||||
|
|
||||||
def set_rule_priorities(self, rule_priorities):
|
def set_rule_priorities(self, rule_priorities):
|
||||||
# validate
|
# validate
|
||||||
|
@ -1208,6 +1208,12 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
|
|||||||
<HealthCheckPort>{{ target_health.health_port }}</HealthCheckPort>
|
<HealthCheckPort>{{ target_health.health_port }}</HealthCheckPort>
|
||||||
<TargetHealth>
|
<TargetHealth>
|
||||||
<State>{{ target_health.status }}</State>
|
<State>{{ target_health.status }}</State>
|
||||||
|
{% if target_health.reason %}
|
||||||
|
<Reason>{{ target_health.reason }}</Reason>
|
||||||
|
{% endif %}
|
||||||
|
{% if target_health.description %}
|
||||||
|
<Description>{{ target_health.description }}</Description>
|
||||||
|
{% endif %}
|
||||||
</TargetHealth>
|
</TargetHealth>
|
||||||
<Target>
|
<Target>
|
||||||
<Port>{{ target_health.port }}</Port>
|
<Port>{{ target_health.port }}</Port>
|
||||||
|
@ -667,6 +667,91 @@ def test_register_targets():
|
|||||||
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ec2
|
||||||
|
@mock_elbv2
|
||||||
|
def test_stopped_instance_target():
|
||||||
|
target_group_port = 8080
|
||||||
|
|
||||||
|
conn = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.0/26',
|
||||||
|
AvailabilityZone='us-east-1b')
|
||||||
|
|
||||||
|
conn.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
|
||||||
|
response = conn.create_target_group(
|
||||||
|
Name='a-target',
|
||||||
|
Protocol='HTTP',
|
||||||
|
Port=target_group_port,
|
||||||
|
VpcId=vpc.id,
|
||||||
|
HealthCheckProtocol='HTTP',
|
||||||
|
HealthCheckPath='/',
|
||||||
|
HealthCheckIntervalSeconds=5,
|
||||||
|
HealthCheckTimeoutSeconds=5,
|
||||||
|
HealthyThresholdCount=5,
|
||||||
|
UnhealthyThresholdCount=2,
|
||||||
|
Matcher={'HttpCode': '200'})
|
||||||
|
target_group = response.get('TargetGroups')[0]
|
||||||
|
|
||||||
|
# No targets registered yet
|
||||||
|
response = conn.describe_target_health(
|
||||||
|
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||||
|
response.get('TargetHealthDescriptions').should.have.length_of(0)
|
||||||
|
|
||||||
|
response = ec2.create_instances(
|
||||||
|
ImageId='ami-1234abcd', MinCount=1, MaxCount=1)
|
||||||
|
instance = response[0]
|
||||||
|
|
||||||
|
target_dict = {
|
||||||
|
'Id': instance.id,
|
||||||
|
'Port': 500
|
||||||
|
}
|
||||||
|
|
||||||
|
response = conn.register_targets(
|
||||||
|
TargetGroupArn=target_group.get('TargetGroupArn'),
|
||||||
|
Targets=[target_dict])
|
||||||
|
|
||||||
|
response = conn.describe_target_health(
|
||||||
|
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||||
|
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||||
|
target_health_description = response.get('TargetHealthDescriptions')[0]
|
||||||
|
|
||||||
|
target_health_description['Target'].should.equal(target_dict)
|
||||||
|
target_health_description['HealthCheckPort'].should.equal(str(target_group_port))
|
||||||
|
target_health_description['TargetHealth'].should.equal({
|
||||||
|
'State': 'healthy'
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.stop()
|
||||||
|
|
||||||
|
response = conn.describe_target_health(
|
||||||
|
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||||
|
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||||
|
target_health_description = response.get('TargetHealthDescriptions')[0]
|
||||||
|
target_health_description['Target'].should.equal(target_dict)
|
||||||
|
target_health_description['HealthCheckPort'].should.equal(str(target_group_port))
|
||||||
|
target_health_description['TargetHealth'].should.equal({
|
||||||
|
'State': 'unused',
|
||||||
|
'Reason': 'Target.InvalidState',
|
||||||
|
'Description': 'Target is in the stopped state'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_elbv2
|
@mock_elbv2
|
||||||
def test_target_group_attributes():
|
def test_target_group_attributes():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user