Skip to content

Commit

Permalink
ELB:describe_instance_health() - implement OutOfService status (#5154)
Browse files Browse the repository at this point in the history
  • Loading branch information
bblommers authored May 21, 2022
1 parent 12843c4 commit 096a892
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 31 deletions.
4 changes: 2 additions & 2 deletions IMPLEMENTATION_COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2292,7 +2292,7 @@

## elb
<details>
<summary>62% implemented</summary>
<summary>65% implemented</summary>

- [ ] add_tags
- [X] apply_security_groups_to_load_balancer
Expand All @@ -2308,7 +2308,7 @@
- [X] delete_load_balancer_policy
- [ ] deregister_instances_from_load_balancer
- [ ] describe_account_limits
- [ ] describe_instance_health
- [X] describe_instance_health
- [ ] describe_load_balancer_attributes
- [X] describe_load_balancer_policies
- [ ] describe_load_balancer_policy_types
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/services/elb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ elb
- [X] delete_load_balancer_policy
- [ ] deregister_instances_from_load_balancer
- [ ] describe_account_limits
- [ ] describe_instance_health
- [X] describe_instance_health
- [ ] describe_load_balancer_attributes
- [X] describe_load_balancer_policies
- [ ] describe_load_balancer_policy_types
Expand Down
3 changes: 3 additions & 0 deletions moto/ec2/models/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ def stop(self):
"Client.UserInitiatedShutdown",
)

def is_running(self):
return self._state.name == "running"

def delete(self, region): # pylint: disable=unused-argument
self.terminate()

Expand Down
21 changes: 21 additions & 0 deletions moto/elb/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from moto.core import BaseBackend, BaseModel, CloudFormationModel
from moto.core.utils import BackendDict
from moto.ec2.models import ec2_backends
from moto.ec2.exceptions import InvalidInstanceIdError
from uuid import uuid4
from .exceptions import (
BadHealthCheckDefinition,
Expand Down Expand Up @@ -380,6 +381,26 @@ def describe_load_balancer_policies(self, lb_name, policy_names):
raise PolicyNotFoundError()
return policies

def describe_instance_health(self, lb_name, instances):
provided_ids = [i["InstanceId"] for i in instances]
registered_ids = self.get_load_balancer(lb_name).instance_ids
ec2_backend = ec2_backends[self.region_name]
if len(provided_ids) == 0:
provided_ids = registered_ids
instances = []
for instance_id in provided_ids:
if instance_id not in registered_ids:
instances.append({"InstanceId": instance_id, "State": "Unknown"})
else:
try:
instance = ec2_backend.get_instance(instance_id)
state = "InService" if instance.is_running() else "OutOfService"
instances.append({"InstanceId": instance_id, "State": state})
except InvalidInstanceIdError:
pass

return instances

def delete_load_balancer_listeners(self, name, ports):
balancer = self.load_balancers.get(name, None)
listeners = []
Expand Down
17 changes: 3 additions & 14 deletions moto/elb/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,21 +288,10 @@ def describe_load_balancer_policies(self):
return template.render(policies=policies)

def describe_instance_health(self):
load_balancer_name = self._get_param("LoadBalancerName")
provided_instance_ids = [
list(param.values())[0]
for param in self._get_list_prefix("Instances.member")
]
registered_instances_id = self.elb_backend.get_load_balancer(
load_balancer_name
).instance_ids
if len(provided_instance_ids) == 0:
provided_instance_ids = registered_instances_id
lb_name = self._get_param("LoadBalancerName")
instances = self._get_params().get("Instances", [])
instances = self.elb_backend.describe_instance_health(lb_name, instances)
template = self.response_template(DESCRIBE_INSTANCE_HEALTH_TEMPLATE)
instances = []
for instance_id in provided_instance_ids:
state = "InService" if instance_id in registered_instances_id else "Unknown"
instances.append({"InstanceId": instance_id, "State": state})
return template.render(instances=instances)

def add_tags(self):
Expand Down
67 changes: 53 additions & 14 deletions tests/test_elb/test_elb.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,30 +868,69 @@ def test_connection_settings_attribute():
def test_describe_instance_health():
elb = boto3.client("elb", 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"
]
# Create three instances
resp = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=2, MaxCount=2)
instance_ids = [i["InstanceId"] for i in resp["Instances"]]

# Register two instances with an LB
lb_name = "my_load_balancer"
elb.create_load_balancer(
Listeners=[{"InstancePort": 80, "LoadBalancerPort": 8080, "Protocol": "HTTP"}],
LoadBalancerName=lb_name,
)
elb.register_instances_with_load_balancer(
LoadBalancerName=lb_name, Instances=[{"InstanceId": instances[0]["InstanceId"]}]
)
instances_health = elb.describe_instance_health(
LoadBalancerName=lb_name,
Instances=[{"InstanceId": instance["InstanceId"]} for instance in instances],
Instances=[{"InstanceId": instance_ids[0]}, {"InstanceId": instance_ids[1]}],
)
instances_health["InstanceStates"].should.have.length_of(2)
instances_health["InstanceStates"][0]["InstanceId"].should.equal(
instances[0]["InstanceId"]

# Describe the Health of all instances
instances_health = elb.describe_instance_health(LoadBalancerName=lb_name)[
"InstanceStates"
]
instances_health.should.have.length_of(2)


@mock_ec2
@mock_elb
def test_describe_instance_health__with_instance_ids():
elb = boto3.client("elb", region_name="us-east-1")
ec2 = boto3.client("ec2", region_name="us-east-1")
# Create three instances
resp = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=3, MaxCount=3)
instance_ids = [i["InstanceId"] for i in resp["Instances"]]

# Register two instances with an LB
lb_name = "my_load_balancer"
elb.create_load_balancer(
Listeners=[{"InstancePort": 80, "LoadBalancerPort": 8080, "Protocol": "HTTP"}],
LoadBalancerName=lb_name,
)
instances_health["InstanceStates"][0]["State"].should.equal("InService")
instances_health["InstanceStates"][1]["InstanceId"].should.equal(
instances[1]["InstanceId"]
elb.register_instances_with_load_balancer(
LoadBalancerName=lb_name,
Instances=[{"InstanceId": instance_ids[0]}, {"InstanceId": instance_ids[2]}],
)
instances_health["InstanceStates"][1]["State"].should.equal("Unknown")

# Stop one instance
ec2.stop_instances(InstanceIds=[instance_ids[2]])

# Describe the Health of instances
instances_health = elb.describe_instance_health(
LoadBalancerName=lb_name,
Instances=[{"InstanceId": iid} for iid in instance_ids],
)["InstanceStates"]
instances_health.should.have.length_of(3)

# The first instance is healthy
instances_health[0]["InstanceId"].should.equal(instance_ids[0])
instances_health[0]["State"].should.equal("InService")

# The second instance was never known to ELB
instances_health[1]["InstanceId"].should.equal(instance_ids[1])
instances_health[1]["State"].should.equal("Unknown")

# The third instance was stopped
instances_health[2]["InstanceId"].should.equal(instance_ids[2])
instances_health[2]["State"].should.equal("OutOfService")


@mock_elb
Expand Down

0 comments on commit 096a892

Please sign in to comment.