cfndsl 0.0.5 → 0.0.6
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.
- data/lib/cfndsl.rb +14 -443
- data/lib/cfndsl/CloudFormationTemplate.rb +151 -0
- data/lib/cfndsl/Errors.rb +33 -0
- data/lib/cfndsl/JSONable.rb +161 -0
- data/lib/cfndsl/Mappings.rb +25 -0
- data/lib/cfndsl/Metadata.rb +10 -0
- data/lib/cfndsl/Outputs.rb +13 -0
- data/lib/cfndsl/Parameters.rb +32 -0
- data/lib/cfndsl/Plurals.rb +28 -0
- data/lib/cfndsl/Properties.rb +25 -0
- data/lib/cfndsl/RefCheck.rb +48 -0
- data/lib/cfndsl/Resources.rb +28 -0
- data/lib/cfndsl/Types.rb +116 -0
- data/lib/cfndsl/aws_types.yaml +442 -0
- data/lib/cfndsl/module.rb +70 -0
- metadata +15 -1
data/lib/cfndsl.rb
CHANGED
@@ -1,448 +1,17 @@
|
|
1
1
|
require 'json';
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
# def Thing(value)
|
17
|
-
# @Thing = value
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
symbols.each do |symbol|
|
21
|
-
class_eval do
|
22
|
-
define_method(symbol) do |value|
|
23
|
-
instance_variable_set( "@#{symbol}", value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
##
|
30
|
-
# Plural names for lists of content objects
|
31
|
-
#
|
32
|
-
|
33
|
-
@@plurals = {
|
34
|
-
:Metadata => :Metadata,
|
35
|
-
:Property => :Properties
|
36
|
-
}
|
37
|
-
|
38
|
-
def dsl_content_object(*symbols)
|
39
|
-
##
|
40
|
-
# Create object declaration methods.
|
41
|
-
#
|
42
|
-
# Usage:
|
43
|
-
# Class Something
|
44
|
-
# dsl_content_object :Stuff
|
45
|
-
# end
|
46
|
-
#
|
47
|
-
# Generates methods like this:
|
48
|
-
#
|
49
|
-
# def Stuff(name, *values, &block)
|
50
|
-
# @Stuffs ||= {}
|
51
|
-
# @Stuffs[name] ||= CfnDsl::#{symbol}Definition.new(*values)
|
52
|
-
# @Stuffs[name].instance_eval &block if block_given?
|
53
|
-
# return @Stuffs[name]
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# The effect of this is that you can then create named sub-objects
|
57
|
-
# from the main object. The sub objects get stuffed into a container
|
58
|
-
# on the main object, and the block is then evaluated in the context
|
59
|
-
# of the new object.
|
60
|
-
#
|
61
|
-
symbols.each do |symbol|
|
62
|
-
plural = @@plurals[symbol] || "#{symbol}s"
|
63
|
-
class_eval %Q/
|
64
|
-
def #{symbol} (name,*values,&block)
|
65
|
-
name = name.to_s
|
66
|
-
@#{plural} ||= {}
|
67
|
-
@#{plural}[name] ||= CfnDsl::#{symbol}Definition.new(*values)
|
68
|
-
@#{plural}[name].instance_eval &block if block_given?
|
69
|
-
return @#{plural}[name]
|
70
|
-
end /
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
module RefCheck
|
77
|
-
##
|
78
|
-
# This module defines some methods for walking the reference tree
|
79
|
-
# of various objects.
|
80
|
-
#
|
81
|
-
def references(refs)
|
82
|
-
##
|
83
|
-
# Build up a set of references.
|
84
|
-
#
|
85
|
-
raise "Circular reference" if @_visited
|
86
|
-
|
87
|
-
@_visited = true
|
88
|
-
|
89
|
-
if( self.respond_to?(:get_references ) ) then
|
90
|
-
self.get_references.each do |ref|
|
91
|
-
refs[ref.to_s] = 1
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
self.ref_children.each do |elem|
|
96
|
-
elem.references(refs) if elem.respond_to?(:references)
|
97
|
-
end
|
98
|
-
|
99
|
-
@_visited = nil
|
100
|
-
|
101
|
-
return refs
|
102
|
-
end
|
103
|
-
|
104
|
-
def ref_children
|
105
|
-
return []
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
class Array
|
111
|
-
include RefCheck
|
112
|
-
def ref_children
|
113
|
-
return self
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class Hash
|
118
|
-
include RefCheck
|
119
|
-
def ref_children
|
120
|
-
return self.values
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
module CfnDsl
|
125
|
-
module Functions
|
126
|
-
|
127
|
-
def Ref(value)
|
128
|
-
##
|
129
|
-
# Equivalent to the CloudFormation template built in function Ref
|
130
|
-
RefDefinition.new(value)
|
131
|
-
end
|
132
|
-
|
133
|
-
def FnBase64( value )
|
134
|
-
##
|
135
|
-
# Equivalent to the CloudFormation template built in function Fn::Base64
|
136
|
-
Fn.new("Base64", value);
|
137
|
-
end
|
138
|
-
|
139
|
-
def FnFindInMap( map, key, value)
|
140
|
-
##
|
141
|
-
# Equivalent to the CloudFormation template built in function Fn::FindInMap
|
142
|
-
Fn.new("FindInMap", [map,key,value] )
|
143
|
-
end
|
144
|
-
|
145
|
-
def FnGetAtt(logicalResource, attribute)
|
146
|
-
##
|
147
|
-
# Equivalent to the CloudFormation template built in function Fn::GetAtt
|
148
|
-
Fn.new( "GetAtt", [logicalResource, attribute], [logicalResource] )
|
149
|
-
end
|
150
|
-
|
151
|
-
def FnGetAZs(region)
|
152
|
-
##
|
153
|
-
# Equivalent to the CloudFormation template built in function Fn::GetAZs
|
154
|
-
Fn.new("GetAZs", region)
|
155
|
-
end
|
156
|
-
|
157
|
-
def FnJoin(string, array)
|
158
|
-
##
|
159
|
-
# Equivalent to the CloudFormation template built in function Fn::Join
|
160
|
-
Fn.new("Join", [ string, array] )
|
161
|
-
end
|
162
|
-
|
163
|
-
def FnFormat(string, *arguments)
|
164
|
-
##
|
165
|
-
# Usage
|
166
|
-
# FnFormat( "This is a %0. It is 100%% %1","test", "effective")
|
167
|
-
#
|
168
|
-
# This will generate a call to Fn::Join that when evaluated will produce
|
169
|
-
# the string "This is a test. It is 100% effective."
|
170
|
-
#
|
171
|
-
# Think of this as %0,%1, etc in the format string being replaced by the
|
172
|
-
# corresponding arguments given after the format string. '%%' is replaced
|
173
|
-
# by the '%' character.
|
174
|
-
#
|
175
|
-
# The actual Fn::Join call corresponding to the above FnFormat call would be
|
176
|
-
# {"Fn::Join": ["",["This is a ","test",". It is 100","%"," ","effective"]]}
|
177
|
-
array = [];
|
178
|
-
string.scan( /(.*?)(%(%|\d+)|\z)/m ) do |x,y|
|
179
|
-
array.push $1 if $1 && $1 != ""
|
180
|
-
if( $3 == '%' ) then
|
181
|
-
array.push '%'
|
182
|
-
elsif( $3 ) then
|
183
|
-
array.push arguments[ $3.to_i ]
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
Fn.new("Join", ["", array])
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
|
192
|
-
class JSONable
|
193
|
-
##
|
194
|
-
# This is the base class for just about everything useful in the
|
195
|
-
# DSL. It knows how to turn DSL Objects into the corresponding
|
196
|
-
# json, and it lets you create new built in function objects
|
197
|
-
# from inside the context of a dsl object.
|
198
|
-
|
199
|
-
include Functions
|
200
|
-
extend Functions
|
201
|
-
include RefCheck
|
202
|
-
|
203
|
-
def to_json(*a)
|
204
|
-
##
|
205
|
-
# Use instance variables to build a json object. Instance
|
206
|
-
# variables that begin with a single underscore are elided.
|
207
|
-
# Instance variables that begin with two underscores have one of
|
208
|
-
# them removed.
|
209
|
-
hash = {}
|
210
|
-
self.instance_variables.each do |var|
|
211
|
-
name = var[1..-1]
|
212
|
-
|
213
|
-
if( name =~ /^__/ ) then
|
214
|
-
# if a variable starts with double underscore, strip one off
|
215
|
-
name = name[1..-1]
|
216
|
-
elsif( name =~ /^_/ ) then
|
217
|
-
# Hide variables that start with single underscore
|
218
|
-
name = nil
|
219
|
-
end
|
220
|
-
|
221
|
-
hash[name] = self.instance_variable_get var if name
|
222
|
-
end
|
223
|
-
hash.to_json(*a)
|
224
|
-
end
|
225
|
-
|
226
|
-
def ref_children
|
227
|
-
return self.instance_variables.map { |var| self.instance_variable_get var }
|
228
|
-
end
|
229
|
-
|
230
|
-
def declare(&block)
|
231
|
-
self.instance_eval &block if block_given?
|
232
|
-
end
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
class Fn < JSONable
|
237
|
-
##
|
238
|
-
# Handles all of the Fn:: objects
|
239
|
-
def initialize( function, argument, refs=[] )
|
240
|
-
@function = function
|
241
|
-
@argument = argument
|
242
|
-
@_refs = refs
|
243
|
-
end
|
244
|
-
|
245
|
-
def to_json(*a)
|
246
|
-
hash = {}
|
247
|
-
hash["Fn::#{@function}"] = @argument
|
248
|
-
hash.to_json(*a)
|
249
|
-
end
|
250
|
-
|
251
|
-
def get_references()
|
252
|
-
return @_refs
|
253
|
-
end
|
254
|
-
|
255
|
-
def ref_children
|
256
|
-
return [@argument]
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
|
261
|
-
class RefDefinition < JSONable
|
262
|
-
##
|
263
|
-
# Handles the Ref objects
|
264
|
-
def initialize( value )
|
265
|
-
@Ref = value
|
266
|
-
end
|
267
|
-
|
268
|
-
def get_references()
|
269
|
-
[@Ref]
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
|
274
|
-
class PropertyDefinition < JSONable
|
275
|
-
##
|
276
|
-
# Handles property objects for Resources
|
277
|
-
#
|
278
|
-
# Usage
|
279
|
-
# Resource("aaa") {
|
280
|
-
# Property("propName", "propValue" )
|
281
|
-
# }
|
282
|
-
#
|
283
|
-
def initialize(value)
|
284
|
-
@value = value;
|
285
|
-
end
|
286
|
-
|
287
|
-
def to_json(*a)
|
288
|
-
@value.to_json(*a)
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
class MappingDefinition < JSONable
|
293
|
-
##
|
294
|
-
# Handles mapping objects
|
295
|
-
#
|
296
|
-
# Usage:
|
297
|
-
# Mapping("AWSRegionArch2AMI", {
|
298
|
-
# "us-east-1" => { "32" => "ami-6411e20d", "64" => "ami-7a11e213" },
|
299
|
-
# "us-west-1" => { "32" => "ami-c9c7978c", "64" => "ami-cfc7978a" },
|
300
|
-
# "eu-west-1" => { "32" => "ami-37c2f643", "64" => "ami-31c2f645" },
|
301
|
-
# "ap-southeast-1" => { "32" => "ami-66f28c34", "64" => "ami-60f28c32" },
|
302
|
-
# "ap-northeast-1" => { "32" => "ami-9c03a89d", "64" => "ami-a003a8a1" }
|
303
|
-
# })
|
304
|
-
|
305
|
-
def initialize(value)
|
306
|
-
@value = value
|
307
|
-
end
|
308
|
-
|
309
|
-
def to_json(*a)
|
310
|
-
@value.to_json(*a)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
class ResourceDefinition < JSONable
|
315
|
-
##
|
316
|
-
# Handles Resource objects
|
317
|
-
dsl_attr_setter :Type, :DependsOn, :DeletionPolicy
|
318
|
-
dsl_content_object :Property, :Metadata
|
319
|
-
|
320
|
-
def get_references()
|
321
|
-
refs = []
|
322
|
-
if @DependsOn then
|
323
|
-
if( @DependsOn.respond_to?(:each) ) then
|
324
|
-
@DependsOn.each do |dep|
|
325
|
-
refs.push dep
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
if( @DependsOn.instance_of?(String) ) then
|
330
|
-
refs.push @DependsOn
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
refs
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
class MetadataDefinition < JSONable
|
339
|
-
##
|
340
|
-
# Handles Metadata objects
|
341
|
-
end
|
342
|
-
|
343
|
-
|
344
|
-
class ParameterDefinition < JSONable
|
345
|
-
##
|
346
|
-
# Handles input parameter objects
|
347
|
-
dsl_attr_setter :Type, :Default, :NoEcho, :AllowedValues, :AllowedPattern, :MaxLength, :MinLength, :MaxValue, :MinValue, :Description, :ConstraintDescription
|
348
|
-
def initialize
|
349
|
-
@Type = :String
|
350
|
-
end
|
351
|
-
|
352
|
-
def String
|
353
|
-
@Type = :String
|
354
|
-
end
|
355
|
-
|
356
|
-
def Number
|
357
|
-
@Type = :Number
|
358
|
-
end
|
359
|
-
|
360
|
-
def CommaDelimitedList
|
361
|
-
@Type = :CommaDelimitedList
|
362
|
-
end
|
363
|
-
|
364
|
-
def to_hash()
|
365
|
-
h = {}
|
366
|
-
h[:Type] = @Type;
|
367
|
-
h[:Default] = @Default if @Default
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
class OutputDefinition < JSONable
|
372
|
-
##
|
373
|
-
# Handles Output objects
|
374
|
-
dsl_attr_setter :Value, :Description
|
375
|
-
|
376
|
-
def initialize( value=nil)
|
377
|
-
@Value = value if value
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
class CloudFormationTemplate < JSONable
|
382
|
-
##
|
383
|
-
# Handles the overall template object
|
384
|
-
dsl_attr_setter :AWSTemplateFormatVersion, :Description
|
385
|
-
dsl_content_object :Parameter, :Output, :Resource, :Mapping
|
386
|
-
|
387
|
-
def initialize
|
388
|
-
@AWSTemplateFormatVersion = "2010-09-09"
|
389
|
-
end
|
390
|
-
|
391
|
-
def generateOutput()
|
392
|
-
puts self.to_json # uncomment for pretty printing # {:space => ' ', :indent => ' ', :object_nl => "\n", :array_nl => "\n" }
|
393
|
-
end
|
394
|
-
|
395
|
-
@@globalRefs = {
|
396
|
-
"AWS::NotificationARNs" => 1,
|
397
|
-
"AWS::Region" => 1,
|
398
|
-
"AWS::StackId" => 1,
|
399
|
-
"AWS::StackName" => 1
|
400
|
-
}
|
401
|
-
|
402
|
-
def isValidRef( ref, origin=nil)
|
403
|
-
ref = ref.to_s
|
404
|
-
origin = origin.to_s if origin
|
405
|
-
|
406
|
-
return true if @@globalRefs.has_key?( ref )
|
407
|
-
|
408
|
-
return true if @Parameters && @Parameters.has_key?( ref )
|
409
|
-
|
410
|
-
if( @Resources.has_key?( ref ) ) then
|
411
|
-
return !origin || !@_ResourceRefs || !@_ResourceRefs[ref] || !@_ResourceRefs[ref].has_key?(origin)
|
412
|
-
end
|
413
|
-
|
414
|
-
return false
|
415
|
-
end
|
416
|
-
|
417
|
-
def checkRefs()
|
418
|
-
invalids = []
|
419
|
-
@_ResourceRefs = {}
|
420
|
-
if(@Resources) then
|
421
|
-
@Resources.keys.each do |resource|
|
422
|
-
@_ResourceRefs[resource.to_s] = @Resources[resource].references({})
|
423
|
-
end
|
424
|
-
@_ResourceRefs.keys.each do |origin|
|
425
|
-
@_ResourceRefs[origin].keys.each do |ref|
|
426
|
-
invalids.push "Invalid Reference: Resource #{origin} refers to #{ref}" unless isValidRef(ref,origin)
|
427
|
-
end
|
428
|
-
end
|
429
|
-
end
|
430
|
-
outputRefs = {}
|
431
|
-
if(@Outputs) then
|
432
|
-
@Outputs.keys.each do |resource|
|
433
|
-
outputRefs[resource.to_s] = @Outputs[resource].references({})
|
434
|
-
end
|
435
|
-
outputRefs.keys.each do |origin|
|
436
|
-
outputRefs[origin].keys.each do |ref|
|
437
|
-
invalids.push "Invalid Reference: Output #{origin} refers to #{ref}" unless isValidRef(ref,nil)
|
438
|
-
end
|
439
|
-
end
|
440
|
-
end
|
441
|
-
return invalids.length>0 ? invalids : nil
|
442
|
-
end
|
443
|
-
|
444
|
-
end
|
445
|
-
end
|
3
|
+
require 'cfndsl/module'
|
4
|
+
require 'cfndsl/Errors'
|
5
|
+
require 'cfndsl/RefCheck'
|
6
|
+
require 'cfndsl/JSONable'
|
7
|
+
require 'cfndsl/Types'
|
8
|
+
require 'cfndsl/Properties'
|
9
|
+
require 'cfndsl/Mappings'
|
10
|
+
require 'cfndsl/Resources'
|
11
|
+
require 'cfndsl/Metadata'
|
12
|
+
require 'cfndsl/Parameters'
|
13
|
+
require 'cfndsl/Outputs'
|
14
|
+
require 'cfndsl/CloudFormationTemplate'
|
446
15
|
|
447
16
|
def CloudFormation(&block)
|
448
17
|
x = CfnDsl::CloudFormationTemplate.new
|
@@ -451,6 +20,8 @@ def CloudFormation(&block)
|
|
451
20
|
if( invalid_references ) then
|
452
21
|
puts invalid_references.join("\n");
|
453
22
|
exit(-1)
|
23
|
+
elsif( CfnDsl::Errors.errors? ) then
|
24
|
+
CfnDsl::Errors.report
|
454
25
|
else
|
455
26
|
x.generateOutput
|
456
27
|
end
|