sfn 1.1.6 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +5 -0
 - data/docs/usage.md +1 -0
 - data/lib/chef/knife/knife_plugin_seed.rb +8 -2
 - data/lib/sfn.rb +1 -0
 - data/lib/sfn/callback.rb +4 -4
 - data/lib/sfn/command.rb +3 -0
 - data/lib/sfn/command/conf.rb +39 -0
 - data/lib/sfn/command/update.rb +126 -1
 - data/lib/sfn/command_module/stack.rb +9 -5
 - data/lib/sfn/command_module/template.rb +12 -6
 - data/lib/sfn/config.rb +2 -0
 - data/lib/sfn/config/conf.rb +9 -0
 - data/lib/sfn/config/create.rb +4 -0
 - data/lib/sfn/config/update.rb +5 -0
 - data/lib/sfn/planner.rb +44 -0
 - data/lib/sfn/planner/aws.rb +410 -0
 - data/lib/sfn/version.rb +1 -1
 - metadata +6 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 698f214f1cdff652dc16b36120697090de470f87
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 7efbb32522675152516584455f8f317b9816e6f8
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 0f2de1bf189064aa4213a6211730d7a0d0760ff613ce5974db6e8957ee7a5301574fcaa15411be1235ca7c7f9f251bd34c9274288d809f1683f540ffa85c7a71
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: c268b90db20e18cb7534ef63b19883026d73e47e62d3cffcfae0d894cb7ad41d58032c715d172d0005f772212250803595c62b06eb9253b92d210ae75940b141
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/docs/usage.md
    CHANGED
    
    
| 
         @@ -63,6 +63,7 @@ unless(defined?(Chef::Knife::CloudformationCreate)) 
     | 
|
| 
       63 
63 
     | 
    
         
             
                        base[k]
         
     | 
| 
       64 
64 
     | 
    
         
             
                      end.compact.first || {}
         
     | 
| 
       65 
65 
     | 
    
         
             
                      cmd_config = cmd_config.to_smash
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
       66 
67 
     | 
    
         
             
                      reconfig = config.find_all do |k,v|
         
     | 
| 
       67 
68 
     | 
    
         
             
                        !v.nil?
         
     | 
| 
       68 
69 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -73,11 +74,16 @@ unless(defined?(Chef::Knife::CloudformationCreate)) 
     | 
|
| 
       73 
74 
     | 
    
         
             
                        end
         
     | 
| 
       74 
75 
     | 
    
         
             
                        [k,v]
         
     | 
| 
       75 
76 
     | 
    
         
             
                      end
         
     | 
| 
       76 
     | 
    
         
            -
                       
     | 
