Repository: cloud-custodian/cloud-custodian

Issue:
ec2 reserved instance resource
per conversation on gitter, use the boto api to get reserved instances using `describe_reserved_instances` 


Discussion:
Anyone working on this?

Resolving patch:
diff --git a/c7n/resources/ec2.py b/c7n/resources/ec2.py
--- a/c7n/resources/ec2.py
+++ b/c7n/resources/ec2.py
@@ -1774,10 +1774,11 @@ def get_instance_attribute(self, resources, attribute):
 class LaunchTemplate(query.QueryResourceManager):
 
     class resource_type(object):
+        id = 'LaunchTemplateId'
         name = 'LaunchTemplateName'
         service = 'ec2'
         date = 'CreateTime'
-        dimension = 'None'
+        dimension = None
         enum_spec = (
             'describe_launch_templates', 'LaunchTemplates', None)
         filter_name = 'LaunchTemplateIds'
@@ -1845,3 +1846,17 @@ def get_asg_templates(self, asgs):
                 (t['LaunchTemplateId'], t['Version']), []).append(
                     a['AutoScalingGroupName'])
         return templates
+
+
+@resources.register('ec2-reserved')
+class ReservedInstance(query.QueryResourceManager):
+
+    class resource_type(object):
+        service = 'ec2'
+        name = id = 'ReservedInstancesId'
+        date = 'Start'
+        enum_spec = (
+            'describe_reserved_instances', 'ReservedInstances', None)
+        filter_name = 'ReservedInstancesIds'
+        filter_type = 'list'
+        dimension = None


Test patch:
diff --git a/tests/data/placebo/test_ec2_reserved_instance_query/ec2.DescribeReservedInstances_1.json b/tests/data/placebo/test_ec2_reserved_instance_query/ec2.DescribeReservedInstances_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ec2_reserved_instance_query/ec2.DescribeReservedInstances_1.json
@@ -0,0 +1,59 @@
+{
+    "status_code": 200,
+    "data": {
+        "ReservedInstances": [
+            {
+                "Duration": 31536000,
+                "End": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 2,
+                    "day": 23,
+                    "hour": 11,
+                    "minute": 25,
+                    "second": 2,
+                    "microsecond": 0
+                },
+                "FixedPrice": 30.0,
+                "InstanceCount": 1,
+                "InstanceType": "t2.micro",
+                "ProductDescription": "Linux/UNIX",
+                "ReservedInstancesId": "32881ecb-6734-4b79-94a0-26c759c2da38",
+                "Start": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 2,
+                    "day": 23,
+                    "hour": 11,
+                    "minute": 25,
+                    "second": 3,
+                    "microsecond": 340000
+                },
+                "State": "active",
+                "UsagePrice": 0.0,
+                "CurrencyCode": "USD",
+                "InstanceTenancy": "default",
+                "OfferingClass": "standard",
+                "OfferingType": "Partial Upfront",
+                "RecurringCharges": [
+                    {
+                        "Amount": 0.0034,
+                        "Frequency": "Hourly"
+                    }
+                ],
+                "Scope": "Region"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "cfd41aad-88c0-4975-9725-f2385aaa5852",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "content-length": "1267",
+                "date": "Sat, 23 Feb 2019 11:45:27 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_ec2.py b/tests/test_ec2.py
--- a/tests/test_ec2.py
+++ b/tests/test_ec2.py
@@ -1517,3 +1517,14 @@ def test_regex_filter(self):
         )
         resources = policy.run()
         self.assertGreater(len(resources), 0)
+
+
+class TestReservedInstance(BaseTest):
+
+    def test_reserved_instance_query(self):
+        factory = self.replay_flight_data('test_ec2_reserved_instance_query')
+        p = self.load_policy({
+            'name': 'ec2-reserved',
+            'resource': 'aws.ec2-reserved'}, session_factory=factory)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)