Repository: cloud-custodian/cloud-custodian

Issue:
Allow `events` to be optional for PHD type
```
policies:
  - name: phd-alerts
    resource: account
    comment: Olay PHD alerts
    mode:
      type: phd
      role: arn:aws:iam::1234567890:role/cloud_custodian_role
```

Should be valid for account level policies (PHD). 
The events[] list can be updated at any point and keeping this list up to date would be impossible.

Output for attempting:

```
Traceback (most recent call last):
  File "/usr/bin/custodian", line 10, in <module>
    sys.exit(main())
  File "/usr/lib/python2.7/site-packages/c7n/cli.py", line 374, in main
    command(config)
  File "/usr/lib/python2.7/site-packages/c7n/commands.py", line 65, in _load_policies
    collection = policy_load(options, fp, validate=validate, vars=vars)
  File "/usr/lib/python2.7/site-packages/c7n/policy.py", line 63, in load
    errors[1], errors[0]))
c7n.exceptions.PolicyValidationError: Failed to validate policy phd-alerts
 Error on policy:phd-alerts resource:account
u'events' is a required property

Failed validating u'required' in schema[5]:
    {u'additionalProperties': False,
     u'properties': {'categories': {u'items': {u'enum': [u'issue',
                                                         u'accountNotification',
                                                         u'scheduledChange']},
                                    u'type': u'array'},
                     u'concurrency': {u'type': u'integer'},
                     u'dead_letter_config': {u'type': u'object'},
                     u'environment': {u'type': u'object'},
                     'events': {u'items': {u'type': u'string'},
                                u'type': u'array'},
                     u'execution-options': {u'type': u'object'},
                     u'function-prefix': {u'type': u'string'},
                     u'kms_key_arn': {u'type': u'string'},
                     u'layers': {u'items': {u'type': u'string'},
                                 u'type': u'array'},
                     u'member-role': {u'type': u'string'},
                     u'memory': {u'type': u'number'},
                     u'packages': {u'items': {u'type': u'string'},
                                   u'type': u'array'},
                     u'role': {u'type': u'string'},
                     u'runtime': {u'enum': [u'python2.7',
                                            u'python3.6',
                                            u'python3.7']},
                     u'security_groups': {u'type': u'array'},
                     'statuses': {u'items': {u'enum': [u'open',
                                                       u'upcoming',
                                                       u'closed']},
                                  u'type': u'array'},
                     u'subnets': {u'type': u'array'},
                     u'tags': {u'type': u'object'},
                     u'timeout': {u'type': u'number'},
                     u'tracing_config': {u'type': u'object'},
                     u'type': {u'enum': [u'phd']}},
     u'required': [u'events', u'type'],
     u'type': u'object'}

On instance:
    {'role': 'arn:aws:iam::1234567890:role/cloud_custodian_role',
     'type': 'phd'}
```


Discussion:

Resolving patch:
diff --git a/c7n/policy.py b/c7n/policy.py
--- a/c7n/policy.py
+++ b/c7n/policy.py
@@ -597,7 +597,6 @@ class PHDMode(LambdaMode):
 
     schema = utils.type_schema(
         'phd',
-        required=['events'],
         events={'type': 'array', 'items': {'type': 'string'}},
         categories={'type': 'array', 'items': {
             'enum': ['issue', 'accountNotification', 'scheduledChange']}},
@@ -613,6 +612,10 @@ def validate(self):
             raise PolicyValidationError(
                 "policy:%s phd event mode not supported for resource:%s" % (
                     self.policy.name, self.policy.resource_type))
+        if 'events' not in self.policy.data['mode']:
+            raise PolicyValidationError(
+                'policy:%s phd event mode requires events for resource:%s' % (
+                    self.policy.name, self.policy.resource_type))
 
     @staticmethod
     def process_event_arns(client, event_arns):


Test patch:
diff --git a/tests/test_policy.py b/tests/test_policy.py
--- a/tests/test_policy.py
+++ b/tests/test_policy.py
@@ -1161,6 +1161,19 @@ def test_is_runnable_parse_dates(self):
         self.assertEqual(pull_mode.is_runnable(), True)
 
 
+class PhdModeTest(BaseTest):
+
+    def test_validation(self):
+        self.assertRaises(
+            PolicyValidationError,
+            self.load_policy,
+            {'name': 'xyz', 'resource': 'ec2',
+             'mode': {'type': 'phd'}})
+        self.load_policy(
+            {'name': 'abc', 'resource': 'account',
+             'mode': {'type': 'phd'}})
+
+
 class GuardModeTest(BaseTest):
 
     def test_unsupported_resource(self):