|
1 | 1 | from __future__ import print_function
|
2 | 2 | from __future__ import division
|
3 | 3 | from __future__ import absolute_import
|
| 4 | +import json |
4 | 5 | import logging
|
| 6 | +import sys |
5 | 7 |
|
6 | 8 | from .base import BaseAction
|
7 | 9 | from .. import exceptions
|
8 | 10 |
|
9 | 11 | logger = logging.getLogger(__name__)
|
10 | 12 |
|
11 | 13 |
|
| 14 | +class Exporter(object): |
| 15 | + def __init__(self, context): |
| 16 | + self.context = context |
| 17 | + |
| 18 | + def start(self): |
| 19 | + pass |
| 20 | + |
| 21 | + def start_stack(self, stack): |
| 22 | + pass |
| 23 | + |
| 24 | + def end_stack(self, stack): |
| 25 | + pass |
| 26 | + |
| 27 | + def write_output(self, key, value): |
| 28 | + pass |
| 29 | + |
| 30 | + def finish(self): |
| 31 | + pass |
| 32 | + |
| 33 | + |
| 34 | +class JsonExporter(Exporter): |
| 35 | + def start(self): |
| 36 | + self.current_outputs = {} |
| 37 | + self.stacks = {} |
| 38 | + |
| 39 | + def start_stack(self, stack): |
| 40 | + self.current_outputs = {} |
| 41 | + |
| 42 | + def end_stack(self, stack): |
| 43 | + self.stacks[stack.name] = { |
| 44 | + "outputs": self.current_outputs, |
| 45 | + "fqn": stack.fqn |
| 46 | + } |
| 47 | + self.current_outputs = {} |
| 48 | + |
| 49 | + def write_output(self, key, value): |
| 50 | + self.current_outputs[key] = value |
| 51 | + |
| 52 | + def finish(self): |
| 53 | + json_data = json.dumps({'stacks': self.stacks}, indent=4) |
| 54 | + sys.stdout.write(json_data) |
| 55 | + sys.stdout.write('\n') |
| 56 | + sys.stdout.flush() |
| 57 | + |
| 58 | + |
| 59 | +class PlainExporter(Exporter): |
| 60 | + def start(self): |
| 61 | + self.current_stack = None |
| 62 | + |
| 63 | + def start_stack(self, stack): |
| 64 | + self.current_stack = stack.name |
| 65 | + |
| 66 | + def end_stack(self, stack): |
| 67 | + self.current_stack = None |
| 68 | + |
| 69 | + def write_output(self, key, value): |
| 70 | + assert self.current_stack |
| 71 | + |
| 72 | + line = '{}.{}={}\n'.format(self.current_stack, key, value) |
| 73 | + sys.stdout.write(line) |
| 74 | + |
| 75 | + def finish(self): |
| 76 | + sys.stdout.flush() |
| 77 | + |
| 78 | + |
| 79 | +class LogExporter(Exporter): |
| 80 | + def start(self): |
| 81 | + logger.info('Outputs for stacks: %s', self.context.get_fqn()) |
| 82 | + |
| 83 | + def start_stack(self, stack): |
| 84 | + logger.info('%s:', stack.fqn) |
| 85 | + |
| 86 | + def write_output(self, key, value): |
| 87 | + logger.info('\t{}: {}'.format(key, value)) |
| 88 | + |
| 89 | + |
| 90 | +EXPORTER_CLASSES = { |
| 91 | + 'json': JsonExporter, |
| 92 | + 'log': LogExporter, |
| 93 | + 'plain': PlainExporter |
| 94 | +} |
| 95 | + |
| 96 | +OUTPUT_FORMATS = list(EXPORTER_CLASSES.keys()) |
| 97 | + |
| 98 | + |
12 | 99 | class Action(BaseAction):
|
13 | 100 | """Get information on CloudFormation stacks.
|
14 | 101 |
|
15 | 102 | Displays the outputs for the set of CloudFormation stacks.
|
16 | 103 |
|
17 | 104 | """
|
18 | 105 |
|
19 |
| - def run(self, *args, **kwargs): |
20 |
| - logger.info('Outputs for stacks: %s', self.context.get_fqn()) |
| 106 | + def build_exporter(self, name): |
| 107 | + try: |
| 108 | + exporter_cls = EXPORTER_CLASSES[name] |
| 109 | + except KeyError: |
| 110 | + logger.error('Unknown output format "{}"'.format(name)) |
| 111 | + return None |
| 112 | + |
| 113 | + return exporter_cls(self.context) |
| 114 | + |
| 115 | + def run(self, output_format='log', *args, **kwargs): |
21 | 116 | if not self.context.get_stacks():
|
22 | 117 | logger.warn('WARNING: No stacks detected (error in config?)')
|
23 |
| - for stack in self.context.get_stacks(): |
| 118 | + return |
| 119 | + |
| 120 | + try: |
| 121 | + exporter = self.build_exporter(output_format) |
| 122 | + except Exception: |
| 123 | + logger.exception('Failed to create exporter instance') |
| 124 | + return |
| 125 | + |
| 126 | + exporter.start() |
| 127 | + |
| 128 | + stacks = sorted(self.context.get_stacks(), key=lambda s: s.fqn) |
| 129 | + for stack in stacks: |
24 | 130 | provider = self.build_provider(stack)
|
25 | 131 |
|
26 | 132 | try:
|
27 |
| - provider_stack = provider.get_stack(stack.fqn) |
| 133 | + outputs = provider.get_outputs(stack.fqn) |
28 | 134 | except exceptions.StackDoesNotExist:
|
29 | 135 | logger.info('Stack "%s" does not exist.' % (stack.fqn,))
|
30 | 136 | continue
|
31 | 137 |
|
32 |
| - logger.info('%s:', stack.fqn) |
33 |
| - if 'Outputs' in provider_stack: |
34 |
| - for output in provider_stack['Outputs']: |
35 |
| - logger.info( |
36 |
| - '\t%s: %s', |
37 |
| - output['OutputKey'], |
38 |
| - output['OutputValue'] |
39 |
| - ) |
| 138 | + outputs = sorted( |
| 139 | + (output['OutputKey'], output['OutputValue']) |
| 140 | + for output in outputs) |
| 141 | + |
| 142 | + exporter.start_stack(stack) |
| 143 | + |
| 144 | + for key, value in outputs: |
| 145 | + exporter.write_output(key, value) |
| 146 | + |
| 147 | + exporter.end_stack(stack) |
| 148 | + |
| 149 | + exporter.finish() |
0 commit comments