cfndsl 0.1.3 → 0.1.4
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/bin/cfndsl +66 -3
- data/lib/cfndsl.rb +82 -0
- data/lib/cfndsl/CloudFormationTemplate.rb +115 -6
- data/lib/cfndsl/Types.rb +162 -12
- data/lib/cfndsl/aws_types.yaml +20 -0
- data/lib/cfndsl/os_types.yaml +2427 -0
- metadata +31 -23
- checksums.yaml +0 -7
data/bin/cfndsl
CHANGED
@@ -1,4 +1,67 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
2
3
|
require 'cfndsl'
|
3
|
-
|
4
|
-
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
optparse = OptionParser.new do|opts|
|
9
|
+
opts.banner = "Usage: cfndsl [options] FILE"
|
10
|
+
|
11
|
+
# Define the options, and what they do
|
12
|
+
options[:output] = '-'
|
13
|
+
opts.on( '-o', '--output FILE', 'Write output to file' ) do |file|
|
14
|
+
options[:output] = file
|
15
|
+
end
|
16
|
+
|
17
|
+
options[:extras] = []
|
18
|
+
opts.on( '-y', '--yaml FILE', 'Import yaml file as local variables' ) do |file|
|
19
|
+
options[:extras].push([:yaml,File.expand_path(file)])
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on( '-r', '--ruby FILE', 'Evaluate ruby file before template' ) do |file|
|
23
|
+
options[:extras].push([:ruby,File.expand_path(file)])
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on( '-j', '--json FILE', 'Import json file as local variables' ) do |file|
|
27
|
+
options[:extras].push([:json,File.expand_path(file)])
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
opts.on( '-D', '--define "VARIABLE=VALUE"', 'Directly set local VARIABLE as VALUE' ) do |file|
|
32
|
+
options[:extras].push([:raw,file])
|
33
|
+
end
|
34
|
+
|
35
|
+
options[:verbose] = false
|
36
|
+
opts.on('-v', '--verbose', "Turn on verbose ouptut") do
|
37
|
+
options[:verbose] = true
|
38
|
+
end
|
39
|
+
|
40
|
+
# This displays the help screen, all programs are
|
41
|
+
# assumed to have this option.
|
42
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
43
|
+
puts opts
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
optparse.parse!
|
49
|
+
unless ARGV[0] then
|
50
|
+
puts optparse.help
|
51
|
+
exit(1)
|
52
|
+
end
|
53
|
+
|
54
|
+
filename = File.expand_path(ARGV[0])
|
55
|
+
verbose = options[:verbose] && STDERR
|
56
|
+
|
57
|
+
model = CfnDsl::eval_file_with_extras(filename, options[:extras], verbose)
|
58
|
+
|
59
|
+
output = STDOUT
|
60
|
+
if options[:output] != '-' then
|
61
|
+
verbose.puts("Writing to #{options[:output]}") if verbose
|
62
|
+
output = File.open( File.expand_path(options[:output]), "w")
|
63
|
+
else
|
64
|
+
verbose.puts("Writing to STDOUT") if verbose
|
65
|
+
end
|
66
|
+
|
67
|
+
output.puts model.to_json
|
data/lib/cfndsl.rb
CHANGED
@@ -15,6 +15,75 @@ require 'cfndsl/Parameters'
|
|
15
15
|
require 'cfndsl/Outputs'
|
16
16
|
require 'cfndsl/CloudFormationTemplate'
|
17
17
|
|
18
|
+
module CfnDsl
|
19
|
+
def self.eval_file_with_extras(filename, extras = [], logstream = nil)
|
20
|
+
# This function handles the eval of the template file and returns the
|
21
|
+
# results. It does this with a ruby "eval", but it builds up a customized
|
22
|
+
# binding environment before it calls eval. The environment can be
|
23
|
+
# customized by passing a list of customizations in the extras parameter.
|
24
|
+
#
|
25
|
+
# These customizations are expressed as an array of pairs of
|
26
|
+
# (type,filename). They are evaluated in the order they appear in the
|
27
|
+
# extras array. The types are as follows
|
28
|
+
#
|
29
|
+
# :yaml - the second element is treated as a file name, which is loaded
|
30
|
+
# as a yaml file. The yaml file should contain a top level
|
31
|
+
# dictionary. Each of the keys of the top level dictionary is
|
32
|
+
# used as a local variable in the evalation context.
|
33
|
+
#
|
34
|
+
# :json - the second element is treated as a file name, which is loaded
|
35
|
+
# as a json file. The yaml file should contain a top level
|
36
|
+
# dictionary. Each of the keys of the top level dictionary is
|
37
|
+
# used as a local variable in the evalation context.
|
38
|
+
#
|
39
|
+
# :ruby - the second element is treated as a file name which is evaluated
|
40
|
+
# as a ruby file. Any assigments (or other binding affecting
|
41
|
+
# side effects) will persist into the context where the template
|
42
|
+
# is evaluated
|
43
|
+
#
|
44
|
+
# :raw - the seccond elements is treated as a ruby statement and is
|
45
|
+
# evaluated in the binding context, similar to the contents of
|
46
|
+
# a ruby file.
|
47
|
+
#
|
48
|
+
# Note that the order is important, as later extra sections can overwrite
|
49
|
+
# or even undo things that were done by earlier sections.
|
50
|
+
|
51
|
+
b = binding
|
52
|
+
extras.each do |pair|
|
53
|
+
type,file = pair
|
54
|
+
case type
|
55
|
+
when :yaml
|
56
|
+
logstream.puts("Loading YAML file #{file}") if logstream
|
57
|
+
parameters = YAML.load(File.read(file))
|
58
|
+
parameters.each do |k,v|
|
59
|
+
logstream.puts("Setting local variable #{k} to #{v}") if logstream
|
60
|
+
b.eval("#{k} = #{v.inspect}")
|
61
|
+
end
|
62
|
+
|
63
|
+
when :json
|
64
|
+
logstream.puts("Loading YAML file #{file}") if logstream
|
65
|
+
parameters = JSON.load(File.read(file))
|
66
|
+
parameters.each do |k,v|
|
67
|
+
logstream.puts("Setting local variable #{k} to #{v}") if logstream
|
68
|
+
b.eval("#{k} = #{v.inspect}")
|
69
|
+
end
|
70
|
+
|
71
|
+
when :ruby
|
72
|
+
logstream("Runnning ruby file #{file}") if logstream
|
73
|
+
b.eval(File.read(file), file)
|
74
|
+
|
75
|
+
when :raw
|
76
|
+
logstrame("Running raw ruby code #{file}") if logstream
|
77
|
+
b.eval(file, "raw code")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
logstream.puts("Loading template file #{filename}") if logstream
|
82
|
+
model = b.eval(File.read(filename), filename)
|
83
|
+
return model
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
18
87
|
def CloudFormation(&block)
|
19
88
|
x = CfnDsl::CloudFormationTemplate.new
|
20
89
|
x.declare(&block)
|
@@ -28,3 +97,16 @@ def CloudFormation(&block)
|
|
28
97
|
end
|
29
98
|
end
|
30
99
|
|
100
|
+
def Heat(&block)
|
101
|
+
x = CfnDsl::HeatTemplate.new
|
102
|
+
x.declare(&block)
|
103
|
+
invalid_references = x.checkRefs()
|
104
|
+
if( invalid_references ) then
|
105
|
+
abort invalid_references.join("\n")
|
106
|
+
elsif( CfnDsl::Errors.errors? ) then
|
107
|
+
abort CfnDsl::Errors.errors.join("\n")
|
108
|
+
else
|
109
|
+
return x
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
@@ -2,7 +2,7 @@ require 'cfndsl/JSONable'
|
|
2
2
|
require 'cfndsl/names'
|
3
3
|
|
4
4
|
module CfnDsl
|
5
|
-
class
|
5
|
+
class OrchestrationTemplate < JSONable
|
6
6
|
##
|
7
7
|
# Handles the overall template object
|
8
8
|
dsl_attr_setter :AWSTemplateFormatVersion, :Description
|
@@ -62,18 +62,26 @@ module CfnDsl
|
|
62
62
|
end
|
63
63
|
return invalids.length>0 ? invalids : nil
|
64
64
|
end
|
65
|
+
end
|
65
66
|
|
67
|
+
class CloudFormationTemplate < OrchestrationTemplate
|
68
|
+
def self.template_types
|
69
|
+
CfnDsl::AWSTypes::AWS_Types
|
70
|
+
end
|
71
|
+
def self.type_module
|
72
|
+
CfnDsl::AWSTypes
|
73
|
+
end
|
66
74
|
|
67
75
|
names = {}
|
68
76
|
nametypes = {}
|
69
|
-
|
77
|
+
self.template_types["Resources"].each_pair do |name, type|
|
70
78
|
# Subclass ResourceDefintion and generate property methods
|
71
79
|
klass = Class.new(CfnDsl::ResourceDefinition)
|
72
80
|
klassname = name.split("::").join("_")
|
73
|
-
|
81
|
+
type_module.const_set( klassname, klass )
|
74
82
|
type["Properties"].each_pair do |pname, ptype|
|
75
83
|
if( ptype.instance_of? String )
|
76
|
-
create_klass =
|
84
|
+
create_klass = type_module.const_get( ptype );
|
77
85
|
|
78
86
|
klass.class_eval do
|
79
87
|
CfnDsl::methodNames(pname) do |method|
|
@@ -91,7 +99,7 @@ module CfnDsl
|
|
91
99
|
else
|
92
100
|
#Array version
|
93
101
|
sing_name = CfnDsl::Plurals.singularize( pname )
|
94
|
-
create_klass =
|
102
|
+
create_klass = type_module.const_get( ptype[0] )
|
95
103
|
klass.class_eval do
|
96
104
|
CfnDsl::methodNames(pname) do |method|
|
97
105
|
define_method(method) do |*values, &block|
|
@@ -128,7 +136,7 @@ module CfnDsl
|
|
128
136
|
# this only happens if there is an ambiguity
|
129
137
|
names[abreve_name] = nil
|
130
138
|
else
|
131
|
-
names[abreve_name] =
|
139
|
+
names[abreve_name] = self.type_module.const_get(klassname)
|
132
140
|
nametypes[abreve_name] = name
|
133
141
|
end
|
134
142
|
parts.shift
|
@@ -154,5 +162,106 @@ module CfnDsl
|
|
154
162
|
end
|
155
163
|
end
|
156
164
|
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
class HeatTemplate < OrchestrationTemplate
|
170
|
+
def self.template_types
|
171
|
+
CfnDsl::OSTypes::OS_Types
|
172
|
+
end
|
173
|
+
def self.type_module
|
174
|
+
CfnDsl::OSTypes
|
175
|
+
end
|
176
|
+
|
177
|
+
names = {}
|
178
|
+
nametypes = {}
|
179
|
+
self.template_types["Resources"].each_pair do |name, type|
|
180
|
+
# Subclass ResourceDefintion and generate property methods
|
181
|
+
klass = Class.new(CfnDsl::ResourceDefinition)
|
182
|
+
klassname = name.split("::").join("_")
|
183
|
+
type_module.const_set( klassname, klass )
|
184
|
+
type["Properties"].each_pair do |pname, ptype|
|
185
|
+
if( ptype.instance_of? String )
|
186
|
+
create_klass = type_module.const_get( ptype );
|
187
|
+
|
188
|
+
klass.class_eval do
|
189
|
+
CfnDsl::methodNames(pname) do |method|
|
190
|
+
define_method(method) do |*values, &block|
|
191
|
+
if( values.length <1 ) then
|
192
|
+
values.push create_klass.new
|
193
|
+
end
|
194
|
+
@Properties ||= {}
|
195
|
+
@Properties[pname] ||= CfnDsl::PropertyDefinition.new( *values )
|
196
|
+
@Properties[pname].value.instance_eval &block if block
|
197
|
+
@Properties[pname].value
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
else
|
202
|
+
#Array version
|
203
|
+
sing_name = CfnDsl::Plurals.singularize( pname )
|
204
|
+
create_klass = type_module.const_get( ptype[0] )
|
205
|
+
klass.class_eval do
|
206
|
+
CfnDsl::methodNames(pname) do |method|
|
207
|
+
define_method(method) do |*values, &block|
|
208
|
+
if( values.length < 1 ) then
|
209
|
+
values.push []
|
210
|
+
end
|
211
|
+
@Properties ||= {}
|
212
|
+
@Properties[pname] ||= PropertyDefinition.new( *values )
|
213
|
+
@Properties[pname].value.instance_eval &block if block
|
214
|
+
@Properties[pname].value
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
CfnDsl::methodNames(sing_name) do |method|
|
219
|
+
define_method(method) do |value=nil, &block|
|
220
|
+
@Properties ||= {}
|
221
|
+
@Properties[pname] ||= PropertyDefinition.new( [] )
|
222
|
+
if( !value ) then
|
223
|
+
value = create_klass.new
|
224
|
+
end
|
225
|
+
@Properties[pname].value.push value
|
226
|
+
value.instance_eval &block if block
|
227
|
+
value
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
parts = name.split "::"
|
235
|
+
while( parts.length > 0)
|
236
|
+
abreve_name = parts.join "_"
|
237
|
+
if( names.has_key? abreve_name ) then
|
238
|
+
# this only happens if there is an ambiguity
|
239
|
+
names[abreve_name] = nil
|
240
|
+
else
|
241
|
+
names[abreve_name] = self.type_module.const_get(klassname)
|
242
|
+
nametypes[abreve_name] = name
|
243
|
+
end
|
244
|
+
parts.shift
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
#Define property setter methods for each of the unambiguous type names
|
249
|
+
names.each_pair do |typename,type|
|
250
|
+
if(type) then
|
251
|
+
class_eval do
|
252
|
+
CfnDsl::methodNames(typename) do |method|
|
253
|
+
define_method(method) do |name,*values,&block|
|
254
|
+
name = name.to_s
|
255
|
+
@Resources ||= {}
|
256
|
+
resource = @Resources[name] ||= type.new(*values)
|
257
|
+
resource.instance_eval &block if block
|
258
|
+
resource.instance_variable_set( "@Type", nametypes[typename] )
|
259
|
+
resource
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
157
265
|
end
|
266
|
+
|
158
267
|
end
|
data/lib/cfndsl/Types.rb
CHANGED
@@ -4,15 +4,15 @@ require 'cfndsl/Plurals'
|
|
4
4
|
require 'cfndsl/names'
|
5
5
|
|
6
6
|
module CfnDsl
|
7
|
-
module
|
8
|
-
|
7
|
+
module AWSTypes
|
9
8
|
aws_types = YAML::load( File.open( "#{File.dirname(__FILE__)}/aws_types.yaml") );
|
10
|
-
|
11
|
-
|
9
|
+
AWSTypes.const_set( "AWS_Types", aws_types);
|
10
|
+
|
12
11
|
# Do a little sanity checking - all of the types referenced in Resources
|
13
12
|
# should be represented in Types
|
14
13
|
aws_types["Resources"].keys.each do |resource_name|
|
15
14
|
#puts resource_name
|
15
|
+
|
16
16
|
resource = aws_types["Resources"][resource_name]
|
17
17
|
resource.values.each do |thing|
|
18
18
|
thing.values.each do |type|
|
@@ -36,9 +36,7 @@ module CfnDsl
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
|
42
40
|
# declare classes for all of the types with named methods for setting the values
|
43
41
|
class AWSType < JSONable
|
44
42
|
end
|
@@ -47,11 +45,11 @@ module CfnDsl
|
|
47
45
|
|
48
46
|
# Go through and declare all of the types first
|
49
47
|
aws_types["Types"].each_key do |typename|
|
50
|
-
if( !
|
51
|
-
klass =
|
48
|
+
if( ! AWSTypes.const_defined? typename ) then
|
49
|
+
klass = AWSTypes.const_set( typename, Class.new(AWSType ) )
|
52
50
|
classes[typename] = klass
|
53
51
|
else
|
54
|
-
classes[typename] =
|
52
|
+
classes[typename] = AWSTypes.const_get(typename)
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
@@ -62,7 +60,157 @@ module CfnDsl
|
|
62
60
|
if( typeval.respond_to? :each_pair ) then
|
63
61
|
typeval.each_pair do |attr_name, attr_type|
|
64
62
|
if( attr_type.kind_of? Array ) then
|
65
|
-
klass = CfnDsl::
|
63
|
+
klass = CfnDsl::AWSTypes.const_get( attr_type[0] )
|
64
|
+
variable = "@#{attr_name}".to_sym
|
65
|
+
|
66
|
+
method = CfnDsl::Plurals::singularize(attr_name)
|
67
|
+
methods = attr_name
|
68
|
+
all_methods = CfnDsl::methodNames(method) +
|
69
|
+
CfnDsl::methodNames(methods)
|
70
|
+
type.class_eval do
|
71
|
+
all_methods.each do |method_name|
|
72
|
+
define_method(method_name) do | value=nil, *rest, &block|
|
73
|
+
existing = instance_variable_get( variable )
|
74
|
+
# For no-op invocations, get out now
|
75
|
+
return existing if value.nil? and rest.length == 0 and ! block
|
76
|
+
|
77
|
+
# We are going to modify the value in some
|
78
|
+
# way, make sure that we have an array to mess
|
79
|
+
# with if we start with nothing
|
80
|
+
if( !existing ) then
|
81
|
+
existing = instance_variable_set( variable, [] )
|
82
|
+
end
|
83
|
+
|
84
|
+
# special case for just a block, no args
|
85
|
+
if( value.nil? and rest.length == 0 and block ) then
|
86
|
+
val = klass.new
|
87
|
+
existing.push val
|
88
|
+
value.instance_eval &block(val)
|
89
|
+
return existin
|
90
|
+
end
|
91
|
+
|
92
|
+
# Glue all of our parameters together into
|
93
|
+
# a giant array - flattening one level deep, if needed
|
94
|
+
array_params = []
|
95
|
+
if( value.kind_of? Array) then
|
96
|
+
value.each {|x| array_params.push x}
|
97
|
+
else
|
98
|
+
array_params.push value
|
99
|
+
end
|
100
|
+
if( rest.length > 0) then
|
101
|
+
rest.each do |v|
|
102
|
+
if( v.kind_of? Array ) then
|
103
|
+
array_params += rest
|
104
|
+
else
|
105
|
+
array_params.push v
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Here, if we were given multiple arguments either
|
111
|
+
# as method [a,b,c], method(a,b,c), or even
|
112
|
+
# method( a, [b], c) we end up with
|
113
|
+
# array_params = [a,b,c]
|
114
|
+
#
|
115
|
+
# array_params will have at least one item
|
116
|
+
# unless the user did something like pass in
|
117
|
+
# a bunch of empty arrays.
|
118
|
+
if block then
|
119
|
+
array_params.each do |val|
|
120
|
+
value = klass.new
|
121
|
+
existing.push value
|
122
|
+
value.instance_eval &block(val) if block
|
123
|
+
end
|
124
|
+
else
|
125
|
+
# List of parameters with no block -
|
126
|
+
# hope that the user knows what he is
|
127
|
+
# doing and stuff them into our existing
|
128
|
+
# array
|
129
|
+
array_params.each do |val|
|
130
|
+
existing.push value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
return existing
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
else
|
138
|
+
klass = CfnDsl::AWSTypes.const_get( attr_type );
|
139
|
+
variable = "@#{attr_name}".to_sym
|
140
|
+
|
141
|
+
type.class_eval do
|
142
|
+
CfnDsl::methodNames(attr_name) do |method|
|
143
|
+
define_method(method) do | value=nil, *rest, &block |
|
144
|
+
value ||= klass.new
|
145
|
+
instance_variable_set( variable, value )
|
146
|
+
value.instance_eval &block if block
|
147
|
+
value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
module OSTypes
|
158
|
+
os_types = YAML::load( File.open( "#{File.dirname(__FILE__)}/os_types.yaml") );
|
159
|
+
OSTypes.const_set( "OS_Types", os_types);
|
160
|
+
|
161
|
+
# Do a little sanity checking - all of the types referenced in Resources
|
162
|
+
# should be represented in Types
|
163
|
+
os_types["Resources"].keys.each do |resource_name|
|
164
|
+
#puts resource_name
|
165
|
+
|
166
|
+
resource = os_types["Resources"][resource_name]
|
167
|
+
resource.values.each do |thing|
|
168
|
+
thing.values.each do |type|
|
169
|
+
if( type.kind_of? Array ) then
|
170
|
+
type.each do | type |
|
171
|
+
puts "unknown type #{type}" unless os_types["Types"].has_key? type
|
172
|
+
end
|
173
|
+
else
|
174
|
+
puts "unknown type #{type}" unless os_types["Types"].has_key? type
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# All of the type values should also be references
|
181
|
+
|
182
|
+
os_types["Types"].values do |type|
|
183
|
+
if( type.respond_to? :values) then
|
184
|
+
type.values.each do |tv|
|
185
|
+
puts "unknown type #{tv}" unless os_types["Types"].has_key? tv
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# declare classes for all of the types with named methods for setting the values
|
191
|
+
class OSType < JSONable
|
192
|
+
end
|
193
|
+
|
194
|
+
classes = {}
|
195
|
+
|
196
|
+
# Go through and declare all of the types first
|
197
|
+
os_types["Types"].each_key do |typename|
|
198
|
+
if( ! OSTypes.const_defined? typename ) then
|
199
|
+
klass = OSTypes.const_set( typename, Class.new(OSType ) )
|
200
|
+
classes[typename] = klass
|
201
|
+
else
|
202
|
+
classes[typename] = OSTypes.const_get(typename)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Now go through them again and define attribute setter methods
|
207
|
+
classes.each_pair do |typename,type|
|
208
|
+
#puts typename
|
209
|
+
typeval = os_types["Types"][typename]
|
210
|
+
if( typeval.respond_to? :each_pair ) then
|
211
|
+
typeval.each_pair do |attr_name, attr_type|
|
212
|
+
if( attr_type.kind_of? Array ) then
|
213
|
+
klass = CfnDsl::OSTypes.const_get( attr_type[0] )
|
66
214
|
variable = "@#{attr_name}".to_sym
|
67
215
|
|
68
216
|
method = CfnDsl::Plurals::singularize(attr_name)
|
@@ -137,7 +285,7 @@ module CfnDsl
|
|
137
285
|
end
|
138
286
|
end
|
139
287
|
else
|
140
|
-
klass = CfnDsl::
|
288
|
+
klass = CfnDsl::OSTypes.const_get( attr_type );
|
141
289
|
variable = "@#{attr_name}".to_sym
|
142
290
|
|
143
291
|
type.class_eval do
|
@@ -155,5 +303,7 @@ module CfnDsl
|
|
155
303
|
end
|
156
304
|
end
|
157
305
|
end
|
306
|
+
|
307
|
+
|
158
308
|
end
|
159
309
|
|