Repository: cloud-custodian/cloud-custodian

Issue:
Add delete action for AWS Cloudtrail resource
I dont see a delete action on aws.cloudtrail resource:

```
$ custodian schema aws.cloudtrail.actions
aws.cloudtrail:
  actions:
  - invoke-lambda
  - notify
  - post-finding
  - put-metric
  - set-logging
  - update-trail
```

Looking at the code it doesnt look too bad to add a delete action, should be just add something like below to `c7n/resources/cloudtrail.py`:

```python
@CloudTrail.action_registry.register('delete-trail')
class UpdateTrail(Action):
    """Delete trail.
    :Example:
    .. code-block:: yaml
       policies:
         - name: cloudtrail-delete
           resource: aws.cloudtrail
           filters:
            - type: value
              key: Name
              value: delete-me
              op: eq
           actions:
            - type: delete
    """
    schema = type_schema(
        'delete-trail',
        attributes={'type': 'object'},
        required=('attributes',))
    shape = 'DeleteTrailRequest'
    permissions = ('cloudtrail:DeleteTrail',)

    def validate(self):
        # do the validate

    def process(self, resources):
        # do the delete
```


Discussion:
seems reasonable, just wondering about use case for delete on trail.
We have one centrally created cloudtrail and unfortunately permissions
granted for others to create another cloudtrail that I cant get changed
right now. The first cloudtrail in an account is free, additional trails
are very expensive in certain setups.


Resolving patch:
diff --git a/c7n/resources/cloudtrail.py b/c7n/resources/cloudtrail.py
--- a/c7n/resources/cloudtrail.py
+++ b/c7n/resources/cloudtrail.py
@@ -15,7 +15,7 @@
 
 import logging
 
-from c7n.actions import Action
+from c7n.actions import Action, BaseAction
 from c7n.exceptions import PolicyValidationError
 from c7n.filters import ValueFilter, Filter
 from c7n.manager import resources
@@ -206,3 +206,35 @@ def process(self, resources):
                 client.start_logging(Name=r['Name'])
             else:
                 client.stop_logging(Name=r['Name'])
+
+
+@CloudTrail.action_registry.register('delete')
+class DeleteTrail(BaseAction):
+    """ Delete a cloud trail
+
+    :example:
+
+    .. code-block:: yaml
+
+      policies:
+        - name: delete-cloudtrail
+          resource: aws.cloudtrail
+          filters:
+           - type: value
+             key: Name
+             value: delete-me
+             op: eq
+          actions:
+           - type: delete
+    """
+
+    schema = type_schema('delete')
+    permissions = ('cloudtrail:DeleteTrail',)
+
+    def process(self, resources):
+        client = local_session(self.manager.session_factory).client('cloudtrail')
+        for r in resources:
+            try:
+                client.delete_trail(Name=r['Name'])
+            except client.exceptions.TrailNotFoundException:
+                continue


