Repository: cloud-custodian/cloud-custodian

Issue:
add back c7n_mailer.replay
the c7n_mailer refactor in #1201 removed c7n_mailer.replay even though the [code review](https://github.com/capitalone/cloud-custodian/pull/1201#discussion_r118406536) indicated not to; I think this just fell through the cracks. Right now, this results in a broken entrypoint:

```
(custodian-config)jantman@phoenix:pts/9:~/manheim/git/CoxAuto-ProductionEngineering/custodian-config/src/c7n/tools/c7n_mailer ((0.8.25.1) %)$ c7n-mailer-replay -h
Traceback (most recent call last):
  File "/home/jantman/manheim/git/CoxAuto-ProductionEngineering/custodian-config/bin/c7n-mailer-replay", line 11, in <module>
    load_entry_point('c7n-mailer', 'console_scripts', 'c7n-mailer-replay')()
  File "/home/jantman/manheim/git/CoxAuto-ProductionEngineering/custodian-config/lib/python2.7/site-packages/pkg_resources/__init__.py", line 561, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/home/jantman/manheim/git/CoxAuto-ProductionEngineering/custodian-config/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2649, in load_entry_point
    return ep.load()
  File "/home/jantman/manheim/git/CoxAuto-ProductionEngineering/custodian-config/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2303, in load
    return self.resolve()
  File "/home/jantman/manheim/git/CoxAuto-ProductionEngineering/custodian-config/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2309, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
ImportError: No module named replay
```

This adds back the module with the same content as before it was removed in 165834d36149629de141158e3d54695f2faaa00d and then removes its duplicated ``CONFIG_SCHEMA``, using the schema directly from c7n_mailer.cli.


Discussion:
@kapilt I'm really really sorry, but this is actually broken. I forgot to take into account the refactor of all the other code. It won't break anything else, but it's also not actually _fixed_ yet. Since I forgot to close this, I'll open a follow-up shortly with actual fixes.

Resolving patch:
diff --git a/tools/c7n_mailer/c7n_mailer/replay.py b/tools/c7n_mailer/c7n_mailer/replay.py
--- a/tools/c7n_mailer/c7n_mailer/replay.py
+++ b/tools/c7n_mailer/c7n_mailer/replay.py
@@ -20,17 +20,16 @@
 import jsonschema
 import yaml
 
-from c7n import utils
 from c7n_mailer.utils import setup_defaults
 from c7n_mailer.cli import CONFIG_SCHEMA
-from .sqs_message_processor import SqsMessageProcessor
+from .email_delivery import EmailDelivery
 
 logger = logging.getLogger(__name__)
 
 
 class MailerTester(object):
 
-    def __init__(self, msg_file, config, msg_plain=False):
+    def __init__(self, msg_file, config, msg_plain=False, json_dump_file=None):
         if not os.path.exists(msg_file):
             raise RuntimeError("File does not exist: %s" % msg_file)
         logger.debug('Reading message from: %s', msg_file)
@@ -42,56 +41,34 @@ def __init__(self, msg_file, config, msg_plain=False):
         else:
             logger.debug('base64-decoding and zlib decompressing message')
             raw = zlib.decompress(base64.b64decode(raw))
+            if json_dump_file is not None:
+                with open(json_dump_file, 'w') as fh:
+                    fh.write(raw)
         self.data = json.loads(raw)
         logger.debug('Loaded message JSON')
         self.config = config
         self.session = boto3.Session()
 
     def run(self, dry_run=False, print_only=False):
-        msg = {
-            'Body': base64.b64encode(zlib.compress(utils.dumps(self.data))),
-            'MessageId': 'replayed-message'
-        }
-        self.show_to(msg)
+        emd = EmailDelivery(self.config, self.session, logger)
+        addrs_to_msgs = emd.get_to_addrs_email_messages_map(self.data)
+        logger.info('Would send email to: %s', addrs_to_msgs.keys())
         if print_only:
-            self.do_print()
+            mime = emd.get_mimetext_message(
+                self.data, self.data['resources'], ['foo@example.com']
+            )
+            logger.info('Send mail with subject: "%s"', mime['Subject'])
+            print(mime.get_payload())
             return
         if dry_run:
-            self.do_dry_run(msg)
+            for to_addrs, mimetext_msg in addrs_to_msgs.items():
+                print('-> SEND MESSAGE TO: %s' % to_addrs)
+                print(mimetext_msg)
             return
-        smp = SqsMessageProcessor(self.config, self.session, None, logger)
-        smp.process_sqs_messsage(msg)
-
-    def do_dry_run(self, msg):
-        def sre(RawMessage):
-            logger.info("SEND RAW MESSAGE:")
-            print(RawMessage['Data'])
-
-        if self.config.get('smtp_server'):
-            del self.config['smtp_server']
-        smp = SqsMessageProcessor(self.config, self.session, None, logger)
-        smp.aws_ses.send_raw_email = sre
-        smp.process_sqs_messsage(msg)
-
-    def do_print(self):
-        def sce(_, email_to, subject, body):
-            logger.info('Send mail with subject "%s":', subject)
-            print(body)
-            raise SystemExit(0)
-
-        smp = SqsMessageProcessor(self.config, self.session, None, logger)
-        smp.send_c7n_email = sce
-        smp.send_message_to_targets(
-            ['foo@example.com'], self.data, self.data['resources']
-        )
-
-    def show_to(self, msg):
-        def smtt(targets, _, resources):
-            logger.info('Would send email for %s resources to: %s',
-                        len(resources), targets)
-        smp = SqsMessageProcessor(self.config, self.session, None, logger)
-        smp.send_message_to_targets = smtt
-        smp.process_sqs_messsage(msg)
+        # else actually send the message...
+        for to_addrs, mimetext_msg in addrs_to_msgs.items():
+            logger.info('Actually sending mail to: %s', to_addrs)
+            emd.send_c7n_email(self.data, list(to_addrs), mimetext_msg)
 
 
 def setup_parser():
@@ -108,6 +85,10 @@ def setup_parser():
                         help='Expect MESSAGE_FILE to be a plain string, '
                              'rather than the base64-encoded, gzipped SQS '
                              'message format')
+    parser.add_argument('-j', '--json-dump-file', dest='json_dump_file',
+                        type=str, action='store', default=None,
+                        help='If dump JSON of MESSAGE_FILE to this path; '
+                             'useful to base64-decode and gunzip a message')
     parser.add_argument('MESSAGE_FILE', type=str,
                         help='Path to SQS message dump/content file')
     return parser
@@ -133,7 +114,10 @@ def main():
     jsonschema.validate(config, CONFIG_SCHEMA)
     setup_defaults(config)
 
-    tester = MailerTester(options.MESSAGE_FILE, config, msg_plain=options.plain)
+    tester = MailerTester(
+        options.MESSAGE_FILE, config, msg_plain=options.plain,
+        json_dump_file=options.json_dump_file
+    )
     tester.run(options.dry_run, options.print_only)
 
 


Test patch: