22from __future__ import division
33from __future__ import absolute_import
44import logging
5+ import json
6+ import sys
57
68from .base import BaseAction
79from .. import exceptions
810
911logger = logging .getLogger (__name__ )
1012
1113
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+ line = '{}.{}={}\n ' .format (self .current_stack , key , value )
71+ sys .stdout .write (line )
72+
73+ def finish (self ):
74+ sys .stdout .flush ()
75+
76+
77+ class LogExporter (Exporter ):
78+ def start (self ):
79+ logger .info ('Outputs for stacks: %s' , self .context .get_fqn ())
80+
81+ def start_stack (self , stack ):
82+ logger .info ('%s:' , stack .fqn )
83+
84+ def write_output (self , key , value ):
85+ logger .info ('\t {}: {}' .format (key , value ))
86+
87+
88+ EXPORTER_CLASSES = {
89+ 'json' : JsonExporter ,
90+ 'log' : LogExporter ,
91+ 'plain' : PlainExporter
92+ }
93+
94+ OUTPUT_FORMATS = list (EXPORTER_CLASSES .keys ())
95+
96+
1297class Action (BaseAction ):
1398 """Get information on CloudFormation stacks.
1499
15100 Displays the outputs for the set of CloudFormation stacks.
16101
17102 """
18103
19- def run (self , * args , ** kwargs ):
20- logger .info ('Outputs for stacks: %s' , self .context .get_fqn ())
104+ @classmethod
105+ def build_exporter (cls , name ):
106+ try :
107+ exporter_cls = EXPORTER_CLASSES [name ]
108+ except KeyError :
109+ logger .error ('Unknown output format "{}"' .format (name ))
110+ raise
111+
112+ try :
113+ return exporter_cls ()
114+ except Exception :
115+ logger .exception ('Failed to create exporter instance' )
116+ raise
117+
118+ def run (self , output_format = 'log' , * args , ** kwargs ):
21119 if not self .context .get_stacks ():
22120 logger .warn ('WARNING: No stacks detected (error in config?)' )
121+ return
122+
123+ exporter = self .build_exporter (output_format )
124+ exporter .start (self .context )
125+
23126 for stack in self .context .get_stacks ():
24127 provider = self .build_provider (stack )
25128
@@ -29,11 +132,13 @@ def run(self, *args, **kwargs):
29132 logger .info ('Stack "%s" does not exist.' % (stack .fqn ,))
30133 continue
31134
32- logger .info ('%s:' , stack .fqn )
135+ exporter .start_stack (stack )
136+
33137 if 'Outputs' in provider_stack :
34138 for output in provider_stack ['Outputs' ]:
35- logger .info (
36- '\t %s: %s' ,
37- output ['OutputKey' ],
38- output ['OutputValue' ]
39- )
139+ exporter .write_output (output ['OutputKey' ],
140+ output ['OutputValue' ])
141+
142+ exporter .end_stack (stack )
143+
144+ exporter .finish ()
0 commit comments