Test patch:
diff --git a/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_1.json b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_1.json
@@ -0,0 +1,16 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {
+            "RequestId": "9ecce740-41c8-470a-a540-5730226733a1",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "9ecce740-41c8-470a-a540-5730226733a1",
+                "content-type": "application/x-amz-json-1.1",
+                "content-length": "2",
+                "date": "Wed, 31 Jul 2019 23:59:03 GMT"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_2.json b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DeleteTrail_2.json
@@ -0,0 +1,21 @@
+{
+    "status_code": 400,
+    "data": {
+        "Error": {
+            "Message": "Unknown trail: arn:aws:cloudtrail:us-east-1:644160558196:trail/delete-me for the user: 644160558196",
+            "Code": "TrailNotFoundException"
+        },
+        "ResponseMetadata": {
+            "RequestId": "8cd9c101-bc05-44b9-8603-c66e45f51e5d",
+            "HTTPStatusCode": 400,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "8cd9c101-bc05-44b9-8603-c66e45f51e5d",
+                "content-type": "application/x-amz-json-1.1",
+                "content-length": "147",
+                "date": "Wed, 31 Jul 2019 23:59:07 GMT",
+                "connection": "close"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DescribeTrails_1.json b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DescribeTrails_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_cloudtrail_delete/cloudtrail.DescribeTrails_1.json
@@ -0,0 +1,63 @@
+{
+    "status_code": 200,
+    "data": {
+        "trailList": [
+            {
+                "Name": "S3-DataEvents",
+                "S3BucketName": "custodian-skunk-trails",
+                "S3KeyPrefix": "DataEvents",
+                "IncludeGlobalServiceEvents": true,
+                "IsMultiRegionTrail": true,
+                "HomeRegion": "us-east-1",
+                "TrailARN": "arn:aws:cloudtrail:us-east-1:644160558196:trail/S3-DataEvents",
+                "LogFileValidationEnabled": true,
+                "HasCustomEventSelectors": true,
+                "IsOrganizationTrail": false
+            },
+            {
+                "Name": "delete-me",
+                "S3BucketName": "c7n-sagemaker-test",
+                "IncludeGlobalServiceEvents": true,
+                "IsMultiRegionTrail": true,
+                "HomeRegion": "us-east-1",
+                "TrailARN": "arn:aws:cloudtrail:us-east-1:644160558196:trail/delete-me",
+                "LogFileValidationEnabled": true,
+                "HasCustomEventSelectors": false,
+                "IsOrganizationTrail": false
+            },
+            {
+                "Name": "orgTrail",
+                "S3BucketName": "c7n-vpc-flow-logs",
+                "IncludeGlobalServiceEvents": true,
+                "IsMultiRegionTrail": true,
+                "HomeRegion": "us-east-1",
+                "TrailARN": "arn:aws:cloudtrail:us-east-1:644160558196:trail/orgTrail",
+                "LogFileValidationEnabled": true,
+                "HasCustomEventSelectors": false,
+                "IsOrganizationTrail": true
+            },
+            {
+                "Name": "skunk-trails",
+                "S3BucketName": "custodian-skunk-trails",
+                "IncludeGlobalServiceEvents": true,
+                "IsMultiRegionTrail": true,
+                "HomeRegion": "us-east-1",
+                "TrailARN": "arn:aws:cloudtrail:us-east-1:644160558196:trail/skunk-trails",
+                "LogFileValidationEnabled": true,
+                "HasCustomEventSelectors": false,
+                "IsOrganizationTrail": false
+            }
+        ],
+        "ResponseMetadata": {
+            "RequestId": "1d7322f5-af1c-416f-8112-3a9103e01398",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "x-amzn-requestid": "1d7322f5-af1c-416f-8112-3a9103e01398",
+                "content-type": "application/x-amz-json-1.1",
+                "content-length": "1279",
+                "date": "Wed, 31 Jul 2019 23:59:03 GMT"
+            },
+            "RetryAttempts": 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_cloudtrail.py b/tests/test_cloudtrail.py
--- a/tests/test_cloudtrail.py
+++ b/tests/test_cloudtrail.py
@@ -151,3 +151,26 @@ def test_cloudtrail_resource_with_not_filter(self):
         )
         resources = p.run()
         self.assertEqual(len(resources), 1)
+
+    def test_cloudtrail_delete(self):
+        factory = self.replay_flight_data("test_cloudtrail_delete")
+        p = self.load_policy(
+            {
+                "name": "cloudtrail-resource",
+                "resource": "cloudtrail",
+                "filters": [{'type': 'value', 'key': 'Name', 'value': 'delete-me'}],
+                'actions': [{'type': 'delete'}],
+            },
+            session_factory=factory)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['Name'], 'delete-me')
+
+        if self.recording:
+            time.sleep(3)
+
+        client = factory().client('cloudtrail')
+        self.assertRaises(
+            client.exceptions.TrailNotFoundException,
+            client.delete_trail,
+            Name=resources[0]['Name'])