| 
       77 
     | 
    
         
            -
                      cmd_config = cmd_config.deep_merge( 
     | 
| 
      
 77 
     | 
    
         
            +
                      n_config = Smash[reconfig]
         
     | 
| 
      
 78 
     | 
    
         
            +
                      cmd_config = cmd_config.deep_merge(n_config)
         
     | 
| 
       78 
79 
     | 
    
         
             
                      self.class.sfn_class.new(cmd_config, name_args).execute!
         
     | 
| 
       79 
80 
     | 
    
         
             
                    end
         
     | 
| 
       80 
81 
     | 
    
         | 
| 
      
 82 
     | 
    
         
            +
                    # NOOP this merge as it breaks expected state
         
     | 
| 
      
 83 
     | 
    
         
            +
                    def merge_configs
         
     | 
| 
      
 84 
     | 
    
         
            +
                      config
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
       81 
87 
     | 
    
         
             
                  end
         
     | 
| 
       82 
88 
     | 
    
         
             
                  knife_klass.instance_variable_set(:@name, "Chef::Knife::#{command_class}")
         
     | 
| 
       83 
89 
     | 
    
         
             
                  knife_klass.instance_variable_set(
         
     | 
    
        data/lib/sfn.rb
    CHANGED
    
    
    
        data/lib/sfn/callback.rb
    CHANGED
    
    | 
         @@ -17,10 +17,10 @@ module Sfn 
     | 
|
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                # Create a new callback instance
         
     | 
| 
       19 
19 
     | 
    
         
             
                #
         
     | 
| 
       20 
     | 
    
         
            -
                # @param [Bogo::Ui]
         
     | 
| 
       21 
     | 
    
         
            -
                # @param [Smash] configuration hash
         
     | 
| 
       22 
     | 
    
         
            -
                # @param [Array<String>] arguments from the CLI
         
     | 
| 
       23 
     | 
    
         
            -
                # @param [Provider] API connection
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param ui [Bogo::Ui]
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @param config [Smash] configuration hash
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @param arguments [Array<String>] arguments from the CLI
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @param api [Provider] API connection
         
     | 
| 
       24 
24 
     | 
    
         
             
                #
         
     | 
| 
       25 
25 
     | 
    
         
             
                # @return [self]
         
     | 
| 
       26 
26 
     | 
    
         
             
                def initialize(ui, config, arguments, api)
         
     | 
    
        data/lib/sfn/command.rb
    CHANGED
    
    | 
         @@ -4,6 +4,9 @@ require 'bogo-cli' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            module Sfn
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Command < Bogo::Cli::Command
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
                include CommandModule::Callbacks
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                autoload :Conf, 'sfn/command/conf'
         
     | 
| 
       7 
10 
     | 
    
         
             
                autoload :Create, 'sfn/command/create'
         
     | 
| 
       8 
11 
     | 
    
         
             
                autoload :Describe, 'sfn/command/describe'
         
     | 
| 
       9 
12 
     | 
    
         
             
                autoload :Destroy, 'sfn/command/destroy'
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'sfn'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Sfn
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Command
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Config command
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Conf < Command
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  # Run the list command
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def execute!
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ui.info ui.color("Current configuration state:")
         
     | 
| 
      
 11 
     | 
    
         
            +
                    Config::Conf.attributes.sort_by(&:first).each do |k, val|
         
     | 
| 
      
 12 
     | 
    
         
            +
                      if(config.has_key?(k))
         
     | 
| 
      
 13 
     | 
    
         
            +
                        ui.print "  #{ui.color(k, :bold, :green)}: "
         
     | 
| 
      
 14 
     | 
    
         
            +
                        format_value(config[k], '  ')
         
     | 
| 
      
 15 
     | 
    
         
            +
                      end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def format_value(value, indent='')
         
     | 
| 
      
 20 
     | 
    
         
            +
                    if(value.is_a?(Hash))
         
     | 
| 
      
 21 
     | 
    
         
            +
                      ui.puts
         
     | 
| 
      
 22 
     | 
    
         
            +
                      value.sort_by(&:first).each do |k,v|
         
     | 
| 
      
 23 
     | 
    
         
            +
                        ui.print "#{indent}  #{ui.color(k, :bold)}: "
         
     | 
| 
      
 24 
     | 
    
         
            +
                        format_value(v, indent + '  ')
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    elsif(value.is_a?(Array))
         
     | 
| 
      
 27 
     | 
    
         
            +
                      ui.puts
         
     | 
| 
      
 28 
     | 
    
         
            +
                      value.map(&:to_s).sort.each do |v|
         
     | 
| 
      
 29 
     | 
    
         
            +
                        ui.print "#{indent}  "
         
     | 
| 
      
 30 
     | 
    
         
            +
                        format_value(v, indent + '  ')
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    else
         
     | 
| 
      
 33 
     | 
    
         
            +
                      ui.puts value.to_s
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/sfn/command/update.rb
    CHANGED
    
    | 
         @@ -76,14 +76,42 @@ module Sfn 
     | 
|
| 
       76 
76 
     | 
    
         
             
                          ui.puts _format_json(translate_template(file))
         
     | 
| 
       77 
77 
     | 
    
         
             
                          return
         
     | 
| 
       78 
78 
     | 
    
         
             
                        end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                        original_template = stack.template
         
     | 
| 
      
 81 
     | 
    
         
            +
                        original_parameters = stack.parameters
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       79 
83 
     | 
    
         
             
                        stack.template = translate_template(file)
         
     | 
| 
       80 
84 
     | 
    
         
             
                        apply_stacks!(stack)
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
       81 
86 
     | 
    
         
             
                        populate_parameters!(file, :current_parameters => stack.parameters)
         
     | 
| 
      
 87 
     | 
    
         
            +
                        update_template = stack.template
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                        if(config[:plan])
         
     | 
| 
      
 90 
     | 
    
         
            +
                          stack.template = original_template
         
     | 
| 
      
 91 
     | 
    
         
            +
                          stack.parameters = original_parameters
         
     | 
| 
      
 92 
     | 
    
         
            +
                          plan = build_planner(stack)
         
     | 
| 
      
 93 
     | 
    
         
            +
                          if(plan)
         
     | 
| 
      
 94 
     | 
    
         
            +
                            result = plan.generate_plan(file, config_root_parameters)
         
     | 
| 
      
 95 
     | 
    
         
            +
                            display_plan_information(result)
         
     | 
| 
      
 96 
     | 
    
         
            +
                          end
         
     | 
| 
      
 97 
     | 
    
         
            +
                        end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
       82 
99 
     | 
    
         
             
                        stack.parameters = config_root_parameters
         
     | 
| 
       83 
     | 
    
         
            -
                        stack.template = Sfn::Utils::StackParameterScrubber.scrub!( 
     | 
| 
      
 100 
     | 
    
         
            +
                        stack.template = Sfn::Utils::StackParameterScrubber.scrub!(update_template)
         
     | 
| 
       84 
101 
     | 
    
         
             
                      else
         
     | 
| 
       85 
102 
     | 
    
         
             
                        apply_stacks!(stack)
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                        original_parameters = stack.parameters
         
     | 
| 
       86 
105 
     | 
    
         
             
                        populate_parameters!(stack.template, :current_parameters => stack.parameters)
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                        if(config[:plan])
         
     | 
| 
      
 108 
     | 
    
         
            +
                          stack.parameters = original_parameters
         
     | 
| 
      
 109 
     | 
    
         
            +
                          plan = Planner::Aws.new(ui, config, arguments, stack)
         
     | 
| 
      
 110 
     | 
    
         
            +
                          if(plan)
         
     | 
| 
      
 111 
     | 
    
         
            +
                            result = plan.generate_plan(stack.template, config_root_parameters)
         
     | 
| 
      
 112 
     | 
    
         
            +
                            display_plan_information(result)
         
     | 
| 
      
 113 
     | 
    
         
            +
                          end
         
     | 
| 
      
 114 
     | 
    
         
            +
                        end
         
     | 
| 
       87 
115 
     | 
    
         
             
                        stack.parameters = config_root_parameters
         
     | 
| 
       88 
116 
     | 
    
         
             
                      end
         
     | 
| 
       89 
117 
     | 
    
         | 
| 
         @@ -115,6 +143,103 @@ module Sfn 
     | 
|
| 
       115 
143 
     | 
    
         
             
                    end
         
     | 
| 
       116 
144 
     | 
    
         
             
                  end
         
     | 
| 
       117 
145 
     | 
    
         | 
| 
      
 146 
     | 
    
         
            +
                  def build_planner(stack)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    klass_name = stack.api.class.to_s.split('::').last
         
     | 
| 
      
 148 
     | 
    
         
            +
                    klass = Planner.const_get(klass_name)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    if(klass)
         
     | 
| 
      
 150 
     | 
    
         
            +
                      klass.new(ui, config, arguments, stack)
         
     | 
| 
      
 151 
     | 
    
         
            +
                    else
         
     | 
| 
      
 152 
     | 
    
         
            +
                      warn "Failed to build planner for current provider. No provider implemented. (`#{klass_name}`)"
         
     | 
| 
      
 153 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                  def display_plan_information(result)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    ui.info ui.color('Pre-update resource planning report:', :bold)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    unless(print_plan_result(result))
         
     | 
| 
      
 160 
     | 
    
         
            +
                      ui.info 'No resources life cycle changes detected in this update!'
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
                    ui.confirm 'Apply this stack update?'
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                  def print_plan_result(info, names=[])
         
     | 
| 
      
 167 
     | 
    
         
            +
                    said_things = false
         
     | 
| 
      
 168 
     | 
    
         
            +
                    unless(info[:stacks].empty?)
         
     | 
| 
      
 169 
     | 
    
         
            +
                      info[:stacks].each do |s_name, s_info|
         
     | 
| 
      
 170 
     | 
    
         
            +
                        said_things = print_plan_result(s_info, [*names, s_name].compact)
         
     | 
| 
      
 171 
     | 
    
         
            +
                      end
         
     | 
| 
      
 172 
     | 
    
         
            +
                    end
         
     | 
| 
      
 173 
     | 
    
         
            +
                    unless(names.flatten.compact.empty?)
         
     | 
| 
      
 174 
     | 
    
         
            +
                      ui.puts
         
     | 
| 
      
 175 
     | 
    
         
            +
                      ui.puts "  #{ui.color('Update plan for:', :bold)} #{ui.color(names.join(' > '), :blue)}"
         
     | 
| 
      
 176 
     | 
    
         
            +
                      unless(info[:unknown].empty?)
         
     | 
| 
      
 177 
     | 
    
         
            +
                        ui.puts "    #{ui.color('!!! Unknown update effect:', :red, :bold)}"
         
     | 
| 
      
 178 
     | 
    
         
            +
                        print_plan_items(info, :unknown, :red)
         
     | 
| 
      
 179 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 180 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 181 
     | 
    
         
            +
                      end
         
     | 
| 
      
 182 
     | 
    
         
            +
                      unless(info[:unavailable].empty?)
         
     | 
| 
      
 183 
     | 
    
         
            +
                        ui.puts "    #{ui.color('Update request not allowed:', :red, :bold)}"
         
     | 
| 
      
 184 
     | 
    
         
            +
                        print_plan_items(info, :unavailable, :red)
         
     | 
| 
      
 185 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 186 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 187 
     | 
    
         
            +
                      end
         
     | 
| 
      
 188 
     | 
    
         
            +
                      unless(info[:replace].empty?)
         
     | 
| 
      
 189 
     | 
    
         
            +
                        ui.puts "    #{ui.color('Resources to be replaced:', :red, :bold)}"
         
     | 
| 
      
 190 
     | 
    
         
            +
                        print_plan_items(info, :replace, :red)
         
     | 
| 
      
 191 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 192 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 193 
     | 
    
         
            +
                      end
         
     | 
| 
      
 194 
     | 
    
         
            +
                      unless(info[:interrupt].empty?)
         
     | 
| 
      
 195 
     | 
    
         
            +
                        ui.puts "    #{ui.color('Resources to be interrupted:', :yellow, :bold)}"
         
     | 
| 
      
 196 
     | 
    
         
            +
                        print_plan_items(info, :interrupt, :yellow)
         
     | 
| 
      
 197 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 198 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 199 
     | 
    
         
            +
                      end
         
     | 
| 
      
 200 
     | 
    
         
            +
                      unless(info[:removed].empty?)
         
     | 
| 
      
 201 
     | 
    
         
            +
                        ui.puts "    #{ui.color('Resources to be removed:', :red, :bold)}"
         
     | 
| 
      
 202 
     | 
    
         
            +
                        print_plan_items(info, :removed, :red)
         
     | 
| 
      
 203 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 204 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 205 
     | 
    
         
            +
                      end
         
     | 
| 
      
 206 
     | 
    
         
            +
                      unless(info[:added].empty?)
         
     | 
| 
      
 207 
     | 
    
         
            +
                        ui.puts "    #{ui.color('Resources to be added:', :green, :bold)}"
         
     | 
| 
      
 208 
     | 
    
         
            +
                        print_plan_items(info, :added, :green)
         
     | 
| 
      
 209 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 210 
     | 
    
         
            +
                        said_things = true
         
     | 
| 
      
 211 
     | 
    
         
            +
                      end
         
     | 
| 
      
 212 
     | 
    
         
            +
                      unless(said_things)
         
     | 
| 
      
 213 
     | 
    
         
            +
                        ui.puts "    #{ui.color('No resource lifecycle changes detected!', :green)}"
         
     | 
| 
      
 214 
     | 
    
         
            +
                        ui.puts
         
     | 
| 
      
 215 
     | 
    
         
            +
                      end
         
     | 
| 
      
 216 
     | 
    
         
            +
                    end
         
     | 
| 
      
 217 
     | 
    
         
            +
                    said_things
         
     | 
| 
      
 218 
     | 
    
         
            +
                  end
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                  # Print planning items
         
     | 
| 
      
 221 
     | 
    
         
            +
                  #
         
     | 
| 
      
 222 
     | 
    
         
            +
                  # @param info [Hash] plan
         
     | 
| 
      
 223 
     | 
    
         
            +
                  # @param key [Symbol] key of items
         
     | 
| 
      
 224 
     | 
    
         
            +
                  # @param color [Symbol] color to flag
         
     | 
| 
      
 225 
     | 
    
         
            +
                  def print_plan_items(info, key, color)
         
     | 
| 
      
 226 
     | 
    
         
            +
                    max_name = info[key].keys.map(&:size).max
         
     | 
| 
      
 227 
     | 
    
         
            +
                    max_type = info[key].values.map{|i|i[:type]}.map(&:size).max
         
     | 
| 
      
 228 
     | 
    
         
            +
                    info[key].each do |name, val|
         
     | 
| 
      
 229 
     | 
    
         
            +
                      ui.print ' ' * 6
         
     | 
| 
      
 230 
     | 
    
         
            +
                      ui.print ui.color("[#{val[:type]}]", color)
         
     | 
| 
      
 231 
     | 
    
         
            +
                      ui.print ' ' * (max_type - val[:type].size)
         
     | 
| 
      
 232 
     | 
    
         
            +
                      ui.print ' ' * 4
         
     | 
| 
      
 233 
     | 
    
         
            +
                      ui.print ui.color(name, :bold)
         
     | 
| 
      
 234 
     | 
    
         
            +
                      unless(val[:properties].nil? || val[:properties].empty?)
         
     | 
| 
      
 235 
     | 
    
         
            +
                        ui.print ' ' * (max_name - name.size)
         
     | 
| 
      
 236 
     | 
    
         
            +
                        ui.print ' ' * 4
         
     | 
| 
      
 237 
     | 
    
         
            +
                        ui.print "Reason: Updated properties: `#{val[:properties].join('`, `')}`"
         
     | 
| 
      
 238 
     | 
    
         
            +
                      end
         
     | 
| 
      
 239 
     | 
    
         
            +
                      ui.puts
         
     | 
| 
      
 240 
     | 
    
         
            +
                    end
         
     | 
| 
      
 241 
     | 
    
         
            +
                  end
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
       118 
243 
     | 
    
         
             
                end
         
     | 
| 
       119 
244 
     | 
    
         
             
              end
         
     | 
| 
       120 
245 
     | 
    
         
             
            end
         
     | 
| 
         @@ -123,11 +123,6 @@ module Sfn 
     | 
|
| 
       123 
123 
     | 
    
         
             
                        stack_parameters = sparkle.fetch('Parameters', Smash.new)
         
     | 
| 
       124 
124 
     | 
    
         
             
                      end
         
     | 
| 
       125 
125 
     | 
    
         
             
                      unless(stack_parameters.empty?)
         
     | 
| 
       126 
     | 
    
         
            -
                        if(sparkle.is_a?(SparkleFormation))
         
     | 
| 
       127 
     | 
    
         
            -
                          ui.info "#{ui.color('Stack runtime parameters:', :bold)} - template: #{ui.color(sparkle.root_path.map(&:name).map(&:to_s).join(' > '), :green, :bold)}"
         
     | 
| 
       128 
     | 
    
         
            -
                        else
         
     | 
| 
       129 
     | 
    
         
            -
                          ui.info ui.color('Stack runtime parameters:', :bold)
         
     | 
| 
       130 
     | 
    
         
            -
                        end
         
     | 
| 
       131 
126 
     | 
    
         
             
                        if(config.get(:parameter).is_a?(Array))
         
     | 
| 
       132 
127 
     | 
    
         
             
                          config[:parameter] = Smash[
         
     | 
| 
       133 
128 
     | 
    
         
             
                            *config.get(:parameter).map(&:to_a).flatten
         
     | 
| 
         @@ -140,6 +135,7 @@ module Sfn 
     | 
|
| 
       140 
135 
     | 
    
         
             
                        else
         
     | 
| 
       141 
136 
     | 
    
         
             
                          config.set(:parameters, config.fetch(:parameter, Smash.new))
         
     | 
| 
       142 
137 
     | 
    
         
             
                        end
         
     | 
| 
      
 138 
     | 
    
         
            +
                        param_banner = false
         
     | 
| 
       143 
139 
     | 
    
         
             
                        stack_parameters.each do |k,v|
         
     | 
| 
       144 
140 
     | 
    
         
             
                          ns_k = (parameter_prefix + [k]).compact.join('__')
         
     | 
| 
       145 
141 
     | 
    
         
             
                          next if config[:parameters][ns_k]
         
     | 
| 
         @@ -167,6 +163,14 @@ module Sfn 
     | 
|
| 
       167 
163 
     | 
    
         
             
                            end
         
     | 
| 
       168 
164 
     | 
    
         
             
                          end
         
     | 
| 
       169 
165 
     | 
    
         
             
                          attempt = 0
         
     | 
| 
      
 166 
     | 
    
         
            +
                          if(!valid && !param_banner)
         
     | 
| 
      
 167 
     | 
    
         
            +
                            if(sparkle.is_a?(SparkleFormation))
         
     | 
| 
      
 168 
     | 
    
         
            +
                              ui.info "#{ui.color('Stack runtime parameters:', :bold)} - template: #{ui.color(sparkle.root_path.map(&:name).map(&:to_s).join(' > '), :green, :bold)}"
         
     | 
| 
      
 169 
     | 
    
         
            +
                            else
         
     | 
| 
      
 170 
     | 
    
         
            +
                              ui.info ui.color('Stack runtime parameters:', :bold)
         
     | 
| 
      
 171 
     | 
    
         
            +
                            end
         
     | 
| 
      
 172 
     | 
    
         
            +
                            param_banner = true
         
     | 
| 
      
 173 
     | 
    
         
            +
                          end
         
     | 
| 
       170 
174 
     | 
    
         
             
                          until(valid)
         
     | 
| 
       171 
175 
     | 
    
         
             
                            attempt += 1
         
     | 
| 
       172 
176 
     | 
    
         
             
                            default = config[:parameters].fetch(
         
     | 
| 
         @@ -139,11 +139,13 @@ module Sfn 
     | 
|
| 
       139 
139 
     | 
    
         
             
                            if(formation.compile_state)
         
     | 
| 
       140 
140 
     | 
    
         
             
                              current_state = current_state.merge(formation.compile_state)
         
     | 
| 
       141 
141 
     | 
    
         
             
                            end
         
     | 
| 
       142 
     | 
    
         
            -
                             
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                               
     | 
| 
      
 142 
     | 
    
         
            +
                            unless(formation.parameters.empty?)
         
     | 
| 
      
 143 
     | 
    
         
            +
                              ui.info "#{ui.color('Compile time parameters:', :bold)} - template: #{ui.color(pathed_name, :green, :bold)}" unless config[:print_only]
         
     | 
| 
      
 144 
     | 
    
         
            +
                              formation.parameters.each do |k,v|
         
     | 
| 
      
 145 
     | 
    
         
            +
                                current_state[k] = request_compile_parameter(k, v, current_state[k], !!formation.parent)
         
     | 
| 
      
 146 
     | 
    
         
            +
                              end
         
     | 
| 
      
 147 
     | 
    
         
            +
                              formation.compile_state = current_state
         
     | 
| 
       145 
148 
     | 
    
         
             
                            end
         
     | 
| 
       146 
     | 
    
         
            -
                            formation.compile_state = current_state
         
     | 
| 
       147 
149 
     | 
    
         
             
                          end
         
     | 
| 
       148 
150 
     | 
    
         
             
                          sparkle_packs.each do |pack|
         
     | 
| 
       149 
151 
     | 
    
         
             
                            sf.sparkle.add_sparkle(pack)
         
     | 
| 
         @@ -197,7 +199,9 @@ module Sfn 
     | 
|
| 
       197 
199 
     | 
    
         
             
                        if(config[:print_only])
         
     | 
| 
       198 
200 
     | 
    
         
             
                          template_url = "http://example.com/bucket/#{name_args.first}_#{stack_name}.json"
         
     | 
| 
       199 
201 
     | 
    
         
             
                        else
         
     | 
| 
       200 
     | 
    
         
            -
                           
     | 
| 
      
 202 
     | 
    
         
            +
                          unless(config[:plan])
         
     | 
| 
      
 203 
     | 
    
         
            +
                            resource.properties.delete!(:stack)
         
     | 
| 
      
 204 
     | 
    
         
            +
                          end
         
     | 
| 
       201 
205 
     | 
    
         
             
                          unless(bucket)
         
     | 
| 
       202 
206 
     | 
    
         
             
                            raise "Failed to locate configured bucket for stack template storage (#{bucket})!"
         
     | 
| 
       203 
207 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -241,7 +245,9 @@ module Sfn 
     | 
|
| 
       241 
245 
     | 
    
         
             
                              :current_parameters => current_parameters
         
     | 
| 
       242 
246 
     | 
    
         
             
                            )
         
     | 
| 
       243 
247 
     | 
    
         
             
                          )
         
     | 
| 
       244 
     | 
    
         
            -
                           
     | 
| 
      
 248 
     | 
    
         
            +
                          unless(config[:plan])
         
     | 
| 
      
 249 
     | 
    
         
            +
                            resource.properties.delete!(:stack)
         
     | 
| 
      
 250 
     | 
    
         
            +
                          end
         
     | 
| 
       245 
251 
     | 
    
         
             
                          bucket = provider.connection.api_for(:storage).buckets.get(
         
     | 
| 
       246 
252 
     | 
    
         
             
                            config[:nesting_bucket]
         
     | 
| 
       247 
253 
     | 
    
         
             
                          )
         
     | 
    
        data/lib/sfn/config.rb
    CHANGED
    
    | 
         @@ -9,6 +9,7 @@ module Sfn 
     | 
|
| 
       9 
9 
     | 
    
         
             
                # Only values allowed designating bool type
         
     | 
| 
       10 
10 
     | 
    
         
             
                BOOLEAN_VALUES = [TrueClass, FalseClass]
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
      
 12 
     | 
    
         
            +
                autoload :Conf, 'sfn/config/conf'
         
     | 
| 
       12 
13 
     | 
    
         
             
                autoload :Create, 'sfn/config/create'
         
     | 
| 
       13 
14 
     | 
    
         
             
                autoload :Describe, 'sfn/config/describe'
         
     | 
| 
       14 
15 
     | 
    
         
             
                autoload :Destroy, 'sfn/config/destroy'
         
     | 
| 
         @@ -67,6 +68,7 @@ module Sfn 
     | 
|
| 
       67 
68 
     | 
    
         
             
                  :description => 'Automatically accept any requests for confirmation'
         
     | 
| 
       68 
69 
     | 
    
         
             
                )
         
     | 
| 
       69 
70 
     | 
    
         | 
| 
      
 71 
     | 
    
         
            +
                attribute :conf, Conf, :coerce => proc{|v| Conf.new(v)}
         
     | 
| 
       70 
72 
     | 
    
         
             
                attribute :create, Create, :coerce => proc{|v| Create.new(v)}
         
     | 
| 
       71 
73 
     | 
    
         
             
                attribute :update, Update, :coerce => proc{|v| Update.new(v)}
         
     | 
| 
       72 
74 
     | 
    
         
             
                attribute :destroy, Destroy, :coerce => proc{|v| Destroy.new(v)}
         
     | 
    
        data/lib/sfn/config/create.rb
    CHANGED
    
    
    
        data/lib/sfn/config/update.rb
    CHANGED
    
    
    
        data/lib/sfn/planner.rb
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'sfn'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Sfn
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Interface for generating plan report
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Planner
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                autoload :Aws, 'sfn/planner/aws'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # @return [Bogo::Ui]
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :ui
         
     | 
| 
      
 11 
     | 
    
         
            +
                # @return [Smash]
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_reader :config
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @return [Array<String>] CLI arguments
         
     | 
| 
      
 14 
     | 
    
         
            +
                attr_reader :arguments
         
     | 
| 
      
 15 
     | 
    
         
            +
                # @return [Miasma::Models::Orchestration::Stack] existing remote stack
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_reader :origin_stack
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                # Create a new planner instance
         
     | 
| 
      
 19 
     | 
    
         
            +
                #
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param ui [Bogo::Ui]
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @param config [Smash]
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @param arguments [Array<String>]
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @param stack [Miasma::Models::Orchestration::Stack]
         
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                # @return [self]
         
     | 
| 
      
 26 
     | 
    
         
            +
                def initialize(ui, config, arguments, stack)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @ui = ui
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @config = config
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @arguments = arguments
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @origin_stack = stack
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Generate update report
         
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                # @param template [Hash] updated template
         
     | 
| 
      
 36 
     | 
    
         
            +
                # @param parameters [Hash] runtime parameters for update
         
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                # @return [Hash] report
         
     | 
| 
      
 39 
     | 
    
         
            +
                def generate_plan(template, parameters)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  raise NotImplementedError
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,410 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'pp'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'sfn'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'sparkle_formation/aws'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'hashdiff'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Sfn
         
     | 
| 
      
 9 
     | 
    
         
            +
              class Planner
         
     | 
| 
      
 10 
     | 
    
         
            +
                # AWS specific planner
         
     | 
| 
      
 11 
     | 
    
         
            +
                class Aws < Planner
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # Customized translator to dereference template
         
     | 
| 
      
 14 
     | 
    
         
            +
                  class Translator < SparkleFormation::Translation
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    # @return [Array<String>] flagged items for value replacement
         
     | 
| 
      
 17 
     | 
    
         
            +
                    attr_reader :flagged
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    # Override to init flagged array
         
     | 
| 
      
 20 
     | 
    
         
            +
                    def initialize(*_)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      super
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @flagged = []
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    # Flag a reference as modified
         
     | 
| 
      
 26 
     | 
    
         
            +
                    #
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # @param ref_name [String]
         
     | 
| 
      
 28 
     | 
    
         
            +
                    # @return [Array<String>]
         
     | 
| 
      
 29 
     | 
    
         
            +
                    def flag_ref(ref_name)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      @flagged << ref_name.to_s
         
     | 
| 
      
 31 
     | 
    
         
            +
                      @flagged.uniq!
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    # Check if resource name is flagged
         
     | 
| 
      
 35 
     | 
    
         
            +
                    #
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # @param name [String]
         
     | 
| 
      
 37 
     | 
    
         
            +
                    # @return [TrueClass, FalseClass]
         
     | 
| 
      
 38 
     | 
    
         
            +
                    def flagged?(name)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      @flagged.include?(name.to_s)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    # Apply function if possible
         
     | 
| 
      
 43 
     | 
    
         
            +
                    #
         
     | 
| 
      
 44 
     | 
    
         
            +
                    # @param hash [Hash]
         
     | 
| 
      
 45 
     | 
    
         
            +
                    # @param funcs [Array] allowed functions
         
     | 
| 
      
 46 
     | 
    
         
            +
                    # @return [Hash]
         
     | 
| 
      
 47 
     | 
    
         
            +
                    # @note also allows 'Ref' within funcs to provide mapping
         
     | 
| 
      
 48 
     | 
    
         
            +
                    #   replacements using the REF_MAPPING constant
         
     | 
| 
      
 49 
     | 
    
         
            +
                    def apply_function(hash, funcs=[])
         
     | 
| 
      
 50 
     | 
    
         
            +
                      k,v = hash.first
         
     | 
| 
      
 51 
     | 
    
         
            +
                      if(hash.size == 1 && (k.start_with?('Fn') || k == 'Ref') && (funcs.empty? || funcs.include?(k)))
         
     | 
| 
      
 52 
     | 
    
         
            +
                        case k
         
     | 
| 
      
 53 
     | 
    
         
            +
                        when 'Fn::Join'
         
     | 
| 
      
 54 
     | 
    
         
            +
                          v.last.join(v.first)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        when 'Fn::FindInMap'
         
     | 
| 
      
 56 
     | 
    
         
            +
                          map_holder = mappings[v[0]]
         
     | 
| 
      
 57 
     | 
    
         
            +
                          if(map_holder)
         
     | 
| 
      
 58 
     | 
    
         
            +
                            map_item = map_holder[dereference(v[1])]
         
     | 
| 
      
 59 
     | 
    
         
            +
                            if(map_item)
         
     | 
| 
      
 60 
     | 
    
         
            +
                              map_item[v[2]]
         
     | 
| 
      
 61 
     | 
    
         
            +
                            else
         
     | 
| 
      
 62 
     | 
    
         
            +
                              raise "Failed to find mapping item! (#{v[0]} -> #{v[1]})"
         
     | 
| 
      
 63 
     | 
    
         
            +
                            end
         
     | 
| 
      
 64 
     | 
    
         
            +
                          else
         
     | 
| 
      
 65 
     | 
    
         
            +
                            raise "Failed to find mapping! (#{v[0]})"
         
     | 
| 
      
 66 
     | 
    
         
            +
                          end
         
     | 
| 
      
 67 
     | 
    
         
            +
                        when 'Fn::GetAtt'
         
     | 
| 
      
 68 
     | 
    
         
            +
                          func.include?('DEREF') ? dereference(hash) : hash
         
     | 
| 
      
 69 
     | 
    
         
            +
                        when 'Ref'
         
     | 
| 
      
 70 
     | 
    
         
            +
                          if(funcs.include?('DEREF'))
         
     | 
| 
      
 71 
     | 
    
         
            +
                            dereference(hash)
         
     | 
| 
      
 72 
     | 
    
         
            +
                          else
         
     | 
| 
      
 73 
     | 
    
         
            +
                            {'Ref' => self.class.const_get(:REF_MAPPING).fetch(v, v)}
         
     | 
| 
      
 74 
     | 
    
         
            +
                          end
         
     | 
| 
      
 75 
     | 
    
         
            +
                        else
         
     | 
| 
      
 76 
     | 
    
         
            +
                          hash
         
     | 
| 
      
 77 
     | 
    
         
            +
                        end
         
     | 
| 
      
 78 
     | 
    
         
            +
                      else
         
     | 
| 
      
 79 
     | 
    
         
            +
                        hash
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    # Override the parent dereference behavior to return junk
         
     | 
| 
      
 84 
     | 
    
         
            +
                    # value on flagged resource match
         
     | 
| 
      
 85 
     | 
    
         
            +
                    #
         
     | 
| 
      
 86 
     | 
    
         
            +
                    # @param hash [Hash]
         
     | 
| 
      
 87 
     | 
    
         
            +
                    # @return [Hash, String]
         
     | 
| 
      
 88 
     | 
    
         
            +
                    def dereference(hash)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      result = nil
         
     | 
| 
      
 90 
     | 
    
         
            +
                      if(hash.is_a?(Hash))
         
     | 
| 
      
 91 
     | 
    
         
            +
                        if(hash.keys.first == 'Ref' && flagged?(hash.values.first))
         
     | 
| 
      
 92 
     | 
    
         
            +
                          result = '__MODIFIED_REFERENCE_VALUE__'
         
     | 
| 
      
 93 
     | 
    
         
            +
                        elsif(hash.keys.first == 'Fn::GetAtt')
         
     | 
| 
      
 94 
     | 
    
         
            +
                          if(hash.values.last.last.start_with?('Outputs.'))
         
     | 
| 
      
 95 
     | 
    
         
            +
                            if(flagged?(hash.values.join('_')))
         
     | 
| 
      
 96 
     | 
    
         
            +
                              result = '__MODIFIED_REFERENCE_VALUE__'
         
     | 
| 
      
 97 
     | 
    
         
            +
                            end
         
     | 
| 
      
 98 
     | 
    
         
            +
                          elsif(flagged?(hash.values.first))
         
     | 
| 
      
 99 
     | 
    
         
            +
                            result = '__MODIFIED_REFERENCE_VALUE__'
         
     | 
| 
      
 100 
     | 
    
         
            +
                          end
         
     | 
| 
      
 101 
     | 
    
         
            +
                        end
         
     | 
| 
      
 102 
     | 
    
         
            +
                      end
         
     | 
| 
      
 103 
     | 
    
         
            +
                      result.nil? ? super : result
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                  # Resources that will be replaced on metadata init updates
         
     | 
| 
      
 109 
     | 
    
         
            +
                  REPLACE_ON_CFN_INIT_UPDATE = [
         
     | 
| 
      
 110 
     | 
    
         
            +
                    'AWS::AutoScaling::LaunchConfiguration'
         
     | 
| 
      
 111 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  # @return [Smash] initialized translators
         
     | 
| 
      
 114 
     | 
    
         
            +
                  attr_accessor :translators
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  # Simple overload to load in aws resource set from
         
     | 
| 
      
 117 
     | 
    
         
            +
                  # sparkleformation
         
     | 
| 
      
 118 
     | 
    
         
            +
                  def initialize(*_)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    super
         
     | 
| 
      
 120 
     | 
    
         
            +
                    SfnAws.load!
         
     | 
| 
      
 121 
     | 
    
         
            +
                    @translators = Smash.new
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  # Generate update report
         
     | 
| 
      
 125 
     | 
    
         
            +
                  #
         
     | 
| 
      
 126 
     | 
    
         
            +
                  # @param template [Hash] updated template
         
     | 
| 
      
 127 
     | 
    
         
            +
                  # @param parameters [Hash] runtime parameters for update
         
     | 
| 
      
 128 
     | 
    
         
            +
                  #
         
     | 
| 
      
 129 
     | 
    
         
            +
                  # @return [Hash] report
         
     | 
| 
      
 130 
     | 
    
         
            +
                  def generate_plan(template, parameters)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    Smash.new(
         
     | 
| 
      
 132 
     | 
    
         
            +
                      :stacks => Smash.new(
         
     | 
| 
      
 133 
     | 
    
         
            +
                        origin_stack.name => plan_stack(
         
     | 
| 
      
 134 
     | 
    
         
            +
                          origin_stack,
         
     | 
| 
      
 135 
     | 
    
         
            +
                          template,
         
     | 
| 
      
 136 
     | 
    
         
            +
                          parameters
         
     | 
| 
      
 137 
     | 
    
         
            +
                        )
         
     | 
| 
      
 138 
     | 
    
         
            +
                      ),
         
     | 
| 
      
 139 
     | 
    
         
            +
                      :added => Smash.new,
         
     | 
| 
      
 140 
     | 
    
         
            +
                      :removed => Smash.new,
         
     | 
| 
      
 141 
     | 
    
         
            +
                      :replace => Smash.new,
         
     | 
| 
      
 142 
     | 
    
         
            +
                      :interrupt => Smash.new,
         
     | 
| 
      
 143 
     | 
    
         
            +
                      :unavailable => Smash.new,
         
     | 
| 
      
 144 
     | 
    
         
            +
                      :unknown => Smash.new
         
     | 
| 
      
 145 
     | 
    
         
            +
                    )
         
     | 
| 
      
 146 
     | 
    
         
            +
                  end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  # Generate plan for stack
         
     | 
| 
      
 151 
     | 
    
         
            +
                  #
         
     | 
| 
      
 152 
     | 
    
         
            +
                  # @param stack [Miasma::Models::Orchestration::Stack]
         
     | 
| 
      
 153 
     | 
    
         
            +
                  # @param new_template [Hash]
         
     | 
| 
      
 154 
     | 
    
         
            +
                  # @param new_parameters [Hash]
         
     | 
| 
      
 155 
     | 
    
         
            +
                  # @return [Hash]
         
     | 
| 
      
 156 
     | 
    
         
            +
                  def plan_stack(stack, new_template, new_parameters)
         
     | 
| 
      
 157 
     | 
    
         
            +
                    plan_results = Smash.new(
         
     | 
| 
      
 158 
     | 
    
         
            +
                      :stacks => Smash.new,
         
     | 
| 
      
 159 
     | 
    
         
            +
                      :added => Smash.new,
         
     | 
| 
      
 160 
     | 
    
         
            +
                      :removed => Smash.new,
         
     | 
| 
      
 161 
     | 
    
         
            +
                      :replace => Smash.new,
         
     | 
| 
      
 162 
     | 
    
         
            +
                      :interrupt => Smash.new,
         
     | 
| 
      
 163 
     | 
    
         
            +
                      :unavailable => Smash.new,
         
     | 
| 
      
 164 
     | 
    
         
            +
                      :unknown => Smash.new,
         
     | 
| 
      
 165 
     | 
    
         
            +
                      :outputs => Smash.new,
         
     | 
| 
      
 166 
     | 
    
         
            +
                      :n_outputs => []
         
     | 
| 
      
 167 
     | 
    
         
            +
                    )
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                    origin_template = dereference_template("#{stack.data.checksum}_origin", stack.template, stack.parameters)
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                    t_key = "#{stack.data.checksum}_#{stack.data.fetch(:logical_id, stack.name)}"
         
     | 
| 
      
 172 
     | 
    
         
            +
                    run_stack_diff(stack, t_key, plan_results, origin_template, new_template, new_parameters)
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                    new_checksum = nil
         
     | 
| 
      
 175 
     | 
    
         
            +
                    current_checksum = false
         
     | 
| 
      
 176 
     | 
    
         
            +
                    until(new_checksum == current_checksum)
         
     | 
| 
      
 177 
     | 
    
         
            +
                      current_checksum = plan_results.checksum
         
     | 
| 
      
 178 
     | 
    
         
            +
                      run_stack_diff(stack, t_key, plan_results, origin_template, new_template, new_parameters)
         
     | 
| 
      
 179 
     | 
    
         
            +
                      new_checksum = plan_results.checksum
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    scrub_plan(plan_results)
         
     | 
| 
      
 182 
     | 
    
         
            +
                    plan_results
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                  # Check if resource type is stack resource type
         
     | 
| 
      
 186 
     | 
    
         
            +
                  #
         
     | 
| 
      
 187 
     | 
    
         
            +
                  # @param type [String]
         
     | 
| 
      
 188 
     | 
    
         
            +
                  # @return [TrueClass, FalseClass]
         
     | 
| 
      
 189 
     | 
    
         
            +
                  def is_stack?(type)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    origin_stack.api.data.fetch(:stack_types, ['AWS::CloudFormation::Stack']).include?(type)
         
     | 
| 
      
 191 
     | 
    
         
            +
                  end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                  # Scrub the plan results to only provide highest precedence diff
         
     | 
| 
      
 194 
     | 
    
         
            +
                  # items
         
     | 
| 
      
 195 
     | 
    
         
            +
                  #
         
     | 
| 
      
 196 
     | 
    
         
            +
                  # @param results [Hash]
         
     | 
| 
      
 197 
     | 
    
         
            +
                  # @return [NilClass]
         
     | 
| 
      
 198 
     | 
    
         
            +
                  def scrub_plan(results)
         
     | 
| 
      
 199 
     | 
    
         
            +
                    precedence = [:unavailable, :replace, :interrupt, :unavailable, :unknown]
         
     | 
| 
      
 200 
     | 
    
         
            +
                    until(precedence.empty?)
         
     | 
| 
      
 201 
     | 
    
         
            +
                      key = precedence.shift
         
     | 
| 
      
 202 
     | 
    
         
            +
                      results[key].keys.each do |k|
         
     | 
| 
      
 203 
     | 
    
         
            +
                        precedence.each do |p_key|
         
     | 
| 
      
 204 
     | 
    
         
            +
                          results[p_key].delete(k)
         
     | 
| 
      
 205 
     | 
    
         
            +
                        end
         
     | 
| 
      
 206 
     | 
    
         
            +
                      end
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end
         
     | 
| 
      
 208 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 209 
     | 
    
         
            +
                  end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                  # Run the stack diff and populate the result set
         
     | 
| 
      
 212 
     | 
    
         
            +
                  #
         
     | 
| 
      
 213 
     | 
    
         
            +
                  # @param stack [Miasma::Models::Orchestration::Stack] existing stack
         
     | 
| 
      
 214 
     | 
    
         
            +
                  # @param plan_result [Smash] plan data to populate
         
     | 
| 
      
 215 
     | 
    
         
            +
                  # @param origin_template [Smash] template of existing stack
         
     | 
| 
      
 216 
     | 
    
         
            +
                  # @param new_template [Smash] template to replace existing
         
     | 
| 
      
 217 
     | 
    
         
            +
                  # @param new_parameters [Smash] parameters to be applied to update
         
     | 
| 
      
 218 
     | 
    
         
            +
                  # @return [NilClass]
         
     | 
| 
      
 219 
     | 
    
         
            +
                  def run_stack_diff(stack, t_key, plan_results, origin_template, new_template, new_parameters)
         
     | 
| 
      
 220 
     | 
    
         
            +
                    translator = translator_for(t_key)
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                    new_parameters = new_parameters.dup
         
     | 
| 
      
 223 
     | 
    
         
            +
                    stack.parameters.each do |k,v|
         
     | 
| 
      
 224 
     | 
    
         
            +
                      if(new_parameters[k].is_a?(Hash))
         
     | 
| 
      
 225 
     | 
    
         
            +
                        val = translator.dereference(new_parameters[k])
         
     | 
| 
      
 226 
     | 
    
         
            +
                        new_parameters[k] = val == new_parameters[k] ? v : val
         
     | 
| 
      
 227 
     | 
    
         
            +
                      end
         
     | 
| 
      
 228 
     | 
    
         
            +
                    end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                    update_template = dereference_template(
         
     | 
| 
      
 231 
     | 
    
         
            +
                      t_key, new_template.to_smash, new_parameters,
         
     | 
| 
      
 232 
     | 
    
         
            +
                      plan_results[:replace].keys + plan_results[:unavailable].keys
         
     | 
| 
      
 233 
     | 
    
         
            +
                    )
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                    o_nested_stacks = origin_template['Resources'].find_all do |s_name, s_val|
         
     | 
| 
      
 236 
     | 
    
         
            +
                      is_stack?(s_val['Type'])
         
     | 
| 
      
 237 
     | 
    
         
            +
                    end.map(&:first)
         
     | 
| 
      
 238 
     | 
    
         
            +
                    n_nested_stacks = new_template['Resources'].find_all do |s_name, s_val|
         
     | 
| 
      
 239 
     | 
    
         
            +
                      is_stack?(s_val['Type'])
         
     | 
| 
      
 240 
     | 
    
         
            +
                    end.map(&:first)
         
     | 
| 
      
 241 
     | 
    
         
            +
                    [o_nested_stacks + n_nested_stacks].flatten.compact.uniq.each do |n_name|
         
     | 
| 
      
 242 
     | 
    
         
            +
                      o_stack = stack.nested_stacks(false).detect{|s| s.data[:logical_id] == n_name}
         
     | 
| 
      
 243 
     | 
    
         
            +
                      n_exists = is_stack?(update_template['Resources'].fetch(n_name, {})['Type'])
         
     | 
| 
      
 244 
     | 
    
         
            +
                      n_template = update_template['Resources'].fetch(n_name, {}).fetch('Properties', {})['Stack']
         
     | 
| 
      
 245 
     | 
    
         
            +
                      n_parameters = update_template['Resources'].fetch(n_name, {}).fetch('Properties', {})['Parameters']
         
     | 
| 
      
 246 
     | 
    
         
            +
                      n_type = update_template['Resources'].fetch(n_name, {}).fetch('Type',
         
     | 
| 
      
 247 
     | 
    
         
            +
                        origin_template['Resources'][n_name]['Type']
         
     | 
| 
      
 248 
     | 
    
         
            +
                      )
         
     | 
| 
      
 249 
     | 
    
         
            +
                      resource = Smash.new(
         
     | 
| 
      
 250 
     | 
    
         
            +
                        :name => n_name,
         
     | 
| 
      
 251 
     | 
    
         
            +
                        :type => n_type,
         
     | 
| 
      
 252 
     | 
    
         
            +
                        :properties => []
         
     | 
| 
      
 253 
     | 
    
         
            +
                      )
         
     | 
| 
      
 254 
     | 
    
         
            +
                      if(o_stack && n_template)
         
     | 
| 
      
 255 
     | 
    
         
            +
                        n_parameters.keys.each do |n_key|
         
     | 
| 
      
 256 
     | 
    
         
            +
                          n_parameters[n_key] = translator.dereference(n_parameters[n_key])
         
     | 
| 
      
 257 
     | 
    
         
            +
                        end
         
     | 
| 
      
 258 
     | 
    
         
            +
                        n_results = plan_stack(o_stack, n_template, n_parameters)
         
     | 
| 
      
 259 
     | 
    
         
            +
                        unless(n_results[:outputs].empty?)
         
     | 
| 
      
 260 
     | 
    
         
            +
                          n_results[:outputs].keys.each do |n_output|
         
     | 
| 
      
 261 
     | 
    
         
            +
                            translator.flag_ref("#{n_name}_Outputs.#{n_output}")
         
     | 
| 
      
 262 
     | 
    
         
            +
                          end
         
     | 
| 
      
 263 
     | 
    
         
            +
                        end
         
     | 
| 
      
 264 
     | 
    
         
            +
                        plan_results[:stacks][n_name] = n_results
         
     | 
| 
      
 265 
     | 
    
         
            +
                      elsif(o_stack && (!n_template && !n_exists))
         
     | 
| 
      
 266 
     | 
    
         
            +
                        plan_results[:removed][n_name] = resource
         
     | 
| 
      
 267 
     | 
    
         
            +
                      elsif(n_template && !o_stack)
         
     | 
| 
      
 268 
     | 
    
         
            +
                        plan_results[:added][n_name] = resource
         
     | 
| 
      
 269 
     | 
    
         
            +
                      end
         
     | 
| 
      
 270 
     | 
    
         
            +
                    end
         
     | 
| 
      
 271 
     | 
    
         
            +
                    n_nested_stacks.each do |ns_name|
         
     | 
| 
      
 272 
     | 
    
         
            +
                      update_template['Resources'][ns_name]['Properties'].delete('Stack')
         
     | 
| 
      
 273 
     | 
    
         
            +
                    end
         
     | 
| 
      
 274 
     | 
    
         
            +
                    HashDiff.diff(origin_template, MultiJson.load(MultiJson.dump(update_template))).group_by do |item|
         
     | 
| 
      
 275 
     | 
    
         
            +
                      item[1]
         
     | 
| 
      
 276 
     | 
    
         
            +
                    end.each do |a_path, diff_items|
         
     | 
| 
      
 277 
     | 
    
         
            +
                      register_diff(
         
     | 
| 
      
 278 
     | 
    
         
            +
                        plan_results, a_path, diff_items, translator_for(t_key),
         
     | 
| 
      
 279 
     | 
    
         
            +
                        :origin => origin_template,
         
     | 
| 
      
 280 
     | 
    
         
            +
                        :update => update_template
         
     | 
| 
      
 281 
     | 
    
         
            +
                      )
         
     | 
| 
      
 282 
     | 
    
         
            +
                    end
         
     | 
| 
      
 283 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 284 
     | 
    
         
            +
                  end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
                  # Register a diff item into the results set
         
     | 
| 
      
 287 
     | 
    
         
            +
                  #
         
     | 
| 
      
 288 
     | 
    
         
            +
                  # @param results [Hash]
         
     | 
| 
      
 289 
     | 
    
         
            +
                  # @param path [String]
         
     | 
| 
      
 290 
     | 
    
         
            +
                  # @param diff [Array]
         
     | 
| 
      
 291 
     | 
    
         
            +
                  # @param templates [Hash]
         
     | 
| 
      
 292 
     | 
    
         
            +
                  # @option :templates [Hash] :origin
         
     | 
| 
      
 293 
     | 
    
         
            +
                  # @option :templates [Hash] :update
         
     | 
| 
      
 294 
     | 
    
         
            +
                  def register_diff(results, path, diff, translator, templates)
         
     | 
| 
      
 295 
     | 
    
         
            +
                    if(path.start_with?('Resources'))
         
     | 
| 
      
 296 
     | 
    
         
            +
                      p_path = path.split('.')
         
     | 
| 
      
 297 
     | 
    
         
            +
                      if(p_path.size == 2)
         
     | 
| 
      
 298 
     | 
    
         
            +
                        diff = diff.first
         
     | 
| 
      
 299 
     | 
    
         
            +
                        key = diff.first == '+' ? :added : :removed
         
     | 
| 
      
 300 
     | 
    
         
            +
                        type = (key == :added ? templates[:update] : templates[:origin])['Resources'][p_path.last]['Type']
         
     | 
| 
      
 301 
     | 
    
         
            +
                        results[key][p_path.last] = Smash.new(
         
     | 
| 
      
 302 
     | 
    
         
            +
                          :name => p_path.last,
         
     | 
| 
      
 303 
     | 
    
         
            +
                          :type => type,
         
     | 
| 
      
 304 
     | 
    
         
            +
                          :properties => []
         
     | 
| 
      
 305 
     | 
    
         
            +
                        )
         
     | 
| 
      
 306 
     | 
    
         
            +
                      else
         
     | 
| 
      
 307 
     | 
    
         
            +
                        if(p_path.include?('Properties'))
         
     | 
| 
      
 308 
     | 
    
         
            +
                          resource_name = p_path[1]
         
     | 
| 
      
 309 
     | 
    
         
            +
                          property_name = p_path[3].sub(/\[\d+\]$/, '')
         
     | 
| 
      
 310 
     | 
    
         
            +
                          type = templates[:origin]['Resources'][resource_name]['Type']
         
     | 
| 
      
 311 
     | 
    
         
            +
                          info = SfnAws.registry[type]
         
     | 
| 
      
 312 
     | 
    
         
            +
                          effect = info[:full_properties].fetch(property_name, {}).fetch(:update_causes, :unknown)
         
     | 
| 
      
 313 
     | 
    
         
            +
                          resource = Smash.new(
         
     | 
| 
      
 314 
     | 
    
         
            +
                            :name => resource_name,
         
     | 
| 
      
 315 
     | 
    
         
            +
                            :type => type,
         
     | 
| 
      
 316 
     | 
    
         
            +
                            :properties => [property_name]
         
     | 
| 
      
 317 
     | 
    
         
            +
                          )
         
     | 
| 
      
 318 
     | 
    
         
            +
                          case effect
         
     | 
| 
      
 319 
     | 
    
         
            +
                          when :replacement
         
     | 
| 
      
 320 
     | 
    
         
            +
                            set_resource(:replace, results, resource_name, resource)
         
     | 
| 
      
 321 
     | 
    
         
            +
                          when :interrupt
         
     | 
| 
      
 322 
     | 
    
         
            +
                            set_resource(:interrupt, results, resource_name, resource)
         
     | 
| 
      
 323 
     | 
    
         
            +
                          when :unavailable
         
     | 
| 
      
 324 
     | 
    
         
            +
                            set_resource(:unavailable, results, resource_name, resource)
         
     | 
| 
      
 325 
     | 
    
         
            +
                          when :none
         
     | 
| 
      
 326 
     | 
    
         
            +
                            # \o/
         
     | 
| 
      
 327 
     | 
    
         
            +
                          else
         
     | 
| 
      
 328 
     | 
    
         
            +
                            set_resource(:unknown, results, resource_name, resource)
         
     | 
| 
      
 329 
     | 
    
         
            +
                          end
         
     | 
| 
      
 330 
     | 
    
         
            +
                        elsif(p_path.include?('AWS::CloudFormation::Init'))
         
     | 
| 
      
 331 
     | 
    
         
            +
                          resource_name = p_path[1]
         
     | 
| 
      
 332 
     | 
    
         
            +
                          type = templates[:origin]['Resources'][resource_name]['Type']
         
     | 
| 
      
 333 
     | 
    
         
            +
                          if(REPLACE_ON_CFN_INIT_UPDATE.include?(type))
         
     | 
| 
      
 334 
     | 
    
         
            +
                            set_resource(:replace, results, resource_name,
         
     | 
| 
      
 335 
     | 
    
         
            +
                              Smash.new(
         
     | 
| 
      
 336 
     | 
    
         
            +
                                :name => resource_name,
         
     | 
| 
      
 337 
     | 
    
         
            +
                                :type => type,
         
     | 
| 
      
 338 
     | 
    
         
            +
                                :properties => ['AWS::CloudFormation::Init']
         
     | 
| 
      
 339 
     | 
    
         
            +
                              )
         
     | 
| 
      
 340 
     | 
    
         
            +
                            )
         
     | 
| 
      
 341 
     | 
    
         
            +
                          end
         
     | 
| 
      
 342 
     | 
    
         
            +
                        end
         
     | 
| 
      
 343 
     | 
    
         
            +
                      end
         
     | 
| 
      
 344 
     | 
    
         
            +
                    elsif(path.start_with?('Outputs'))
         
     | 
| 
      
 345 
     | 
    
         
            +
                      set_resource(:outputs, results, path.split('.')[1], {:properties => []})
         
     | 
| 
      
 346 
     | 
    
         
            +
                    end
         
     | 
| 
      
 347 
     | 
    
         
            +
                  end
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
                  # Set resource item into result set
         
     | 
| 
      
 350 
     | 
    
         
            +
                  #
         
     | 
| 
      
 351 
     | 
    
         
            +
                  # @param kind [Symbol]
         
     | 
| 
      
 352 
     | 
    
         
            +
                  # @param results [Hash]
         
     | 
| 
      
 353 
     | 
    
         
            +
                  # @param name [String]
         
     | 
| 
      
 354 
     | 
    
         
            +
                  # @param resource [Hash]
         
     | 
| 
      
 355 
     | 
    
         
            +
                  def set_resource(kind, results, name, resource)
         
     | 
| 
      
 356 
     | 
    
         
            +
                    if(results[kind][name])
         
     | 
| 
      
 357 
     | 
    
         
            +
                      results[kind][name][:properties] += resource[:properties]
         
     | 
| 
      
 358 
     | 
    
         
            +
                      results[kind][name][:properties].uniq!
         
     | 
| 
      
 359 
     | 
    
         
            +
                    else
         
     | 
| 
      
 360 
     | 
    
         
            +
                      results[kind][name] = resource
         
     | 
| 
      
 361 
     | 
    
         
            +
                    end
         
     | 
| 
      
 362 
     | 
    
         
            +
                  end
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
                  # Dereference all parameters within template to allow for
         
     | 
| 
      
 365 
     | 
    
         
            +
                  # processing using real values
         
     | 
| 
      
 366 
     | 
    
         
            +
                  #
         
     | 
| 
      
 367 
     | 
    
         
            +
                  # @param t_key [String]
         
     | 
| 
      
 368 
     | 
    
         
            +
                  # @param template [Hash]
         
     | 
| 
      
 369 
     | 
    
         
            +
                  # @param parameters [Hash]
         
     | 
| 
      
 370 
     | 
    
         
            +
                  # @param flagged [Array<String>]
         
     | 
| 
      
 371 
     | 
    
         
            +
                  #
         
     | 
| 
      
 372 
     | 
    
         
            +
                  # @return [Hash]
         
     | 
| 
      
 373 
     | 
    
         
            +
                  def dereference_template(t_key, template, parameters, flagged=[])
         
     | 
| 
      
 374 
     | 
    
         
            +
                    translator = translator_for(t_key, template, parameters)
         
     | 
| 
      
 375 
     | 
    
         
            +
                    flagged.each do |item|
         
     | 
| 
      
 376 
     | 
    
         
            +
                      translator.flag_ref(item)
         
     | 
| 
      
 377 
     | 
    
         
            +
                    end
         
     | 
| 
      
 378 
     | 
    
         
            +
                    template['Resources'] = translator.dereference_processor(template['Resources'], ['Ref', 'Fn', 'DEREF'])
         
     | 
| 
      
 379 
     | 
    
         
            +
                    template['Outputs'] = translator.dereference_processor(template['Outputs'], ['Ref', 'Fn', 'DEREF'])
         
     | 
| 
      
 380 
     | 
    
         
            +
                    template
         
     | 
| 
      
 381 
     | 
    
         
            +
                  end
         
     | 
| 
      
 382 
     | 
    
         
            +
             
     | 
| 
      
 383 
     | 
    
         
            +
                  # Provide a translator instance for given key (new or cached instance)
         
     | 
| 
      
 384 
     | 
    
         
            +
                  #
         
     | 
| 
      
 385 
     | 
    
         
            +
                  # @param t_key [String] identifier
         
     | 
| 
      
 386 
     | 
    
         
            +
                  # @param template [Hash] stack template
         
     | 
| 
      
 387 
     | 
    
         
            +
                  # @param parameters [Hash] stack parameters
         
     | 
| 
      
 388 
     | 
    
         
            +
                  # @return [Translator]
         
     | 
| 
      
 389 
     | 
    
         
            +
                  def translator_for(t_key, template=nil, parameters=nil)
         
     | 
| 
      
 390 
     | 
    
         
            +
                    o_translator = translators[t_key]
         
     | 
| 
      
 391 
     | 
    
         
            +
                    if(template)
         
     | 
| 
      
 392 
     | 
    
         
            +
                      translator = Translator.new(template, :parameters => parameters)
         
     | 
| 
      
 393 
     | 
    
         
            +
                      if(o_translator)
         
     | 
| 
      
 394 
     | 
    
         
            +
                        o_translator.flagged.each do |i|
         
     | 
| 
      
 395 
     | 
    
         
            +
                          translator.flag_ref(i)
         
     | 
| 
      
 396 
     | 
    
         
            +
                        end
         
     | 
| 
      
 397 
     | 
    
         
            +
                      end
         
     | 
| 
      
 398 
     | 
    
         
            +
                      translators[t_key] = translator
         
     | 
| 
      
 399 
     | 
    
         
            +
                      o_translator = translator
         
     | 
| 
      
 400 
     | 
    
         
            +
                    else
         
     | 
| 
      
 401 
     | 
    
         
            +
                      unless(o_translator)
         
     | 
| 
      
 402 
     | 
    
         
            +
                        o_translator = Translator.new({}, :parameters => {})
         
     | 
| 
      
 403 
     | 
    
         
            +
                      end
         
     | 
| 
      
 404 
     | 
    
         
            +
                    end
         
     | 
| 
      
 405 
     | 
    
         
            +
                    o_translator
         
     | 
| 
      
 406 
     | 
    
         
            +
                  end
         
     | 
| 
      
 407 
     | 
    
         
            +
             
     | 
| 
      
 408 
     | 
    
         
            +
                end
         
     | 
| 
      
 409 
     | 
    
         
            +
              end
         
     | 
| 
      
 410 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/sfn/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: sfn
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.1.8
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Chris Roberts
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2015- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-11-04 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bogo-cli
         
     | 
| 
         @@ -124,6 +124,7 @@ files: 
     | 
|
| 
       124 
124 
     | 
    
         
             
            - lib/sfn/callback.rb
         
     | 
| 
       125 
125 
     | 
    
         
             
            - lib/sfn/callback/stack_policy.rb
         
     | 
| 
       126 
126 
     | 
    
         
             
            - lib/sfn/command.rb
         
     | 
| 
      
 127 
     | 
    
         
            +
            - lib/sfn/command/conf.rb
         
     | 
| 
       127 
128 
     | 
    
         
             
            - lib/sfn/command/create.rb
         
     | 
| 
       128 
129 
     | 
    
         
             
            - lib/sfn/command/describe.rb
         
     | 
| 
       129 
130 
     | 
    
         
             
            - lib/sfn/command/destroy.rb
         
     | 
| 
         @@ -143,6 +144,7 @@ files: 
     | 
|
| 
       143 
144 
     | 
    
         
             
            - lib/sfn/command_module/stack.rb
         
     | 
| 
       144 
145 
     | 
    
         
             
            - lib/sfn/command_module/template.rb
         
     | 
| 
       145 
146 
     | 
    
         
             
            - lib/sfn/config.rb
         
     | 
| 
      
 147 
     | 
    
         
            +
            - lib/sfn/config/conf.rb
         
     | 
| 
       146 
148 
     | 
    
         
             
            - lib/sfn/config/create.rb
         
     | 
| 
       147 
149 
     | 
    
         
             
            - lib/sfn/config/describe.rb
         
     | 
| 
       148 
150 
     | 
    
         
             
            - lib/sfn/config/destroy.rb
         
     | 
| 
         @@ -158,6 +160,8 @@ files: 
     | 
|
| 
       158 
160 
     | 
    
         
             
            - lib/sfn/config/validate.rb
         
     | 
| 
       159 
161 
     | 
    
         
             
            - lib/sfn/monkey_patch.rb
         
     | 
| 
       160 
162 
     | 
    
         
             
            - lib/sfn/monkey_patch/stack.rb
         
     | 
| 
      
 163 
     | 
    
         
            +
            - lib/sfn/planner.rb
         
     | 
| 
      
 164 
     | 
    
         
            +
            - lib/sfn/planner/aws.rb
         
     | 
| 
       161 
165 
     | 
    
         
             
            - lib/sfn/provider.rb
         
     | 
| 
       162 
166 
     | 
    
         
             
            - lib/sfn/utils.rb
         
     | 
| 
       163 
167 
     | 
    
         
             
            - lib/sfn/utils/debug.rb
         
     |