Add ec2 instance state reason

- Add instance.reason and instance.state_reason
(http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-Item
Type-StateReasonType.html)
- Add ec2 filtering by state-reason-code and state-reason-message
This commit is contained in:
Arthur Wang 2014-10-20 15:54:00 -04:00
parent 68d2db55d4
commit 6963866c7e
3 changed files with 42 additions and 3 deletions

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import copy
import itertools
from collections import defaultdict
from datetime import datetime
import six
import boto
@ -95,6 +96,11 @@ class InstanceState(object):
self.name = name
self.code = code
class StateReason(object):
def __init__(self, message="", code=""):
self.message = message
self.code = code
class TaggedEC2Resource(object):
def get_tags(self, *args, **kwargs):
@ -258,6 +264,8 @@ class Instance(BotoInstance, TaggedEC2Resource):
self.id = random_instance_id()
self.image_id = image_id
self._state = InstanceState("running", 16)
self._reason = ""
self._state_reason = StateReason()
self.user_data = user_data
self.security_groups = security_groups
self.instance_type = kwargs.get("instance_type", "m1.small")
@ -317,6 +325,9 @@ class Instance(BotoInstance, TaggedEC2Resource):
self._state.name = "running"
self._state.code = 16
self._reason = ""
self._state_reason = StateReason()
def stop(self, *args, **kwargs):
for nic in self.nics.values():
nic.stop()
@ -324,6 +335,10 @@ class Instance(BotoInstance, TaggedEC2Resource):
self._state.name = "stopped"
self._state.code = 80
self._reason = "User initiated ({0})".format(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'))
self._state_reason = StateReason("Client.UserInitiatedShutdown: User initiated shutdown",
"Client.UserInitiatedShutdown")
def terminate(self, *args, **kwargs):
for nic in self.nics.values():
nic.stop()
@ -331,10 +346,17 @@ class Instance(BotoInstance, TaggedEC2Resource):
self._state.name = "terminated"
self._state.code = 48
self._reason = "User initiated ({0})".format(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'))
self._state_reason = StateReason("Client.UserInitiatedShutdown: User initiated shutdown",
"Client.UserInitiatedShutdown")
def reboot(self, *args, **kwargs):
self._state.name = "running"
self._state.code = 16
self._reason = ""
self._state_reason = StateReason()
def get_tags(self):
tags = ec2_backend.describe_tags(filters={'resource-id': [self.id]})
return tags

View File

@ -303,7 +303,7 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns='http://ec2.amazona
</instanceState>
<privateDnsName>ip-10.0.0.12.ec2.internal</privateDnsName>
<dnsName>ec2-46.51.219.63.compute-1.amazonaws.com</dnsName>
<reason/>
<reason>{{ instance._reason }}</reason>
<keyName>{{ instance.key_name }}</keyName>
<amiLaunchIndex>0</amiLaunchIndex>
<productCodes/>
@ -337,6 +337,10 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns='http://ec2.amazona
</item>
{% endfor %}
</groupSet>
<stateReason>
<code>{{ instance._state_reason.code }}</code>
<message>{{ instance._state_reason.message }}</message>
</stateReason>
<architecture>{{ instance.architecture }}</architecture>
<kernelId>{{ instance.kernel }}</kernelId>
<rootDeviceType>ebs</rootDeviceType>

View File

@ -266,15 +266,28 @@ def keypair_names_from_querystring(querystring_dict):
filter_dict_attribute_mapping = {
'instance-state-name': 'state',
'instance-id': 'id'
'instance-id': 'id',
'state-reason-code': '_state_reason.code',
'state-reason-message': '_state_reason.message'
}
def get_instance_value(instance, instance_attr):
keys = instance_attr.split('.')
val = instance
for key in keys:
if hasattr(val, key):
val = getattr(val, key)
elif isinstance(val, dict):
val = val[key]
else:
return None
return val
def passes_filter_dict(instance, filter_dict):
for filter_name, filter_values in filter_dict.items():
if filter_name in filter_dict_attribute_mapping:
instance_attr = filter_dict_attribute_mapping[filter_name]
instance_value = getattr(instance, instance_attr)
instance_value = get_instance_value(instance, instance_attr)
if instance_value not in filter_values:
return False
elif filter_name.startswith('tag:'):