Repository: cloud-custodian/cloud-custodian

Issue:
ElastiCache - Add support for replication-groups resources
@kapilt Currently ElastiCache only can see resources that are created in a 'Cluster' mode.  If creating an ElastiCache NOT in cluster mode, c7n doesn't pick it up as it is a resource type of **replication-group** and would need to be able to pickup the replicationGroupId from the event as the resource Id.  https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elasticache.html#ElastiCache.Client.describe_replication_groups


Discussion:
PratMis: Not sure what's causing this test to fail.
Failure traceback:

```
[gw1] linux -- Python 3.6.10 /home/vsts/work/1/s/.tox/py36-cov/bin/python
 Traceback (most recent call last):
   File "/home/vsts/work/1/s/tests/test_mu.py", line 62, in test_generate_requirements
     assert set(packages) == set([
   Extra items in the right set:
   'urllib3'
   Use -v to get the full diff
```
kapilt: failure was unrelated, I've added a fix for that to trunk
PratMis: Thanks @kapilt !

Patch:
diff --git a/c7n/executor.py b/c7n/executor.py
index b5333fca2..cb1577034 100644
--- a/c7n/executor.py
+++ b/c7n/executor.py
@@ -13,33 +13,11 @@
 # limitations under the License.
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-from concurrent.futures import (
-    ProcessPoolExecutor, ThreadPoolExecutor)
-
-from c7n.registry import PluginRegistry
+from concurrent.futures import (ProcessPoolExecutor, ThreadPoolExecutor)  # noqa
 
 import threading
 
 
-class ExecutorRegistry(PluginRegistry):
-
-    def __init__(self, plugin_type):
-        super(ExecutorRegistry, self).__init__(plugin_type)
-
-        self.register('process', ProcessPoolExecutor)
-        self.register('thread', ThreadPoolExecutor)
-        self.register('main', MainThreadExecutor)
-
-
-def executor(name, **kw):
-    factory = executors.get(name)
-    # post element refactoring
-    # factory.validate(kw)
-    if factory is None:
-        raise ValueError("No Such Executor %s" % name)
-    return factory(**kw)
-
-
 class MainThreadExecutor(object):
     """ For running tests.
 
@@ -103,7 +81,3 @@ class MainThreadFuture(object):
 
     def add_done_callback(self, fn):
         return fn(self)
-
-
-executors = ExecutorRegistry('executor')
-executors.load_plugins()
diff --git a/c7n/mu.py b/c7n/mu.py
index c75ea5b0b..a50de5b24 100644
--- a/c7n/mu.py
+++ b/c7n/mu.py
@@ -338,8 +338,8 @@ def _package_deps(package, deps=None, ignore=()):
 def custodian_archive(packages=None):
     """Create a lambda code archive for running custodian.
 
-    Lambda archive currently always includes `c7n` and
-    `pkg_resources`. Add additional packages in the mode block.
+    Lambda archive currently always includes `c7n`.  Add additional
+    packages via function parameters, or in policy via mode block.
 
     Example policy that includes additional packages
 
