cfndsl 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cfndsl.rb CHANGED
@@ -1,448 +1,17 @@
1
1
  require 'json';
2
2
 
3
- class Module
4
- private
5
- def dsl_attr_setter(*symbols)
6
- ##
7
- # Create setter methods
8
- #
9
- # Usage:
10
- # class Something
11
- # dsl_attr_setter :Thing
12
- # end
13
- #
14
- # Generates a setter method like this one for each symbol in *symbols:
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