Repository: cloud-custodian/cloud-custodian

Issue:
aws - phd mode error

running a policy with phd execution mode generates an error

given policy

```yaml
policies:
  - name: health-event-notify
    resource: account
    description: |
      Health event notifications to SQS.
    mode:
      type: phd
      categories: ['issue','scheduledChange']
      statuses: ['open','upcoming']
      role: custodian-mu
```

results in
```
2020-09-17 09:37:55,669: custodian.policy:INFO Provisioning policy lambda: health-event-notify region: us-east-1
2020-09-17 09:37:55,924: custodian.output:ERROR Error while executing policy
Traceback (most recent call last):
  File "/home/kapilt/projects/cloud-custodian/c7n/policy.py", line 508, in provision
    return manager.publish(
  File "/home/kapilt/projects/cloud-custodian/c7n/mu.py", line 397, in publish
    if e.add(func):
  File "/home/kapilt/projects/cloud-custodian/c7n/mu.py", line 1104, in add
    pattern = self.render_event_pattern()
  File "/home/kapilt/projects/cloud-custodian/c7n/mu.py", line 1080, in render_event_pattern
    payload['detail']['eventTypeCategory'] = self.data['categories']
KeyError: 'detail'
```
custodian version: trunk, originally reported on gitter


Discussion:

Resolving patch:
diff --git a/c7n/mu.py b/c7n/mu.py
--- a/c7n/mu.py
+++ b/c7n/mu.py
@@ -1072,10 +1072,11 @@ def render_event_pattern(self):
             payload['detail-type'] = events
         elif event_type == 'phd':
             payload['source'] = ['aws.health']
+            payload.setdefault('detail', {})
             if self.data.get('events'):
-                payload['detail'] = {
+                payload['detail'].update({
                     'eventTypeCode': list(self.data['events'])
-                }
+                })
             if self.data.get('categories', []):
                 payload['detail']['eventTypeCategory'] = self.data['categories']
         elif event_type == 'hub-finding':


Test patch:
diff --git a/tests/data/placebo/test_phd_event_account/README b/tests/data/placebo/test_phd_event_account/README
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_phd_event_account/README
@@ -0,0 +1 @@
+Intentionally blank
diff --git a/tests/test_mu.py b/tests/test_mu.py
--- a/tests/test_mu.py
+++ b/tests/test_mu.py
@@ -233,6 +233,25 @@ def test_phd_mode(self):
              'source': ['aws.health']}
         )
 
+    def test_phd_mode_account(self):
+        factory = self.replay_flight_data('test_phd_event_account')
+        p = self.load_policy(
+            {'name': 'ec2-retire',
+             'resource': 'account',
+             'mode': {
+                 'categories': ['issue', 'scheduledChange'],
+                 'statuses': ['open', 'upcoming'],
+                 'type': 'phd'}}, session_factory=factory)
+
+        p_lambda = PolicyLambda(p)
+        events = p_lambda.get_events(factory)
+        self.assertEqual(
+            json.loads(events[0].render_event_pattern()),
+            {'detail': {
+                'eventTypeCategory': ['issue', 'scheduledChange']},
+             'source': ['aws.health']}
+        )
+
     def test_cloudtrail_delay(self):
         p = self.load_policy({
             'name': 'aws-account',