@@ -355,7 +355,7 @@ def custodian_archive(packages=None):
     packages: List of additional packages to include in the lambda archive.
 
     """
-    modules = {'c7n', 'pkg_resources'}
+    modules = {'c7n'}
     if packages:
         modules = filter(None, modules.union(packages))
     return PythonPackageArchive(sorted(modules))
diff --git a/c7n/registry.py b/c7n/registry.py
index f582f04d5..953483546 100644
--- a/c7n/registry.py
+++ b/c7n/registry.py
@@ -117,17 +117,3 @@ class PluginRegistry(object):
 
     def items(self):
         return self._factories.items()
-
-    def load_plugins(self):
-        """ Load external plugins.
-
-        Custodian is intended to interact with internal and external systems
-        that are not suitable for embedding into the custodian code base.
-        """
-        try:
-            from pkg_resources import iter_entry_points
-        except ImportError:
-            return
-        for ep in iter_entry_points(group="custodian.%s" % self.plugin_type):
-            f = ep.load()
-            f()
diff --git a/c7n/resources/ec2.py b/c7n/resources/ec2.py
index abd9a5b64..f83ccdb9b 100644
--- a/c7n/resources/ec2.py
+++ b/c7n/resources/ec2.py
@@ -920,6 +920,112 @@ class SsmStatus(ValueFilter):
             r[self.annotation] = info_map.get(r['InstanceId'], {})
 
 
+@EC2.filter_registry.register('ssm-compliance')
+class SsmCompliance(Filter):
+    """Filter ec2 instances by their ssm compliance status.
+
+    :Example:
+
+    Find non-compliant ec2 instances.
+
+    .. code-block:: yaml
+
+        policies:
+          - name: ec2-ssm-compliance
+            resource: ec2
+            filters:
+              - type: ssm-compliance
+                compliance_types:
+                  - Association
+                  - Patch
+                severity:
+                  - CRITICAL
+                  - HIGH
+                  - MEDIUM
+                  - LOW
+                  - UNSPECIFIED
+                states:
+                  - NON_COMPLIANT
+                eval_filters:
+                 - type: value
+                   key: ExecutionSummary.ExecutionTime
+                   value_type: age
+                   value: 30
+                   op: less-than
+    """
+    schema = type_schema(
+        'ssm-compliance',
+        **{'required': ['compliance_types'],
+           'compliance_types': {'type': 'array', 'items': {'type': 'string'}},
+           'severity': {'type': 'array', 'items': {'type': 'string'}},
+           'op': {'enum': ['or', 'and']},
+           'eval_filters': {'type': 'array', 'items': {
+                            'oneOf': [
+                                {'$ref': '#/definitions/filters/valuekv'},
+                                {'$ref': '#/definitions/filters/value'}]}},
+           'states': {'type': 'array',
+                      'default': ['NON_COMPLIANT'],
+                      'items': {
+                          'enum': [
+                              'COMPLIANT',
+                              'NON_COMPLIANT'
+                          ]}}})
+    permissions = ('ssm:ListResourceComplianceSummaries',)
+    annotation = 'c7n:ssm-compliance'
+
+    def process(self, resources, event=None):
+        op = self.data.get('op', 'or') == 'or' and any or all
+        eval_filters = []
+        for f in self.data.get('eval_filters', ()):
+            vf = ValueFilter(f)
+            vf.annotate = False
+            eval_filters.append(vf)
+
+        client = utils.local_session(self.manager.session_factory).client('ssm')
+        filters = [
+            {
+                'Key': 'Status',
+                'Values': self.data['states'],
+                'Type': 'EQUAL'
+            },
+            {
+                'Key': 'ComplianceType',
+                'Values': self.data['compliance_types'],
+                'Type': 'EQUAL'
+            }
+        ]
+        severity = self.data.get('severity')
+        if severity:
+            filters.append(
+                {
+                    'Key': 'OverallSeverity',
+                    'Values': severity,
+                    'Type': 'EQUAL'
+                })
+
+        resource_map = {}
+        pager = client.get_paginator('list_resource_compliance_summaries')
+        for page in pager.paginate(Filters=filters):
+            items = page['ResourceComplianceSummaryItems']
+            for i in items:
+                if not eval_filters:
+                    resource_map.setdefault(
+                        i['ResourceId'], []).append(i)
+                    continue
+                if op([f.match(i) for f in eval_filters]):
+                    resource_map.setdefault(
+                        i['ResourceId'], []).append(i)
+
+        results = []
+        for r in resources:
+            result = resource_map.get(r['InstanceId'])
+            if result:
+                r[self.annotation] = result
+                results.append(r)
+
+        return results
+
+
 @actions.register('set-monitoring')
 class MonitorInstances(BaseAction, StateTransitionFilter):
     """Action on EC2 Instances to enable/disable detailed monitoring
diff --git a/c7n/resources/elasticache.py b/c7n/resources/elasticache.py
index 140789149..f809233a6 100644
--- a/c7n/resources/elasticache.py
+++ b/c7n/resources/elasticache.py
@@ -458,3 +458,16 @@ def _cluster_eligible_for_snapshot(cluster):
         cluster['Engine'] != 'memcached' and not
         TTYPE.match(cluster['CacheNodeType'])
     )
