Class: Aws::Cfn::Dsl::Template
- Inherits:
-
TemplateDSL
- Object
- TemplateDSL
- Aws::Cfn::Dsl::Template
- Defined in:
- lib/aws/cfn/dsl/template.rb
Instance Attribute Summary collapse
-
#dict ⇒ Object
readonly
Returns the value of attribute dict.
Instance Method Summary collapse
- #exec!(argv = ARGV) ⇒ Object
- #file(b) ⇒ Object
- #hash_refs(line, scope) ⇒ Object
-
#initialize(path = nil, &block) ⇒ Template
constructor
A new instance of Template.
- #mapping(name, options = nil) ⇒ Object
-
#output(name, options = nil) ⇒ Object
def resource_file(p) file “Resources/#p.rb” end.
-
#parameter(name, options = nil) ⇒ Object
def mapping_file(p) file “Mappings/#p.rb” end.
-
#resource(name, options = nil) ⇒ Object
def parameter_file(p) file “Parameters/#p.rb” end.
Constructor Details
#initialize(path = nil, &block) ⇒ Template
Returns a new instance of Template.
17 18 19 20 21 22 |
# File 'lib/aws/cfn/dsl/template.rb', line 17 def initialize(path=nil,&block) @path = path || File.dirname(caller[2].split(%r'\s+').shift.split(':')[0]) super() do # We do nothing with the template for now end end |
Instance Attribute Details
#dict ⇒ Object (readonly)
Returns the value of attribute dict.
11 12 13 |
# File 'lib/aws/cfn/dsl/template.rb', line 11 def dict @dict end |
Instance Method Details
#exec!(argv = ARGV) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/aws/cfn/dsl/template.rb', line 94 def exec!(argv=ARGV) @opts = Slop.parse(help: true) do "usage: #{$PROGRAM_NAME} <expand|diff|validate|create|update|delete>" on :o, :output=, 'The template file to save this DSL expansion to', as: String end action = argv[0] || 'expand' unless %w(expand diff validate create update delete).include? action $stderr.puts "usage: #{$PROGRAM_NAME} <expand|diff|validate|create|update|delete>" exit(2) end unless (argv & %w(--template-file --template-url)).empty? $stderr.puts "#{File.basename($PROGRAM_NAME)}: The --template-file and --template-url command-line options are not allowed. (You are running the template itself right now ... !)" exit(2) end # Find parameters where extension attribute :Immutable is true then remove it from the # cfn template since we can't pass it to CloudFormation. immutable_parameters = excise_parameter_attribute!(:Immutable) # Tag CloudFormation stacks based on :Tags defined in the template = # The command line string looks like: --tag "Key=key; Value=value" --tag "Key2=key2; Value2=value" = .sort.map { |tag| ["--tag", "Key=%s; Value=%s" % tag.split('=')] }.flatten # example: <template.rb> cfn-create-stack my-stack-name --parameters "Env=prod" --region eu-west-1 # Execute the AWS CLI cfn-cmd command to validate/create/update a CloudFormation stack. if action == 'diff' or (action == 'expand' and not nopretty) template_string = JSON.pretty_generate(self) else template_string = JSON.generate(self) end if action == 'expand' # Write the pretty-printed JSON template to stdout and exit. [--nopretty] option writes output with minimal whitespace # example: <template.rb> expand --parameters "Env=prod" --region eu-west-1 --nopretty if @opts[:output] dest = @opts[:output] if File.directory? dest file = File.basename $PROGRAM_NAME file.gsub!(%r'\.rb', '.json') dest = File.join dest, file end IO.write(dest, template_string) else puts template_string end exit(true) end temp_file = File.absolute_path("#{$PROGRAM_NAME}.expanded.json") File.write(temp_file, template_string) cmdline = ['cfn-cmd'] + argv + ['--template-file', temp_file] + case action when 'diff' # example: <template.rb> diff my-stack-name --parameters "Env=prod" --region eu-west-1 # Diff the current template for an existing stack with the expansion of this template. # The --parameters and --tag options were used to expand the template but we don't need them anymore. Discard. _, = (argv[1..-1], %w(), %w(--parameters --tag)) # Separate the remaining command-line options into options for 'cfn-cmd' and options for 'diff'. , = (, %w(), %w(--stack-name --region --parameters --connection-timeout -I --access-key-id -S --secret-key -K --ec2-private-key-file-path -U --url)) # If the first argument is a stack name then shift it from diff_options over to cfn_options. if [0] && !(/^-/ =~ [0]) .unshift(.shift) end # Run CloudFormation commands to describe the existing stack = .map { |arg| "'#{arg}'" }.join(' ') old_template_raw = exec_capture_stdout("cfn-cmd cfn-get-template #{}") # ec2 template output is not valid json: TEMPLATE "<json>\n"\n old_template_object = JSON.parse(old_template_raw[11..-3]) old_template_string = JSON.pretty_generate(old_template_object) old_stack_attributes = exec_describe_stack() = old_stack_attributes["TAGS"] old_parameters_string = old_stack_attributes["PARAMETERS"] # Sort the tag strings alphabetically to make them easily comparable = ( || '').split(';').sort.map { |tag| %Q(TAG "#{tag}"\n) }.join = .sort.map { |tag| "TAG \"#{tag}\"\n" }.join # Sort the parameter strings alphabetically to make them easily comparable old_parameters_string = (old_parameters_string || '').split(';').sort.map { |param| %Q(PARAMETER "#{param}"\n) }.join parameters_string = parameters.sort.map { |key, value| "PARAMETER \"#{key}=#{value}\"\n" }.join # Diff the expanded template with the template from CloudFormation. old_temp_file = File.absolute_path("#{$PROGRAM_NAME}.current.json") new_temp_file = File.absolute_path("#{$PROGRAM_NAME}.expanded.json") File.write(old_temp_file, + old_parameters_string + old_template_string) File.write(new_temp_file, + parameters_string + template_string) # Compare templates system(*["diff"] + + [old_temp_file, new_temp_file]) File.delete(old_temp_file) File.delete(new_temp_file) exit(true) when 'cfn-validate-template' # The cfn-validate-template command doesn't support --parameters so remove it if it was provided for template expansion. _, cmdline = (cmdline, %w(), %w(--parameters --tag)) when 'cfn-update-stack' # Pick out the subset of cfn-update-stack options that apply to cfn-describe-stacks. , = (argv[1..-1], %w(), %w(--stack-name --region --connection-timeout -I --access-key-id -S --secret-key -K --ec2-private-key-file-path -U --url)) # If the first argument is a stack name then shift it over to cfn_options. if [0] && !(/^-/ =~ [0]) .unshift(.shift) end # Run CloudFormation command to describe the existing stack = .map { |arg| "'#{arg}'" }.join(' ') old_stack_attributes = exec_describe_stack() # If updating a stack and some parameters are marked as immutable, fail if the new parameters don't match the old ones. if not immutable_parameters.empty? old_parameters_string = old_stack_attributes["PARAMETERS"] old_parameters = Hash[(old_parameters_string || '').split(';').map { |pair| pair.split('=', 2) }] new_parameters = parameters immutable_parameters.sort.each do |param| if old_parameters[param].to_s != new_parameters[param].to_s $stderr.puts "Error: cfn-update-stack may not update immutable parameter " + "'#{param}=#{old_parameters[param]}' to '#{param}=#{new_parameters[param]}'." exit(false) end end end # Tags are immutable in CloudFormation. The cfn-update-stack command doesn't support --tag options, so remove # the argument (if it exists) and validate against the existing stack to ensure tags haven't changed. # Compare the sorted arrays for an exact match = old_stack_attributes['TAGS'].split(';').sort rescue [] # Use empty Array if .split fails if != $stderr.puts "CloudFormation stack tags do not match and cannot be updated. You must either use the same tags or create a new stack." + "\n" + ( - ).map {|tag| "< #{tag}" }.join("\n") + "\n" + "---" + "\n" + ( - ).map {|tag| "> #{tag}"}.join("\n") exit(false) end _, cmdline = (cmdline, %w(), %w(--tag)) end # Execute command cmdline unless system(*cmdline) $stderr.puts "\nExecution of 'cfn-cmd' failed. To facilitate debugging, the generated JSON template " + "file was not deleted. You may delete the file manually if it isn't needed: #{temp_file}" exit(false) end File.delete(temp_file) exit(true) end |
#file(b) ⇒ Object
24 25 26 27 |
# File 'lib/aws/cfn/dsl/template.rb', line 24 def file(b) block = File.read File.join(@path,b) eval block end |
#hash_refs(line, scope) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/aws/cfn/dsl/template.rb', line 73 def hash_refs(line,scope) match = line.match %r/^(.*?)(\{\s*:\S+\s*=>.*?\}|\{\s*\S+:\s*.*?\})(.*)$/ if match h = nil eval "h = #{match[2]}", binding k = h.keys[0] v = h.delete(k) v = if v.is_a?Array v.map{|e| e.to_s } else v.to_s end h[k.to_s] = v scope[:logger].debug h [match[1], h, hash_refs(match[3],scope) ] else "#{line}\n" end end |
#mapping(name, options = nil) ⇒ Object
29 30 31 32 33 34 35 |
# File 'lib/aws/cfn/dsl/template.rb', line 29 def mapping(name, =nil) if .nil? file "Mappings/#{name}.rb" else super(name,) end end |
#output(name, options = nil) ⇒ Object
def resource_file(p)
file "Resources/#{p}.rb"
end
65 66 67 68 69 70 71 |
# File 'lib/aws/cfn/dsl/template.rb', line 65 def output(name, =nil) if .nil? file "Outputs/#{name}.rb" else super(name,) end end |
#parameter(name, options = nil) ⇒ Object
def mapping_file(p)
file "Mappings/#{p}.rb"
end
41 42 43 44 45 46 47 |
# File 'lib/aws/cfn/dsl/template.rb', line 41 def parameter(name, =nil) if .nil? file "Parameters/#{name}.rb" else super(name,) end end |
#resource(name, options = nil) ⇒ Object
def parameter_file(p)
file "Parameters/#{p}.rb"
end
53 54 55 56 57 58 59 |
# File 'lib/aws/cfn/dsl/template.rb', line 53 def resource(name, =nil) if .nil? file "Resources/#{name}.rb" else super(name,) end end |