Merge pull request #2764 from bblommers/feature/ec2-describe-instance-filters
Feature - EC2 describe_instance_status now uses filters
This commit is contained in:
commit
a92f862e86
@ -822,6 +822,21 @@ class Instance(TaggedEC2Resource, BotoInstance):
|
||||
return self.public_ip
|
||||
raise UnformattedGetAttTemplateException()
|
||||
|
||||
def applies(self, filters):
|
||||
if filters:
|
||||
applicable = False
|
||||
for f in filters:
|
||||
acceptable_values = f["values"]
|
||||
if f["name"] == "instance-state-name":
|
||||
if self._state.name in acceptable_values:
|
||||
applicable = True
|
||||
if f["name"] == "instance-state-code":
|
||||
if str(self._state.code) in acceptable_values:
|
||||
applicable = True
|
||||
return applicable
|
||||
# If there are no filters, all instances are valid
|
||||
return True
|
||||
|
||||
|
||||
class InstanceBackend(object):
|
||||
def __init__(self):
|
||||
@ -921,22 +936,23 @@ class InstanceBackend(object):
|
||||
value = getattr(instance, key)
|
||||
return instance, value
|
||||
|
||||
def all_instances(self):
|
||||
def all_instances(self, filters=None):
|
||||
instances = []
|
||||
for reservation in self.all_reservations():
|
||||
for instance in reservation.instances:
|
||||
if instance.applies(filters):
|
||||
instances.append(instance)
|
||||
return instances
|
||||
|
||||
def all_running_instances(self):
|
||||
def all_running_instances(self, filters=None):
|
||||
instances = []
|
||||
for reservation in self.all_reservations():
|
||||
for instance in reservation.instances:
|
||||
if instance.state_code == 16:
|
||||
if instance.state_code == 16 and instance.applies(filters):
|
||||
instances.append(instance)
|
||||
return instances
|
||||
|
||||
def get_multi_instances_by_id(self, instance_ids):
|
||||
def get_multi_instances_by_id(self, instance_ids, filters=None):
|
||||
"""
|
||||
:param instance_ids: A string list with instance ids
|
||||
:return: A list with instance objects
|
||||
@ -946,6 +962,7 @@ class InstanceBackend(object):
|
||||
for reservation in self.all_reservations():
|
||||
for instance in reservation.instances:
|
||||
if instance.id in instance_ids:
|
||||
if instance.applies(filters):
|
||||
result.append(instance)
|
||||
|
||||
# TODO: Trim error message down to specific invalid id.
|
||||
|
@ -113,16 +113,34 @@ class InstanceResponse(BaseResponse):
|
||||
template = self.response_template(EC2_START_INSTANCES)
|
||||
return template.render(instances=instances)
|
||||
|
||||
def _get_list_of_dict_params(self, param_prefix, _dct):
|
||||
"""
|
||||
Simplified version of _get_dict_param
|
||||
Allows you to pass in a custom dict instead of using self.querystring by default
|
||||
"""
|
||||
params = []
|
||||
for key, value in _dct.items():
|
||||
if key.startswith(param_prefix):
|
||||
params.append(value)
|
||||
return params
|
||||
|
||||
def describe_instance_status(self):
|
||||
instance_ids = self._get_multi_param("InstanceId")
|
||||
include_all_instances = self._get_param("IncludeAllInstances") == "true"
|
||||
filters = self._get_list_prefix("Filter")
|
||||
filters = [
|
||||
{"name": f["name"], "values": self._get_list_of_dict_params("value.", f)}
|
||||
for f in filters
|
||||
]
|
||||
|
||||
if instance_ids:
|
||||
instances = self.ec2_backend.get_multi_instances_by_id(instance_ids)
|
||||
instances = self.ec2_backend.get_multi_instances_by_id(
|
||||
instance_ids, filters
|
||||
)
|
||||
elif include_all_instances:
|
||||
instances = self.ec2_backend.all_instances()
|
||||
instances = self.ec2_backend.all_instances(filters)
|
||||
else:
|
||||
instances = self.ec2_backend.all_running_instances()
|
||||
instances = self.ec2_backend.all_running_instances(filters)
|
||||
|
||||
template = self.response_template(EC2_INSTANCE_STATUS)
|
||||
return template.render(instances=instances)
|
||||
|
@ -1144,7 +1144,7 @@ def test_describe_instance_status_with_instances():
|
||||
|
||||
|
||||
@mock_ec2_deprecated
|
||||
def test_describe_instance_status_with_instance_filter():
|
||||
def test_describe_instance_status_with_instance_filter_deprecated():
|
||||
conn = boto.connect_ec2("the_key", "the_secret")
|
||||
|
||||
# We want to filter based on this one
|
||||
@ -1166,6 +1166,75 @@ def test_describe_instance_status_with_instance_filter():
|
||||
cm.exception.request_id.should_not.be.none
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_instance_status_with_instance_filter():
|
||||
conn = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
# We want to filter based on this one
|
||||
reservation = conn.run_instances(ImageId="ami-1234abcd", MinCount=3, MaxCount=3)
|
||||
instance1 = reservation["Instances"][0]
|
||||
instance2 = reservation["Instances"][1]
|
||||
instance3 = reservation["Instances"][2]
|
||||
conn.stop_instances(InstanceIds=[instance1["InstanceId"]])
|
||||
stopped_instance_ids = [instance1["InstanceId"]]
|
||||
running_instance_ids = sorted([instance2["InstanceId"], instance3["InstanceId"]])
|
||||
all_instance_ids = sorted(stopped_instance_ids + running_instance_ids)
|
||||
|
||||
# Filter instance using the state name
|
||||
state_name_filter = {
|
||||
"running_and_stopped": [
|
||||
{"Name": "instance-state-name", "Values": ["running", "stopped"]}
|
||||
],
|
||||
"running": [{"Name": "instance-state-name", "Values": ["running"]}],
|
||||
"stopped": [{"Name": "instance-state-name", "Values": ["stopped"]}],
|
||||
}
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_name_filter["running_and_stopped"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(all_instance_ids)
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_name_filter["running"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(running_instance_ids)
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_name_filter["stopped"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(stopped_instance_ids)
|
||||
|
||||
# Filter instance using the state code
|
||||
state_code_filter = {
|
||||
"running_and_stopped": [
|
||||
{"Name": "instance-state-code", "Values": ["16", "80"]}
|
||||
],
|
||||
"running": [{"Name": "instance-state-code", "Values": ["16"]}],
|
||||
"stopped": [{"Name": "instance-state-code", "Values": ["80"]}],
|
||||
}
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_code_filter["running_and_stopped"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(all_instance_ids)
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_code_filter["running"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(running_instance_ids)
|
||||
|
||||
found_statuses = conn.describe_instance_status(
|
||||
IncludeAllInstances=True, Filters=state_code_filter["stopped"]
|
||||
)["InstanceStatuses"]
|
||||
found_instance_ids = [status["InstanceId"] for status in found_statuses]
|
||||
sorted(found_instance_ids).should.equal(stopped_instance_ids)
|
||||
|
||||
|
||||
@requires_boto_gte("2.32.0")
|
||||
@mock_ec2_deprecated
|
||||
def test_describe_instance_status_with_non_running_instances():
|
||||
|
Loading…
Reference in New Issue
Block a user