+
+
+@resources.register('elasticache-group')
+class ElastiCacheReplicationGroup(QueryResourceManager):
+
+    class resource_type(TypeInfo):
+        service = "elasticache"
+        enum_spec = ('describe_replication_groups',
+                     'ReplicationGroups[]', None)
+        arn_type = 'replicationgroup'
+        id = name = dimension = 'ReplicationGroupId'
+
+    permissions = ('elasticache:DescribeReplicationGroups',)
diff --git a/c7n/resources/resource_map.py b/c7n/resources/resource_map.py
index e2455a63c..7aea903d7 100644
--- a/c7n/resources/resource_map.py
+++ b/c7n/resources/resource_map.py
@@ -51,6 +51,7 @@ ResourceMap = {
     "aws.elasticbeanstalk": "c7n.resources.elasticbeanstalk.ElasticBeanstalk",
     "aws.elasticbeanstalk-environment": (
         "c7n.resources.elasticbeanstalk.ElasticBeanstalkEnvironment"),
+    "aws.elasticache-group": "c7n.resources.elasticache.ElastiCacheReplicationGroup",
     "aws.elasticsearch": "c7n.resources.elasticsearch.ElasticSearchDomain",
     "aws.elb": "c7n.resources.elb.ELB",
     "aws.emr": "c7n.resources.emr.EMRCluster",
diff --git a/docs/source/aws/aws-modes.rst b/docs/source/aws/aws-modes.rst
index 62d63409b..3c6716ce6 100644
--- a/docs/source/aws/aws-modes.rst
+++ b/docs/source/aws/aws-modes.rst
@@ -37,7 +37,7 @@ Custodian can run in numerous modes depending on the provider with the default b
 - ec2-instance-state:
     Runs custodian in AWS lambda and is triggered by ec2 instance state changes. This is useful if you
     have policies that are specific to ec2. See `EC2 lifecycles
-    <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html/>`_ for more details.
+    <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html>`_ for more details.
 
   .. c7n-schema:: mode.ec2-instance-state
 
@@ -45,7 +45,7 @@ Custodian can run in numerous modes depending on the provider with the default b
 - asg-instance-state:
     Runs custodian in AWS lambda and is triggered by asg instance state changes. This is useful if you
     have policies that are specific to asg. See `ASG lifecycle hooks
-    <https://docs.aws.amazon.com/autoscaling/ec2/userguide/lifecycle-hooks.html/>`_ for more details.
+    <https://docs.aws.amazon.com/autoscaling/ec2/userguide/lifecycle-hooks.html>`_ for more details.
 
   .. c7n-schema:: mode.asg-instance-state
 


Test patch:
diff --git a/tests/data/placebo/test_ec2_ssm_compliance_filter/ec2.DescribeInstances_1.json b/tests/data/placebo/test_ec2_ssm_compliance_filter/ec2.DescribeInstances_1.json
new file mode 100644
index 000000000..5ee1da1b1
--- /dev/null
+++ b/tests/data/placebo/test_ec2_ssm_compliance_filter/ec2.DescribeInstances_1.json
@@ -0,0 +1,326 @@
+{
+    "status_code": 200,
+    "data": {
+        "Reservations": [
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-0f65671a86f061fcd",
+                        "InstanceId": "i-0dea82d960d56dc1d",
+                        "InstanceType": "t2.medium",
+                        "KeyName": "ssm-dev",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2019,
+                            "month": 1,
+                            "day": 30,
+                            "hour": 13,
+                            "minute": 14,
+                            "second": 36,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+                        "Placement": {
+                            "AvailabilityZone": "us-east-2a",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-11-50.us-east-2.compute.internal",
+                        "PrivateIpAddress": "172.31.11.50",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-18-191-215-59.us-east-2.compute.amazonaws.com",
+                        "PublicIpAddress": "18.191.215.59",
+                        "State": {
+                            "Code": 64,
+                            "Name": "stopping"
+                        },
+                        "StateTransitionReason": "User initiated (2019-01-30 13:33:45 GMT)",
+                        "SubnetId": "subnet-db9f62b2",
+                        "VpcId": "vpc-5f6c9936",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/sda1",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2019,
+                                        "month": 1,
+                                        "day": 30,
+                                        "hour": 13,
+                                        "minute": 14,
+                                        "second": 36,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-08d1573a7cd3fd1f2"
+                                }
+                            }
+                        ],
+                        "ClientToken": "",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "IamInstanceProfile": {
+                            "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
+                            "Id": "AIPAJO5EMJ3YEMNUF5ZWM"
+                        },
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-18-191-215-59.us-east-2.compute.amazonaws.com",
+                                    "PublicIp": "18.191.215.59"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2019,
+                                        "month": 1,
+                                        "day": 30,
+                                        "hour": 13,
+                                        "minute": 14,
+                                        "second": 36,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-0bc8d36721d13f0a6",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "Primary network interface",
+                                "Groups": [
+                                    {
+                                        "GroupName": "launch-wizard-1",
+                                        "GroupId": "sg-bebafdd5"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "02:27:4e:43:cb:e6",
+                                "NetworkInterfaceId": "eni-01075318d08f25bf5",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-11-50.us-east-2.compute.internal",
+                                "PrivateIpAddress": "172.31.11.50",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-18-191-215-59.us-east-2.compute.amazonaws.com",
+                                            "PublicIp": "18.191.215.59"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-11-50.us-east-2.compute.internal",
+                                        "PrivateIpAddress": "172.31.11.50"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-db9f62b2",
+                                "VpcId": "vpc-5f6c9936"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/sda1",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "launch-wizard-1",
+                                "GroupId": "sg-bebafdd5"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "StateReason": {
+                            "Code": "Client.UserInitiatedShutdown",
+                            "Message": "Client.UserInitiatedShutdown: User initiated shutdown"
+                        },
+                        "Tags": [
+                            {
+                                "Key": "Name",
+                                "Value": "kapil-ssm-dev"
+                            }
+                        ],
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 2,
+                            "ThreadsPerCore": 1
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "ReservationId": "r-07103c7504d70d128"
+            },
+            {
+                "Groups": [],
+                "Instances": [
+                    {
+                        "AmiLaunchIndex": 0,
+                        "ImageId": "ami-0f65671a86f061fcd",
+                        "InstanceId": "i-0ba3874e85bb97244",
+                        "InstanceType": "t2.medium",
+                        "KeyName": "ssm-dev",
+                        "LaunchTime": {
+                            "__class__": "datetime",
+                            "year": 2019,
+                            "month": 1,
+                            "day": 30,
+                            "hour": 11,
+                            "minute": 58,
+                            "second": 37,
+                            "microsecond": 0
+                        },
+                        "Monitoring": {
+                            "State": "disabled"
+                        },
+                        "Placement": {
+                            "AvailabilityZone": "us-east-2a",
+                            "GroupName": "",
+                            "Tenancy": "default"
+                        },
+                        "PrivateDnsName": "ip-172-31-10-93.us-east-2.compute.internal",
+                        "PrivateIpAddress": "172.31.10.93",
+                        "ProductCodes": [],
+                        "PublicDnsName": "ec2-18-222-166-169.us-east-2.compute.amazonaws.com",
+                        "PublicIpAddress": "18.222.166.169",
+                        "State": {
+                            "Code": 16,
+                            "Name": "running"
+                        },
+                        "StateTransitionReason": "",
+                        "SubnetId": "subnet-db9f62b2",
+                        "VpcId": "vpc-5f6c9936",
+                        "Architecture": "x86_64",
+                        "BlockDeviceMappings": [
+                            {
+                                "DeviceName": "/dev/sda1",
+                                "Ebs": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2019,
+                                        "month": 1,
+                                        "day": 30,
+                                        "hour": 11,
+                                        "minute": 58,
+                                        "second": 37,
+                                        "microsecond": 0
+                                    },
+                                    "DeleteOnTermination": true,
+                                    "Status": "attached",
+                                    "VolumeId": "vol-0fcfccae49c73e29a"
+                                }
+                            }
+                        ],
+                        "ClientToken": "",
+                        "EbsOptimized": false,
+                        "EnaSupport": true,
+                        "Hypervisor": "xen",
+                        "IamInstanceProfile": {
+                            "Arn": "arn:aws:iam::644160558196:instance-profile/CloudCustodianRole",
+                            "Id": "AIPAJO5EMJ3YEMNUF5ZWM"
+                        },
+                        "NetworkInterfaces": [
+                            {
+                                "Association": {
+                                    "IpOwnerId": "amazon",
+                                    "PublicDnsName": "ec2-18-222-166-169.us-east-2.compute.amazonaws.com",
+                                    "PublicIp": "18.222.166.169"
+                                },
+                                "Attachment": {
+                                    "AttachTime": {
+                                        "__class__": "datetime",
+                                        "year": 2019,
+                                        "month": 1,
+                                        "day": 30,
+                                        "hour": 11,
+                                        "minute": 58,
+                                        "second": 37,
+                                        "microsecond": 0
+                                    },
+                                    "AttachmentId": "eni-attach-0dbd4eeabb5c3ffa0",
+                                    "DeleteOnTermination": true,
+                                    "DeviceIndex": 0,
+                                    "Status": "attached"
+                                },
+                                "Description": "",
+                                "Groups": [
+                                    {
+                                        "GroupName": "launch-wizard-1",
+                                        "GroupId": "sg-bebafdd5"
+                                    }
+                                ],
+                                "Ipv6Addresses": [],
+                                "MacAddress": "02:ac:dd:b6:54:8a",
+                                "NetworkInterfaceId": "eni-0fe02396b03961784",
+                                "OwnerId": "644160558196",
+                                "PrivateDnsName": "ip-172-31-10-93.us-east-2.compute.internal",
+                                "PrivateIpAddress": "172.31.10.93",
+                                "PrivateIpAddresses": [
+                                    {
+                                        "Association": {
+                                            "IpOwnerId": "amazon",
+                                            "PublicDnsName": "ec2-18-222-166-169.us-east-2.compute.amazonaws.com",
+                                            "PublicIp": "18.222.166.169"
+                                        },
+                                        "Primary": true,
+                                        "PrivateDnsName": "ip-172-31-10-93.us-east-2.compute.internal",
+                                        "PrivateIpAddress": "172.31.10.93"
+                                    }
+                                ],
+                                "SourceDestCheck": true,
+                                "Status": "in-use",
+                                "SubnetId": "subnet-db9f62b2",
+                                "VpcId": "vpc-5f6c9936"
+                            }
+                        ],
+                        "RootDeviceName": "/dev/sda1",
+                        "RootDeviceType": "ebs",
+                        "SecurityGroups": [
+                            {
+                                "GroupName": "launch-wizard-1",
+                                "GroupId": "sg-bebafdd5"
+                            }
+                        ],
+                        "SourceDestCheck": true,
+                        "Tags": [
+                            {
+                                "Key": "Name",
+                                "Value": "kapil-ssm-dev"
+                            }
+                        ],
+                        "VirtualizationType": "hvm",
+                        "CpuOptions": {
+                            "CoreCount": 2,
+                            "ThreadsPerCore": 1
+                        },
+                        "CapacityReservationSpecification": {
+                            "CapacityReservationPreference": "open"
+                        },
+                        "HibernationOptions": {
+                            "Configured": false
+                        }
+                    }
+                ],
+                "OwnerId": "644160558196",
+                "ReservationId": "r-074f65542bb72fd56"
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "8151c8c3-afeb-4a62-b10d-b801d72a7458",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "content-type": "text/xml;charset=UTF-8",
+                "transfer-encoding": "chunked",
+                "vary": "Accept-Encoding",
+                "date": "Wed, 30 Jan 2019 13:34:16 GMT",
+                "server": "AmazonEC2"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
diff --git a/tests/data/placebo/test_ec2_ssm_compliance_filter/ssm.ListResourceComplianceSummaries_1.json b/tests/data/placebo/test_ec2_ssm_compliance_filter/ssm.ListResourceComplianceSummaries_1.json
new file mode 100644
index 000000000..cddb0b11a
--- /dev/null
+++ b/tests/data/placebo/test_ec2_ssm_compliance_filter/ssm.ListResourceComplianceSummaries_1.json
@@ -0,0 +1,150 @@
+{
+  "status_code": 200,
+  "data": {
+    "ResourceComplianceSummaryItems": [
+      {
+        "ComplianceType": "Association",
+        "CompliantSummary": {
+          "CompliantCount": 1,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 1
+          }
+        },
+        "ExecutionSummary": {
+          "ExecutionTime": "2020-03-20 10:52:50-04:00"
+        },
+        "NonCompliantSummary": {
+          "NonCompliantCount": 3,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 3
+          }
+        },
+        "OverallSeverity": "UNSPECIFIED",
+        "ResourceId": "i-0dea82d960d56dc1d",
+        "ResourceType": "ManagedInstance",
+        "Status": "NON_COMPLIANT"
+      },
+      {
+        "ComplianceType": "Patch",
+        "CompliantSummary": {
+          "CompliantCount": 310,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 310
+          }
+        },
+        "ExecutionSummary": {
+          "ExecutionId": "e44bffd7-4017-44ec-80f9-a6fbf932672f",
+          "ExecutionTime": "2020-03-19 18:50:59-04:00",
+          "ExecutionType": "Command"
+        },
+        "NonCompliantSummary": {
+          "NonCompliantCount": 36,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 36
+          }
+        },
+        "OverallSeverity": "UNSPECIFIED",
+        "ResourceId": "i-0dea82d960d56dc1d",
+        "ResourceType": "ManagedInstance",
+        "Status": "NON_COMPLIANT"
+      },
+      {
+        "ComplianceType": "Association",
+        "CompliantSummary": {
+          "CompliantCount": 1,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 1
+          }
+        },
+        "ExecutionSummary": {
+          "ExecutionTime": "2020-03-20 10:52:50-04:00"
+        },
+        "NonCompliantSummary": {
+          "NonCompliantCount": 3,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 3
+          }
+        },
+        "OverallSeverity": "UNSPECIFIED",
+        "ResourceId": "i-0ba3874e85bb97244",
+        "ResourceType": "ManagedInstance",
+        "Status": "NON_COMPLIANT"
+      },
+      {
+        "ComplianceType": "Patch",
+        "CompliantSummary": {
+          "CompliantCount": 310,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 310
+          }
+        },
+        "ExecutionSummary": {
+          "ExecutionId": "e44bffd7-4017-44ec-80f9-a6fbf932672f",
+          "ExecutionTime": "2020-03-19 18:50:59-04:00",
+          "ExecutionType": "Command"
+        },
+        "NonCompliantSummary": {
+          "NonCompliantCount": 36,
+          "SeveritySummary": {
+            "CriticalCount": 0,
+            "HighCount": 0,
+            "InformationalCount": 0,
+            "LowCount": 0,
+            "MediumCount": 0,
+            "UnspecifiedCount": 36
+          }
+        },
+        "OverallSeverity": "UNSPECIFIED",
+        "ResourceId": "i-0ba3874e85bb97244",
+        "ResourceType": "ManagedInstance",
+        "Status": "NON_COMPLIANT"
+      }
+    ],
+    "ResponseMetadata": {
+      "HTTPHeaders": {
+        "content-length": "12345",
+        "content-type": "application/x-amz-json-1.1",
+        "date": "Fri, 20 Mar 2020 15:09:20 GMT",
+        "x-amzn-requestid": "88383b45-36f4-44bb-b8a6-942dd5ffca3b"
+      },
+      "HTTPStatusCode": 200,
+      "RequestId": "88383b45-36f4-44bb-b8a6-942dd5ffca3b",
+      "RetryAttempts": 0
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_elasticache_replication_group/elasticache.DescribeReplicationGroups_1.json b/tests/data/placebo/test_elasticache_replication_group/elasticache.DescribeReplicationGroups_1.json
new file mode 100644
index 000000000..fbe4e5cf2
--- /dev/null
+++ b/tests/data/placebo/test_elasticache_replication_group/elasticache.DescribeReplicationGroups_1.json
@@ -0,0 +1,73 @@
+{
+    "status_code": 200,
+    "data": {
+        "ReplicationGroups": [
+            {
+                "ReplicationGroupId": "test-c7n-rg",
+                "Description": "test-c7n-rg",
+                "Status": "available",
+                "PendingModifiedValues": {},
+                "MemberClusters": [
+                    "test-c7n-rg-001",
+                    "test-c7n-rg-002"
+                ],
+                "NodeGroups": [
+                    {
+                        "NodeGroupId": "0001",
+                        "Status": "available",
+                        "PrimaryEndpoint": {
+                            "Address": "test-c7n-rg.qgcgte.ng.0001.use1.cache.amazonaws.com",
+                            "Port": 6379
+                        },
+                        "ReaderEndpoint": {
+                            "Address": "test-c7n-rg-ro.qgcgte.ng.0001.use1.cache.amazonaws.com",
+                            "Port": 6379
+                        },
+                        "NodeGroupMembers": [
+                            {
+                                "CacheClusterId": "test-c7n-rg-001",
+                                "CacheNodeId": "0001",
+                                "ReadEndpoint": {
+                                    "Address": "test-c7n-rg-001.qgcgte.0001.use1.cache.amazonaws.com",
+                                    "Port": 6379
+                                },
+                                "PreferredAvailabilityZone": "us-east-1a",
+                                "CurrentRole": "primary"
+                            },
+                            {
+                                "CacheClusterId": "test-c7n-rg-002",
+                                "CacheNodeId": "0001",
+                                "ReadEndpoint": {
+                                    "Address": "test-c7n-rg-002.qgcgte.0001.use1.cache.amazonaws.com",
+                                    "Port": 6379
+                                },
+                                "PreferredAvailabilityZone": "us-east-1a",
+                                "CurrentRole": "replica"
+                            }
+                        ]
+                    }
+                ],
+                "SnapshottingClusterId": "test-c7n-rg-002",
+                "AutomaticFailover": "enabled",
+                "SnapshotRetentionLimit": 1,
+                "SnapshotWindow": "03:00-04:00",
+                "ClusterEnabled": false,
+                "CacheNodeType": "cache.r5.large",
+                "AuthTokenEnabled": false,
+                "TransitEncryptionEnabled": false,
+                "AtRestEncryptionEnabled": false
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "ca18b602-dd47-44d2-97b0-0b02dea5556d",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "ca18b602-dd47-44d2-97b0-0b02dea5556d",
+                "content-type": "text/xml",
+                "content-length": "2848",
+                "date": "Tue, 11 Feb 2020 18:12:43 GMT"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_ec2.py b/tests/test_ec2.py
index 2b0eb8497..e949d90ff 100644
--- a/tests/test_ec2.py
+++ b/tests/test_ec2.py
@@ -263,6 +263,34 @@ class TestSsm(BaseTest):
             [r['InstanceId'] for r in resources],
             ['i-0dea82d960d56dc1d', 'i-0ba3874e85bb97244'])
 
+    def test_ssm_compliance(self):
+        session_factory = self.replay_flight_data('test_ec2_ssm_compliance_filter')
+        policy = self.load_policy({
+            'name': 'ec2-ssm-compliance',
+            'resource': 'aws.ec2',
+            'filters': [
+                {'type': 'ssm-compliance',
+                 'compliance_types': [
+                     'Association',
+                     'Patch'
+                 ],
+                 'severity': [
+                     'CRITICAL',
+                     'HIGH',
+                     'MEDIUM',
+                     'LOW',
+                     'UNSPECIFIED'
+                 ],
+                 'states': ['NON_COMPLIANT']}]},
+            session_factory=session_factory,
+            config={'region': 'us-east-2'})
+        resources = policy.run()
+        self.assertEqual(len(resources), 2)
+        self.assertTrue('c7n:ssm-compliance' in resources[0])
+        self.assertEqual(
+            [r['InstanceId'] for r in resources],
+            ['i-0dea82d960d56dc1d', 'i-0ba3874e85bb97244'])
+
 
 class TestHealthEventsFilter(BaseTest):
 
diff --git a/tests/test_elasticache.py b/tests/test_elasticache.py
index 814a3e380..f36f010ba 100644
--- a/tests/test_elasticache.py
+++ b/tests/test_elasticache.py
@@ -458,3 +458,15 @@ class TestModifyVpcSecurityGroupsAction(BaseTest):
         self.assertEqual(len(resources[0]["SecurityGroups"]), 1)
         self.assertEqual(len(clean_resources[0]["SecurityGroups"]), 2)
         self.assertEqual(len(clean_resources), 3)
+
+
+class TestElastiCacheReplicationGroup(BaseTest):
+
+    def test_elasticache_replication_group(self):
+        session_factory = self.replay_flight_data("test_elasticache_replication_group")
+        p = self.load_policy(
+            {"name": "elasticache-rg", "resource": "elasticache-group"},
+            session_factory=session_factory,)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['ReplicationGroupId'], 'test-c7n-rg')
diff --git a/tests/test_mu.py b/tests/test_mu.py
index 5896ed967..af0cba3e3 100644
--- a/tests/test_mu.py
+++ b/tests/test_mu.py
@@ -995,7 +995,6 @@ class PythonArchiveTest(unittest.TestCase):
         archive.close()
         filenames = archive.get_filenames()
         self.assertTrue("c7n/__init__.py" in filenames)
-        self.assertTrue("pkg_resources/__init__.py" in filenames)
 
     def make_file(self):
         bench = tempfile.mkdtemp()