Class: CloudFormationTool::CloudFormation
- Inherits:
-
Object
- Object
- CloudFormationTool::CloudFormation
show all
- Defined in:
- lib/cloud_formation_tool/cloud_formation.rb,
lib/cloud_formation_tool/cloud_formation/stack.rb,
lib/cloud_formation_tool/cloud_formation/lambda_code.rb,
lib/cloud_formation_tool/cloud_formation/nested_stack.rb,
lib/cloud_formation_tool/cloud_formation/cloud_front_distribution.rb
Defined Under Namespace
Modules: CloudFrontDistribution, CloudFrontInvalidation
Classes: LambdaCode, NestedStack, Stack
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
Returns a new instance of CloudFormation.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 15
def initialize(path)
$MAX_USER_DATA_SIZE = 16384 if $MAX_USER_DATA_SIZE.nil?
log "Loading #{path}"
@path = path
@path = "#{@path}/cloud-formation.yaml" if File.directory? @path
@path = "#{@path}.yaml" if !File.exist? @path and File.exist? "#{@path}.yaml"
@basedir = File.dirname(@path)
@compiled = false
@params = nil
begin
text = File.read(@path)
text.gsub!(/^#.*\n/,'')
text = fixShorthand(text)
@data = YAML.load(text, filename: @path, permitted_classes: [Date, Symbol]).to_h
rescue Psych::SyntaxError => e
e.message =~ /line (\d+) column (\d+)/
lines = text.split "\n"
raise CloudFormationTool::Errors::AppError, "Error parsing #{path} at line #{e.line} column #{e.column}:\n" +
"#{lines[e.line-1]}\n" +
"#{(' ' * (e.column - 1 ))}^- #{e.problem} #{e.context}"
rescue Errno::ENOENT => e
raise CloudFormationTool::Errors::AppError, "Error reading #{path}: #{e.message}"
end
end
|
Instance Attribute Details
#basedir ⇒ Object
Returns the value of attribute basedir.
13
14
15
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 13
def basedir
@basedir
end
|
Class Method Details
.parse(path) ⇒ Object
9
10
11
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 9
def self.parse(path)
CloudFormation.new(path)
end
|
Instance Method Details
#compile(parameters = nil) ⇒ Object
41
42
43
44
45
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 41
def compile(parameters = nil)
@params = parameters unless parameters.nil?
embed_includes
@data = load_files(@data)
end
|
#each ⇒ Object
227
228
229
230
231
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 227
def each
compile['Parameters'].each do |name, param|
yield name, param['Default']
end
end
|
#embed_includes ⇒ Object
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
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 96
def embed_includes
(@data.delete(@data.keys.find{|k| k.start_with? 'Include'}) || []).each do |path|
realpath = "#{@basedir}/#{path}"
cfile_key = File.dirname(realpath).gsub(%r{/(.)}){|m| $1.upcase }.gsub(/\W+/,'')
rewrites = Hash.new
CloudFormation.new(realpath).compile.each do |category, catdata|
next if %w(AWSTemplateFormatVersion Description).include? category
if category == "Parameters"
rewriteParameters catdata, cfile_key, rewrites
@data["Parameters"].merge! catdata
next
end
case catdata
when Hash
(@data[category] ||= {}).keys.each do |key|
if catdata.has_key? key
raise CloudFormationTool::Errors::AppError, "Error compiling #{path} - duplicate '#{category}' item: #{key}"
end
end
catdata = fixrefs(catdata, rewrites)
@data[category].merge! catdata
when Array
if @data[category].nil?
@data[category] = catdata
elsif @data[category].is_a? Array
@data[category] += catdata
else
raise CloudFormationTool::Errors::AppError, "Error compiling #{path} - conflicting types for '#{category}'"
end
else
if @data[category].nil?
@data[category] = catdata
else
raise CloudFormationTool::Errors::AppError, "Error compiling #{path} - I do not know how to merge non-list non-dictionary '#{category}'!"
end
end
end
end
end
|
#embed_includes_future ⇒ Object
86
87
88
89
90
91
92
93
94
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 86
def embed_includes_future
(@data.delete(@data.keys.find{|k| k.start_with? 'Include'}) || []).each do |path|
case path
when Hash
when String
embed_included_path path
end
end
end
|
#fixrefs(data, rmap) ⇒ Object
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 66
def fixrefs(data, rmap)
case data
when Hash
data.inject({}) do |h,(k,v)|
h[k] = if k == "Ref"
rmap[v] || v
else
fixrefs(v,rmap)
end
h
end
when Array
data.collect do |item|
fixrefs(item, rmap)
end
else
return data
end
end
|
#fixShorthand(text) ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 52
def fixShorthand(text)
text.gsub(/(?:(\s*)([^![:space:]]+))?(\s+)!(\w+)/) do |match|
case $4
when *%w(Base64 FindInMap GetAtt GetAZs ImportValue Join Select Sub Split
And Equals If Not Or)
($2.nil? ? "" : "#{$1}#{$2}\n#{$1} ") + "#{$3}\"Fn::#{$4}\":"
when 'Ref'
"#{$1}#{$2}\n#{$1} #{$3}#{$4}:"
else
match
end
end
end
|
#load_files(data, restype = nil) ⇒ Object
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
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 186
def load_files(data, restype = nil)
case data
when Array
data.collect { |data| load_files(data, restype) }
when Hash
restype = data['Type'] if restype.nil? and data.key?('Type')
data.inject({}) do |dict, (key, val)|
dict[key] = case restype
when 'AWS::AutoScaling::LaunchConfiguration', 'AWS::EC2::LaunchTemplate'
if (key == "UserData") and (val["File"])
CloudInit.new("#{@basedir}/#{val["File"]}").to_base64
elsif (key == "UserData") and (val["FileTemplate"])
{ "Fn::Base64" => { "Fn::Sub" => CloudInit.new("#{@basedir}/#{val["FileTemplate"]}").compile } }
else
load_files(val, restype)
end
when 'AWS::Lambda::Function'
if key == 'Code'
LambdaCode.new(val, self, data['Runtime']).to_cloudformation
else
load_files(val, restype)
end
when 'AWS::CloudFormation::Stack'
if key == 'Properties' and val.key?('Template')
NestedStack.new(val, self).to_cloudformation
else
load_files(val, restype)
end
else
load_files(val, restype)
end
dict
end
else
data
end
end
|
#resolveVal(value) ⇒ Object
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 163
def resolveVal(value)
case value
when Hash
if value.key? 'Ref'
if @params.nil?
value
else res = @params[value['Ref']] || ((@data['Parameters']||{})[value['Ref']] || {})['Default']
if res.nil?
raise CloudFormationTool::Errors::AppError, "Reference #{value['Ref']} can't be resolved"
end
res
end
else
raise CloudFormationTool::Errors::AppError, "Value #{value} is not a valid value or reference"
end
else
value
end
end
|
#rewriteParameters(data, key, rewrites) ⇒ Object
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 142
def rewriteParameters data, key, rewrites
(@data["Parameters"]||={}).each do |name, param|
unless data.has_key? name
@data["Parameters"][name] = param
next
end
next if param['Default'] == data[name]['Default']
if data[name].has_key?('Override') and data[name]['Override'] == false
data.delete(name)
next
end
newname = "#{key}z#{name}"
log "Rewriting conflicting parameter #{name} (='#{data[name]['Default']}') to #{newname}"
data[newname] = data.delete name
rewrites[name] = newname
end
end
|
#to_yaml(parameters = {}) ⇒ Object
47
48
49
50
|
# File 'lib/cloud_formation_tool/cloud_formation.rb', line 47
def to_yaml(parameters = {})
@params = parameters
compile.to_yaml
end
|