Repository: cloud-custodian/cloud-custodian

Issue:
Bug in `Notify`'s expand_variables when to_from or cc_from present.
`TypeError: __init__() takes exactly 3 arguments (2 given)`


Discussion:

Resolving patch:
diff --git a/c7n/actions.py b/c7n/actions.py
--- a/c7n/actions.py
+++ b/c7n/actions.py
@@ -400,7 +400,9 @@ class Notify(EventAction):
 
     schema = {
         'type': 'object',
-        'required': ['type', 'transport', 'to'],
+        'oneOf': [
+            {'required': ['type', 'transport', 'to']},
+            {'required': ['type', 'transport', 'to_from']}],
         'properties': {
             'type': {'enum': ['notify']},
             'to': {'type': 'array', 'items': {'type': 'string'}},
@@ -451,13 +453,13 @@ def expand_variables(self, message):
             to_from['url'] = to_from['url'].format(**message)
             if 'expr' in to_from:
                 to_from['expr'] = to_from['expr'].format(**message)
-            p['to'] = ValuesFrom(to_from).get_values()
+            p['to'] = ValuesFrom(to_from, self.manager).get_values()
         if 'cc_from' in self.data:
             cc_from = self.data['cc_from'].copy()
             cc_from['url'] = cc_from['url'].format(**message)
             if 'expr' in cc_from:
                 cc_from['expr'] = cc_from['expr'].format(**message)
-            p['cc'] = ValuesFrom(cc_from).get_values()
+            p['cc'] = ValuesFrom(cc_from, self.manager).get_values()
         return p
 
     def process(self, resources, event=None):
@@ -502,7 +504,10 @@ def send_sns(self, message):
 
     def send_sqs(self, message):
         queue = self.data['transport']['queue']
-        if queue.startswith('https://sqs.'):
+        if queue.startswith('https://queue.amazonaws.com'):
+            region = 'us-east-1'
+            queue_url = queue
+        elif queue.startswith('https://sqs.'):
             region = queue.split('.', 2)[1]
             queue_url = queue
         elif queue.startswith('arn:sqs'):


Test patch:
diff --git a/tests/data/placebo/test_notify_address_from/iam.ListAccountAliases_1.json b/tests/data/placebo/test_notify_address_from/iam.ListAccountAliases_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/iam.ListAccountAliases_1.json
@@ -0,0 +1,20 @@
+{
+    "status_code": 200, 
+    "data": {
+        "AccountAliases": [
+            "custodian-skunk-works"
+        ], 
+        "IsTruncated": false, 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "23d8808e-61b7-11e7-8709-2f131dd3413d", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "23d8808e-61b7-11e7-8709-2f131dd3413d", 
+                "date": "Wed, 05 Jul 2017 19:21:26 GMT", 
+                "content-length": "400", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.CreateQueue_1.json b/tests/data/placebo/test_notify_address_from/sqs.CreateQueue_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.CreateQueue_1.json
@@ -0,0 +1,19 @@
+{
+    "status_code": 200, 
+    "data": {
+        "QueueUrl": "https://queue.amazonaws.com/644160558196/c7n-notify-test", 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "352c4c90-a62e-5beb-8c69-1d47985b0cd7", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "352c4c90-a62e-5beb-8c69-1d47985b0cd7", 
+                "content-length": "327", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:21:25 GMT", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.DeleteQueue_1.json b/tests/data/placebo/test_notify_address_from/sqs.DeleteQueue_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.DeleteQueue_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "117169bc-b037-58dc-9dde-386b8e8a1eb2", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "117169bc-b037-58dc-9dde-386b8e8a1eb2", 
+                "content-length": "211", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:22:37 GMT", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.GetQueueAttributes_1.json b/tests/data/placebo/test_notify_address_from/sqs.GetQueueAttributes_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.GetQueueAttributes_1.json
@@ -0,0 +1,31 @@
+{
+    "status_code": 200, 
+    "data": {
+        "Attributes": {
+            "ApproximateNumberOfMessagesNotVisible": "0", 
+            "MessageRetentionPeriod": "345600", 
+            "ApproximateNumberOfMessagesDelayed": "0", 
+            "MaximumMessageSize": "262144", 
+            "CreatedTimestamp": "1499282485", 
+            "ApproximateNumberOfMessages": "0", 
+            "ReceiveMessageWaitTimeSeconds": "0", 
+            "DelaySeconds": "0", 
+            "VisibilityTimeout": "30", 
+            "LastModifiedTimestamp": "1499282485", 
+            "QueueArn": "arn:aws:sqs:us-east-1:644160558196:c7n-notify-test"
+        }, 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "41613406-ae72-57a0-84f5-65d19004ea3f", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "41613406-ae72-57a0-84f5-65d19004ea3f", 
+                "content-length": "1169", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:21:26 GMT", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.ListQueues_1.json b/tests/data/placebo/test_notify_address_from/sqs.ListQueues_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.ListQueues_1.json
@@ -0,0 +1,21 @@
+{
+    "status_code": 200, 
+    "data": {
+        "QueueUrls": [
+            "https://queue.amazonaws.com/644160558196/c7n-notify-test"
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "7f052c96-4188-5a47-b39f-7d417ffe847a", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "7f052c96-4188-5a47-b39f-7d417ffe847a", 
+                "content-length": "323", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:21:26 GMT", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.ReceiveMessage_1.json b/tests/data/placebo/test_notify_address_from/sqs.ReceiveMessage_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.ReceiveMessage_1.json
@@ -0,0 +1,32 @@
+{
+    "status_code": 200, 
+    "data": {
+        "Messages": [
+            {
+                "Body": "eJzNlVlv00AQx9/9KSo/4/qIY2I/UYF4IoUewANC1XY9Tpbs4e6Rxq347uxhEktUQUKI4jfPjOf/m8O7j1GMMBaG67g5ibFRWrQE8URtDN8k90JuVPziZB90Q1oXV5VlXmXz+SKvK++WsCKCO5dRCSClk3z8TAf7YxRjfNNJwcKLkdRFd4RCk6bpFsm0E7QFqVKWpTUrcVUMu5lq86Kos63qMM5LltlnxdPrVLOe1WtBLrwK7HrpsgFDhAbeTkiGfE3flAWIvjujFs9NgLE1fIliBq9gh1hP4RRboOhrwDvmHHpwybjQpBu8gpaIq15IHQq6M2B8yFrrXtmavOEUMfQgOLpXLlk6nVyKX/Ik5Es0KB1PddSdssyBuheU4CGohIkqT/p/DPWJxjz7nP/JaMJiSFDCSLz3OBtHbNKTBLWtjRpxCdW29p/zu3AgH0OL/hjOoYS6YQv+JOGG0incXu+s76XYEdsxODfsFuT7bmnR0ArUudCfiCK31KNnnvav4LlEo8glaAtoF/gDSCL8WTYr51UW1I7AvQGKBmgPZFakWSKN19C+nbT0QByms0Q2n2Fjmivy4IsrqiIvS5/ntQQr114TZlHtT+/ceVnXxaIoF/PfYR14LgED2cLo+IyIdimvAAveTsJ8Hb9Yfd8JJXpwHwnj13kWfO/sab60l0JHjlP6ws+kvwSQ5I0dTWP3sdlfCM10SM3TO/QDzy8Cvw==", 
+                "Attributes": {
+                    "ApproximateFirstReceiveTimestamp": "1499282490188", 
+                    "SenderId": "AIDAJEZOTH6YPO3DY45QW", 
+                    "ApproximateReceiveCount": "1", 
+                    "SentTimestamp": "1499282486808"
+                }, 
+                "ReceiptHandle": "AQEB3pXw3hpkgOyXt0wnKUGi36MDNoIAl6b55MIxYvFA3aj9cS7s0N6wG8wOIuRDnKypghoOCYH3cGHFWQqYd3Ls7QTbPyeFSlBbXeF0u9Ys+F73YiuV1L3QdLftz/z1KHHRfEIRchAT3XONIWzMnhMkMdZksEtaP3aZuRKt5340lpt6FffBlmP4DzahyyHCEHCYWyZzMEIhM2CgVFwYjPPCewIeX0EljvFiugwtXtA0voXOjydBCZAge7I7Lm3xGnv1aOMAUohbi9bIC4jI5IRwO1tyQWaRjXWOeoE1L7JJbfBkjMUhI4qP3J7g+A9S1pj8xFvdNwDjBTWS2kL46R1UunHDZlv4ezFXSsa3DtJpNmzs/Y7ZomAg7KyZx829bY0WwulU1OyWe8yK1EpMNHsYHQ==", 
+                "MD5OfBody": "9e6e42bca67c80b24271e60a8f956bb7", 
+                "MessageId": "0e8d46b1-e569-4e06-9033-3809eb38d48b"
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "9e80e979-a067-5f9d-b8fb-b8ae9e1de8a1", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "9e80e979-a067-5f9d-b8fb-b8ae9e1de8a1", 
+                "content-length": "1907", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:21:30 GMT", 
+                "content-type": "text/xml"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_notify_address_from/sqs.SendMessage_1.json b/tests/data/placebo/test_notify_address_from/sqs.SendMessage_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_notify_address_from/sqs.SendMessage_1.json
@@ -0,0 +1,21 @@
+{
+    "status_code": 200, 
+    "data": {
+        "MD5OfMessageBody": "9e6e42bca67c80b24271e60a8f956bb7", 
+        "MD5OfMessageAttributes": "cd44329f02ab950a07225de4475134e7", 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "086a8b6f-52b5-5a36-877b-dab86cc3722b", 
+            "HTTPHeaders": {
+                "x-amzn-requestid": "086a8b6f-52b5-5a36-877b-dab86cc3722b", 
+                "content-length": "459", 
+                "server": "Server", 
+                "connection": "keep-alive", 
+                "date": "Wed, 05 Jul 2017 19:21:26 GMT", 
+                "content-type": "text/xml"
+            }
+        }, 
+        "MessageId": "0e8d46b1-e569-4e06-9033-3809eb38d48b"
+    }
+}
\ No newline at end of file
diff --git a/tests/test_notify.py b/tests/test_notify.py
--- a/tests/test_notify.py
+++ b/tests/test_notify.py
@@ -13,11 +13,61 @@
 # limitations under the License.
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-from .common import BaseTest
+from .common import BaseTest, functional
+
+import base64
+import json
+import tempfile
+import zlib
 
 
 class NotifyTest(BaseTest):
 
+    @functional
+    def test_notify_address_from(self):
+        session_factory = self.replay_flight_data(
+            'test_notify_address_from')
+        client = session_factory().client('sqs')
+        queue_url = client.create_queue(
+            QueueName='c7n-notify-test')['QueueUrl']
+        self.addCleanup(client.delete_queue, QueueUrl=queue_url)
+        temp_file = tempfile.NamedTemporaryFile()
+        json.dump({'emails': ['me@example.com']}, temp_file)
+        temp_file.flush()
+        self.addCleanup(temp_file.close)
+
+        policy = self.load_policy({
+            'name': 'notify-address',
+            'resource': 'sqs',
+            'filters': [
+                {'QueueUrl': queue_url}],
+            'actions': [{
+                'type': 'notify',
+                'to_from': {
+                    'url': 'file://%s' % temp_file.name,
+                    'format': 'json',
+                    'expr': 'emails'},
+                'cc_from': {
+                    'url': 'file://%s' % temp_file.name,
+                    'format': 'json',
+                    'expr': 'emails'},
+                'transport': {
+                    'type': 'sqs',
+                    'queue': queue_url}}]
+            }, session_factory=session_factory)
+        resources = policy.run()
+        self.assertEqual(len(resources), 1)
+        messages = client.receive_message(
+            QueueUrl=queue_url,
+            AttributeNames=['All']).get('Messages', [])
+        self.assertEqual(len(messages), 1)
+
+        body = json.loads(zlib.decompress(base64.b64decode(messages[0]['Body'])))
+        self.assertEqual(
+            set(body.keys()),
+            set(('account_id', 'action', 'event', 'policy', 'region', 'account',
+                'resources')))
+        
     def test_sns_notify(self):
         session_factory = self.replay_flight_data(
             'test_sns_notify_action')