Repository: cloud-custodian/cloud-custodian

Issue:
AWS unused filter for ebs-snapshots
for ebs-snapshots unused would mean not referenced by launch-template, launch-config, or ami. 

for ebs volumes (original issue filed), one can just do an attribute/value filter on attachment metadata to detect orphaned volumes.

[original]
EBS volumes can be orphaned if its associated EC2 is terminated. We should be able to scan all ebs volumes to find ones that are not associated with an EC2 in order to remove them.


Discussion:

Resolving patch:
diff --git a/c7n/resources/ebs.py b/c7n/resources/ebs.py
--- a/c7n/resources/ebs.py
+++ b/c7n/resources/ebs.py
@@ -247,6 +247,69 @@ def process_resource_set(self, client, resource_set):
         return results
 
 
+@Snapshot.filter_registry.register('unused')
+class SnapshotUnusedFilter(Filter):
+    """Filters snapshots based on usage
+
+    true: snapshot is not used by launch-template, launch-config, or ami.
+
+    false: snapshot is being used by launch-template, launch-config, or ami.
+
+    :example:
+
+    .. code-block:: yaml
+
+            policies:
+              - name: snapshot-unused
+                resource: ebs-snapshot
+                filters:
+                  - type: unused
+                    value: true
+    """
+
+    schema = type_schema('unused', value={'type': 'boolean'})
+
+    def get_permissions(self):
+        return list(itertools.chain([
+            self.manager.get_resource_manager(m).get_permissions()
+            for m in ('asg', 'launch-config', 'ami')]))
+
+    def _pull_asg_snapshots(self):
+        asgs = self.manager.get_resource_manager('asg').resources()
+        snap_ids = set()
+        lcfgs = set(a['LaunchConfigurationName'] for a in asgs if 'LaunchConfigurationName' in a)
+        lcfg_mgr = self.manager.get_resource_manager('launch-config')
+
+        if lcfgs:
+            for lc in lcfg_mgr.resources():
+                for b in lc.get('BlockDeviceMappings'):
+                    if 'Ebs' in b and 'SnapshotId' in b['Ebs']:
+                        snap_ids.add(b['Ebs']['SnapshotId'])
+
+        tmpl_mgr = self.manager.get_resource_manager('launch-template-version')
+        for tversion in tmpl_mgr.get_resources(
+                list(tmpl_mgr.get_asg_templates(asgs).keys())):
+            for bd in tversion['LaunchTemplateData']['BlockDeviceMappings']:
+                if 'Ebs' in bd and 'SnapshotId' in bd['Ebs']:
+                    snap_ids.add(bd['Ebs']['SnapshotId'])
+        return snap_ids
+
+    def _pull_ami_snapshots(self):
+        amis = self.manager.get_resource_manager('ami').resources()
+        ami_snaps = set()
+        for i in amis:
+            for dev in i.get('BlockDeviceMappings'):
+                if 'Ebs' in dev and 'SnapshotId' in dev['Ebs']:
+                    ami_snaps.add(dev['Ebs']['SnapshotId'])
+        return ami_snaps
+
+    def process(self, resources, event=None):
+        snaps = self._pull_asg_snapshots().union(self._pull_ami_snapshots())
+        if self.data.get('value', True):
+            return [r for r in resources if r['SnapshotId'] not in snaps]
+        return [r for r in resources if r['SnapshotId'] in snaps]
+
+
 @Snapshot.filter_registry.register('skip-ami-snapshots')
 class SnapshotSkipAmiSnapshots(Filter):
     """


Test patch:
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_1.json b/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_1.json
@@ -0,0 +1,58 @@
+{
+    "status_code": 200,
+    "data": {
+        "AutoScalingGroups": [
+            {
+                "AutoScalingGroupName": "c7n-test",
+                "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:644160558196:autoScalingGroup:34881cd0-f726-4a32-bf6f-4ba4280c3b0f:autoScalingGroupName/c7n-test",
+                "LaunchTemplate": {
+                    "LaunchTemplateId": "lt-0f4a39147cc7881b9",
+                    "LaunchTemplateName": "c7n-test",
+                    "Version": "$Default"
+                },
+                "MinSize": 1,
+                "MaxSize": 1,
+                "DesiredCapacity": 1,
+                "DefaultCooldown": 300,
+                "AvailabilityZones": [
+                    "us-east-1d"
+                ],
+                "LoadBalancerNames": [],
+                "TargetGroupARNs": [],
+                "HealthCheckType": "EC2",
+                "HealthCheckGracePeriod": 300,
+                "Instances": [],
+                "CreatedTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 17,
+                    "minute": 18,
+                    "second": 26,
+                    "microsecond": 771000
+                },
+                "SuspendedProcesses": [],
+                "VPCZoneIdentifier": "subnet-3a334610",
+                "EnabledMetrics": [],
+                "Tags": [],
+                "TerminationPolicies": [
+                    "Default"
+                ],
+                "NewInstancesProtectedFromScaleIn": false,
+                "ServiceLinkedRoleARN": "arn:aws:iam::644160558196:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "57358631-41cc-11e9-b45e-03f58e2fc2f0",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "57358631-41cc-11e9-b45e-03f58e2fc2f0",
+                "content-type": "text/xml",
+                "content-length": "1807",
+                "date": "Fri, 08 Mar 2019 18:02:30 GMT"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_2.json b/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/autoscaling.DescribeAutoScalingGroups_2.json
@@ -0,0 +1,58 @@
+{
+    "status_code": 200,
+    "data": {
+        "AutoScalingGroups": [
+            {
+                "AutoScalingGroupName": "c7n-test",
+                "AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:644160558196:autoScalingGroup:34881cd0-f726-4a32-bf6f-4ba4280c3b0f:autoScalingGroupName/c7n-test",
+                "LaunchTemplate": {
+                    "LaunchTemplateId": "lt-0f4a39147cc7881b9",
+                    "LaunchTemplateName": "c7n-test",
+                    "Version": "$Default"
+                },
+                "MinSize": 1,
+                "MaxSize": 1,
+                "DesiredCapacity": 1,
+                "DefaultCooldown": 300,
+                "AvailabilityZones": [
+                    "us-east-1d"
+                ],
+                "LoadBalancerNames": [],
+                "TargetGroupARNs": [],
+                "HealthCheckType": "EC2",
+                "HealthCheckGracePeriod": 300,
+                "Instances": [],
+                "CreatedTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 17,
+                    "minute": 18,
+                    "second": 26,
+                    "microsecond": 771000
+                },
+                "SuspendedProcesses": [],
+                "VPCZoneIdentifier": "subnet-3a334610",
+                "EnabledMetrics": [],
+                "Tags": [],
+                "TerminationPolicies": [
+                    "Default"
+                ],
+                "NewInstancesProtectedFromScaleIn": false,
+                "ServiceLinkedRoleARN": "arn:aws:iam::644160558196:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "57d87c59-41cc-11e9-8e94-03cd555de4e3",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "57d87c59-41cc-11e9-8e94-03cd555de4e3",
+                "content-type": "text/xml",
+                "content-length": "1807",
+                "date": "Fri, 08 Mar 2019 18:02:30 GMT"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_1.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_1.json
@@ -0,0 +1,48 @@
+{
+    "status_code": 200,
+    "data": {
+        "Images": [
+            {
+                "Architecture": "x86_64",
+                "CreationDate": "2019-03-08T16:07:13.000Z",
+                "ImageId": "ami-008c67c239389d171",
+                "ImageLocation": "644160558196/test-c7n-amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "ImageType": "machine",
+                "Public": false,
+                "OwnerId": "644160558196",
+                "State": "available",
+                "BlockDeviceMappings": [
+                    {
+                        "DeviceName": "/dev/xvda",
+                        "Ebs": {
+                            "DeleteOnTermination": true,
+                            "SnapshotId": "snap-0b80955e4f7052f72",
+                            "VolumeSize": 8,
+                            "VolumeType": "gp2",
+                            "Encrypted": true
+                        }
+                    }
+                ],
+                "Description": "[Copied ami-97785bed from us-east-1] amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "EnaSupport": true,
+                "Hypervisor": "xen",
+                "Name": "test-c7n-amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "RootDeviceName": "/dev/xvda",
+                "RootDeviceType": "ebs",
+                "SriovNetSupport": "simple",
+                "VirtualizationType": "hvm"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "7fc610e5-763b-4c7f-8b49-14d90127a058",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "content-length": "1740",
+                "date": "Fri, 08 Mar 2019 18:02:31 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_2.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeImages_2.json
@@ -0,0 +1,48 @@
+{
+    "status_code": 200,
+    "data": {
+        "Images": [
+            {
+                "Architecture": "x86_64",
+                "CreationDate": "2019-03-08T16:07:13.000Z",
+                "ImageId": "ami-008c67c239389d171",
+                "ImageLocation": "644160558196/test-c7n-amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "ImageType": "machine",
+                "Public": false,
+                "OwnerId": "644160558196",
+                "State": "available",
+                "BlockDeviceMappings": [
+                    {
+                        "DeviceName": "/dev/xvda",
+                        "Ebs": {
+                            "DeleteOnTermination": true,
+                            "SnapshotId": "snap-0b80955e4f7052f72",
+                            "VolumeSize": 8,
+                            "VolumeType": "gp2",
+                            "Encrypted": true
+                        }
+                    }
+                ],
+                "Description": "[Copied ami-97785bed from us-east-1] amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "EnaSupport": true,
+                "Hypervisor": "xen",
+                "Name": "test-c7n-amzn-ami-hvm-2017.09.1.20180115-x86_64-gp2",
+                "RootDeviceName": "/dev/xvda",
+                "RootDeviceType": "ebs",
+                "SriovNetSupport": "simple",
+                "VirtualizationType": "hvm"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "d64ef955-9ce3-4c68-bd80-bbd6393d8ccb",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "content-length": "1740",
+                "date": "Fri, 08 Mar 2019 18:02:32 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_1.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_1.json
@@ -0,0 +1,60 @@
+{
+    "status_code": 200,
+    "data": {
+        "LaunchTemplateVersions": [
+            {
+                "LaunchTemplateId": "lt-0f4a39147cc7881b9",
+                "LaunchTemplateName": "c7n-test",
+                "VersionNumber": 1,
+                "CreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 17,
+                    "minute": 17,
+                    "second": 53,
+                    "microsecond": 0
+                },
+                "CreatedBy": "arn:aws:iam::644160558196:user/pratyush.mishra@capitalone.com",
+                "DefaultVersion": true,
+                "LaunchTemplateData": {
+                    "BlockDeviceMappings": [
+                        {
+                            "DeviceName": "/dev/xvda",
+                            "Ebs": {
+                                "Encrypted": false,
+                                "DeleteOnTermination": true,
+                                "SnapshotId": "snap-0ff5b79fdf9b021e8",
+                                "VolumeSize": 8,
+                                "VolumeType": "gp2"
+                            }
+                        },
+                        {
+                            "DeviceName": "/dev/sdb",
+                            "Ebs": {
+                                "Encrypted": false,
+                                "SnapshotId": "snap-0b818bbec5eebac4c",
+                                "VolumeSize": -43
+                            }
+                        }
+                    ],
+                    "ImageId": "ami-02da3a138888ced85",
+                    "InstanceType": "t1.micro"
+                }
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "27c45fea-b419-4a34-97f8-ad46f40d5ee5",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "transfer-encoding": "chunked",
+                "vary": "Accept-Encoding",
+                "date": "Fri, 08 Mar 2019 18:02:30 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_2.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeLaunchTemplateVersions_2.json
@@ -0,0 +1,60 @@
+{
+    "status_code": 200,
+    "data": {
+        "LaunchTemplateVersions": [
+            {
+                "LaunchTemplateId": "lt-0f4a39147cc7881b9",
+                "LaunchTemplateName": "c7n-test",
+                "VersionNumber": 1,
+                "CreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 17,
+                    "minute": 17,
+                    "second": 53,
+                    "microsecond": 0
+                },
+                "CreatedBy": "arn:aws:iam::644160558196:user/pratyush.mishra@capitalone.com",
+                "DefaultVersion": true,
+                "LaunchTemplateData": {
+                    "BlockDeviceMappings": [
+                        {
+                            "DeviceName": "/dev/xvda",
+                            "Ebs": {
+                                "Encrypted": false,
+                                "DeleteOnTermination": true,
+                                "SnapshotId": "snap-0ff5b79fdf9b021e8",
+                                "VolumeSize": 8,
+                                "VolumeType": "gp2"
+                            }
+                        },
+                        {
+                            "DeviceName": "/dev/sdb",
+                            "Ebs": {
+                                "Encrypted": false,
+                                "SnapshotId": "snap-0b818bbec5eebac4c",
+                                "VolumeSize": -43
+                            }
+                        }
+                    ],
+                    "ImageId": "ami-02da3a138888ced85",
+                    "InstanceType": "t1.micro"
+                }
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "d9256794-71f8-45a9-b9d7-0f47d6286b15",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "transfer-encoding": "chunked",
+                "vary": "Accept-Encoding",
+                "date": "Fri, 08 Mar 2019 18:02:31 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_1.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_1.json
@@ -0,0 +1,79 @@
+{
+    "status_code": 200,
+    "data": {
+        "Snapshots": [
+            {
+                "Description": "test",
+                "Encrypted": false,
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0bf9e1af959fbdddf",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 6,
+                    "hour": 0,
+                    "minute": 44,
+                    "second": 22,
+                    "microsecond": 972000
+                },
+                "State": "completed",
+                "VolumeId": "vol-0bf78c2aa3a923550",
+                "VolumeSize": 1
+            },
+            {
+                "Description": "Copied for DestinationAmi ami-008c67c239389d171 from SourceAmi ami-97785bed for SourceSnapshot snap-0fae6f7252388fc12. Task created on 1,552,061,232,790.",
+                "Encrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/798bc4bb-3079-4a9a-bc27-2c7f2b6c91d0",
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0b80955e4f7052f72",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 16,
+                    "minute": 12,
+                    "second": 36,
+                    "microsecond": 913000
+                },
+                "State": "completed",
+                "VolumeId": "vol-ffffffff",
+                "VolumeSize": 8
+            },
+            {
+                "Description": "c7n-test",
+                "Encrypted": false,
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0b818bbec5eebac4c",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 16,
+                    "minute": 9,
+                    "second": 25,
+                    "microsecond": 523000
+                },
+                "State": "completed",
+                "VolumeId": "vol-090f204348522c306",
+                "VolumeSize": 8
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "98a222b5-e785-48c7-9a59-8f8416284dbc",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "content-length": "1850",
+                "date": "Fri, 08 Mar 2019 18:02:29 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_2.json b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_ebs_snapshot_unused/ec2.DescribeSnapshots_2.json
@@ -0,0 +1,79 @@
+{
+    "status_code": 200,
+    "data": {
+        "Snapshots": [
+            {
+                "Description": "test",
+                "Encrypted": false,
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0bf9e1af959fbdddf",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 6,
+                    "hour": 0,
+                    "minute": 44,
+                    "second": 22,
+                    "microsecond": 972000
+                },
+                "State": "completed",
+                "VolumeId": "vol-0bf78c2aa3a923550",
+                "VolumeSize": 1
+            },
+            {
+                "Description": "Copied for DestinationAmi ami-008c67c239389d171 from SourceAmi ami-97785bed for SourceSnapshot snap-0fae6f7252388fc12. Task created on 1,552,061,232,790.",
+                "Encrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/798bc4bb-3079-4a9a-bc27-2c7f2b6c91d0",
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0b80955e4f7052f72",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 16,
+                    "minute": 12,
+                    "second": 36,
+                    "microsecond": 913000
+                },
+                "State": "completed",
+                "VolumeId": "vol-ffffffff",
+                "VolumeSize": 8
+            },
+            {
+                "Description": "c7n-test",
+                "Encrypted": false,
+                "OwnerId": "644160558196",
+                "Progress": "100%",
+                "SnapshotId": "snap-0b818bbec5eebac4c",
+                "StartTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 3,
+                    "day": 8,
+                    "hour": 16,
+                    "minute": 9,
+                    "second": 25,
+                    "microsecond": 523000
+                },
+                "State": "completed",
+                "VolumeId": "vol-090f204348522c306",
+                "VolumeSize": 8
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "71e80439-304b-4660-8fbb-f1ae2d98dc45",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "content-length": "1850",
+                "date": "Fri, 08 Mar 2019 18:02:30 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_ebs.py b/tests/test_ebs.py
--- a/tests/test_ebs.py
+++ b/tests/test_ebs.py
@@ -244,6 +244,33 @@ def test_snapshot_ami_snapshot_filter(self):
         self.assertEqual(len(resources), 2)
 
 
+class SnapshotUnusedTest(BaseTest):
+
+    def test_snapshot_unused(self):
+        factory = self.replay_flight_data("test_ebs_snapshot_unused")
+        p = self.load_policy(
+            {
+                "name": "snap-unused",
+                "resource": "ebs-snapshot",
+                "filters": [{"type": "unused", "value": True}],
+            },
+            session_factory=factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+
+        policy = self.load_policy(
+            {
+                "name": "snap-used",
+                "resource": "ebs-snapshot",
+                "filters": [{"type": "unused", "value": False}],
+            },
+            session_factory=factory,
+        )
+        resources = policy.run()
+        self.assertEqual(len(resources), 2)
+
+
 class SnapshotTrimTest(BaseTest):
 
     def test_snapshot_trim(self):