sparkle_formation 1.1.14 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -22
- data/lib/sparkle_formation/aws.rb +2 -101
- data/lib/sparkle_formation/error.rb +2 -0
- data/lib/sparkle_formation/resources/aws.rb +40 -0
- data/lib/sparkle_formation/resources/aws_resources.json +5801 -0
- data/lib/sparkle_formation/resources.rb +114 -0
- data/lib/sparkle_formation/sparkle.rb +40 -45
- data/lib/sparkle_formation/sparkle_attribute/aws.rb +314 -0
- data/lib/sparkle_formation/sparkle_attribute.rb +44 -295
- data/lib/sparkle_formation/sparkle_formation.rb +68 -22
- data/lib/sparkle_formation/sparkle_struct.rb +9 -1
- data/lib/sparkle_formation/translation/heat.rb +7 -6
- data/lib/sparkle_formation/translation/rackspace.rb +9 -7
- data/lib/sparkle_formation/translation.rb +8 -7
- data/lib/sparkle_formation/utils.rb +42 -2
- data/lib/sparkle_formation/version.rb +2 -1
- data/lib/sparkle_formation.rb +2 -0
- data/sparkle_formation.gemspec +2 -1
- metadata +22 -5
- data/lib/sparkle_formation/aws/cfn_resources.rb +0 -4609
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'sparkle_formation'
|
2
|
+
|
3
|
+
class SparkleFormation
|
4
|
+
# Resources helper
|
5
|
+
class Resources
|
6
|
+
|
7
|
+
autoload :Aws, 'sparkle_formation/resources/aws'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
include SparkleFormation::Utils::AnimalStrings
|
12
|
+
# @!parse include SparkleFormation::Utils::AnimalStrings
|
13
|
+
|
14
|
+
# Register resource
|
15
|
+
#
|
16
|
+
# @param type [String] Orchestration resource type
|
17
|
+
# @param hash [Hash] metadata information
|
18
|
+
# @return [TrueClass]
|
19
|
+
def register(type, hash)
|
20
|
+
unless(class_variable_defined?(:@@registry))
|
21
|
+
@@registry = AttributeStruct.hashish.new
|
22
|
+
end
|
23
|
+
@@registry[type] = hash
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Resource information
|
28
|
+
#
|
29
|
+
# @param identifier [String, Symbol] resource identifier
|
30
|
+
# @param key [String, Symbol] specific data
|
31
|
+
# @return [Hashish]
|
32
|
+
def resource(identifier, key=nil)
|
33
|
+
res = lookup(identifier)
|
34
|
+
if(key && res)
|
35
|
+
res[key.to_sym]
|
36
|
+
else
|
37
|
+
res
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Register all discovered resources
|
42
|
+
#
|
43
|
+
# @param json_path_or_hash [String, Hashish] path to files or hash
|
44
|
+
# @return [TrueClass]
|
45
|
+
def load(json_path_or_hash)
|
46
|
+
if(json_path_or_hash.is_a?(String))
|
47
|
+
content = AttributeStruct.hashish.new(MultiJson.load(File.read(json_path_or_hash)))
|
48
|
+
else
|
49
|
+
content = json_path_or_hash
|
50
|
+
end
|
51
|
+
content.each do |type, hash|
|
52
|
+
register(type, hash)
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
# Load the builtin AWS resources
|
58
|
+
#
|
59
|
+
# @return [TrueClass]
|
60
|
+
def load!
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
# Discover registry key via part searching
|
65
|
+
#
|
66
|
+
# @param key [String, Symbol]
|
67
|
+
# @return [String, NilClass]
|
68
|
+
def registry_key(key)
|
69
|
+
o_key = key
|
70
|
+
key = key.to_s.tr('_', '')
|
71
|
+
snake_parts = nil
|
72
|
+
result = @@registry.keys.detect do |ref|
|
73
|
+
ref = ref.downcase
|
74
|
+
snake_parts = ref.split('::')
|
75
|
+
until(snake_parts.empty?)
|
76
|
+
break if snake_parts.join('') == key
|
77
|
+
snake_parts.shift
|
78
|
+
end
|
79
|
+
!snake_parts.empty?
|
80
|
+
end
|
81
|
+
if(result)
|
82
|
+
collisions = @@registry.keys.find_all do |ref|
|
83
|
+
split_ref = ref.downcase.split('::')
|
84
|
+
ref = split_ref.slice(split_ref.size - snake_parts.size, split_ref.size).join('')
|
85
|
+
key == ref
|
86
|
+
end
|
87
|
+
if(collisions.size > 1)
|
88
|
+
raise ArgumentError.new 'Ambiguous dynamic name returned multiple matches! ' \
|
89
|
+
"`#{o_key.inspect}` -> #{collisions.sort.join(', ')}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
result
|
93
|
+
end
|
94
|
+
|
95
|
+
# Registry information for given type
|
96
|
+
#
|
97
|
+
# @param key [String, Symbol]
|
98
|
+
# @return [Hashish, NilClass]
|
99
|
+
def lookup(key)
|
100
|
+
@@registry[registry_key(key)]
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [Hashish] currently loaded AWS registry
|
104
|
+
def registry
|
105
|
+
if(class_variable_defined?(:@@registry))
|
106
|
+
@@registry
|
107
|
+
else
|
108
|
+
@@registry = AttributeStruct.hashish.new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'sparkle_formation'
|
2
2
|
|
3
|
+
# Unicorns and rainbows
|
3
4
|
class SparkleFormation
|
5
|
+
# Independent collection of SparkleFormation items
|
4
6
|
class Sparkle
|
5
7
|
|
6
8
|
class << self
|
@@ -17,16 +19,15 @@ class SparkleFormation
|
|
17
19
|
idx = caller.index do |item|
|
18
20
|
item.end_with?("`register!'")
|
19
21
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
22
|
+
idx = idx ? idx.next : 0
|
23
|
+
file = caller[idx].split(':', 2).first
|
24
|
+
path = File.join(File.dirname(file), 'sparkleformation')
|
25
|
+
unless(File.directory?(path))
|
26
|
+
path = nil
|
27
|
+
end
|
28
|
+
unless(name)
|
29
|
+
name = File.basename(caller[idx].split(':', 2).first)
|
30
|
+
name.sub!(File.extname(name), '')
|
30
31
|
end
|
31
32
|
end
|
32
33
|
unless(name)
|
@@ -61,6 +62,7 @@ class SparkleFormation
|
|
61
62
|
|
62
63
|
# Wrapper for evaluating sfn files to store within sparkle
|
63
64
|
# container and remove global application
|
65
|
+
# rubocop:disable Metrics/MethodLength
|
64
66
|
def eval_wrapper
|
65
67
|
klass = Class.new(BasicObject)
|
66
68
|
klass.class_eval(<<-EOS
|
@@ -214,7 +216,8 @@ class SparkleFormation
|
|
214
216
|
@raw_data = Smash.new(
|
215
217
|
:dynamic => [],
|
216
218
|
:component => [],
|
217
|
-
:registry => []
|
219
|
+
:registry => [],
|
220
|
+
:template => []
|
218
221
|
)
|
219
222
|
@wrapper = eval_wrapper.new
|
220
223
|
wrapper.part_data(raw_data)
|
@@ -245,35 +248,7 @@ class SparkleFormation
|
|
245
248
|
# @return [Smash<name:path>]
|
246
249
|
def templates
|
247
250
|
memoize(:templates) do
|
248
|
-
Smash.new
|
249
|
-
Dir.glob(File.join(root, '**', '**', '*.{json,rb}')) do |path|
|
250
|
-
slim_path = path.sub("#{root}/", '')
|
251
|
-
next if DIRS.include?(slim_path.split('/').first)
|
252
|
-
data = Smash.new(:template => [])
|
253
|
-
t_wrap = eval_wrapper.new
|
254
|
-
t_wrap.part_data(data)
|
255
|
-
if(slim_path.end_with?('.rb'))
|
256
|
-
begin
|
257
|
-
t_wrap.instance_eval(IO.read(path), path, 1)
|
258
|
-
rescue TypeError
|
259
|
-
end
|
260
|
-
end
|
261
|
-
data = data[:template].first || Smash.new
|
262
|
-
unless(data[:name])
|
263
|
-
data[:name] = slim_path.tr('/', '__').sub(/\.(rb|json)$/, '')
|
264
|
-
end
|
265
|
-
if(hash[data[:name]])
|
266
|
-
raise KeyError.new "Template name is already in use within pack! (`#{data[:name]}`)"
|
267
|
-
end
|
268
|
-
hash[data[:name]] = data.merge(
|
269
|
-
Smash.new(
|
270
|
-
:type => :template,
|
271
|
-
:path => path,
|
272
|
-
:serialized => !path.end_with?('.rb')
|
273
|
-
)
|
274
|
-
)
|
275
|
-
end
|
276
|
-
end
|
251
|
+
Smash.new
|
277
252
|
end
|
278
253
|
end
|
279
254
|
|
@@ -290,9 +265,9 @@ class SparkleFormation
|
|
290
265
|
result = send(TYPES[type])[name]
|
291
266
|
if(result.nil? && TYPES[type] == 'templates')
|
292
267
|
result = (
|
293
|
-
send(TYPES[type]).detect{|
|
268
|
+
send(TYPES[type]).detect{|_, v|
|
294
269
|
name = name.to_s
|
295
|
-
short_name = v[:path].sub(
|
270
|
+
short_name = v[:path].sub(%r{#{Regexp.escape(root)}/?}, '')
|
296
271
|
v[:path] == name ||
|
297
272
|
short_name == name ||
|
298
273
|
short_name.sub('.rb', '').gsub(File::SEPARATOR, '__').tr('-', '_') == name ||
|
@@ -323,7 +298,7 @@ class SparkleFormation
|
|
323
298
|
def locate_root
|
324
299
|
VALID_ROOT_DIRS.map do |part|
|
325
300
|
path = File.expand_path(File.join(Dir.pwd, part))
|
326
|
-
if(File.
|
301
|
+
if(File.exist?(path))
|
327
302
|
path
|
328
303
|
end
|
329
304
|
end.compact.first
|
@@ -332,8 +307,28 @@ class SparkleFormation
|
|
332
307
|
# Load all sparkle parts
|
333
308
|
def load_parts!
|
334
309
|
memoize(:load_parts) do
|
335
|
-
Dir.glob(File.join(root,
|
336
|
-
|
310
|
+
Dir.glob(File.join(root, '**', '**', '*.{json,rb}')).each do |file|
|
311
|
+
slim_path = file.sub("#{root}/", '')
|
312
|
+
if(file.end_with?('.rb'))
|
313
|
+
begin
|
314
|
+
wrapper.instance_eval(IO.read(file), file, 1)
|
315
|
+
rescue TypeError
|
316
|
+
end
|
317
|
+
end
|
318
|
+
if(file.end_with?('.json') || raw_data[:template].first)
|
319
|
+
data = raw_data[:template].pop || Smash.new
|
320
|
+
unless(data[:name])
|
321
|
+
data[:name] = slim_path.tr('/', '__').sub(/\.(rb|json)$/, '')
|
322
|
+
end
|
323
|
+
if(templates[data[:name]])
|
324
|
+
raise KeyError.new "Template name is already in use within pack! (`#{data[:name]}`)"
|
325
|
+
end
|
326
|
+
templates[data[:name]] = data.merge(
|
327
|
+
:type => :template,
|
328
|
+
:path => file,
|
329
|
+
:serialized => !file.end_with?('.rb')
|
330
|
+
)
|
331
|
+
end
|
337
332
|
end
|
338
333
|
raw_data.each do |key, items|
|
339
334
|
items.each do |item|
|
@@ -0,0 +1,314 @@
|
|
1
|
+
require 'sparkle_formation'
|
2
|
+
|
3
|
+
class SparkleFormation
|
4
|
+
|
5
|
+
# Provides template helper methods
|
6
|
+
module SparkleAttribute
|
7
|
+
|
8
|
+
# AWS specific helper implementations
|
9
|
+
module Aws
|
10
|
+
|
11
|
+
# Fn::Join generator
|
12
|
+
#
|
13
|
+
# @param args [Object]
|
14
|
+
# @return [Hash]
|
15
|
+
def _cf_join(*args)
|
16
|
+
options = args.detect{|i| i.is_a?(Hash) && i[:options]} || {:options => {}}
|
17
|
+
args.delete(options)
|
18
|
+
unless(args.size == 1)
|
19
|
+
args = [args]
|
20
|
+
end
|
21
|
+
{'Fn::Join' => [options[:options][:delimiter] || '', *args]}
|
22
|
+
end
|
23
|
+
alias_method :join!, :_cf_join
|
24
|
+
|
25
|
+
# Ref generator
|
26
|
+
#
|
27
|
+
# @param thing [String, Symbol] reference name
|
28
|
+
# @return [Hash]
|
29
|
+
# @note Symbol value will force key processing
|
30
|
+
def _cf_ref(thing)
|
31
|
+
__t_stringish(thing)
|
32
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
33
|
+
{'Ref' => thing}
|
34
|
+
end
|
35
|
+
alias_method :_ref, :_cf_ref
|
36
|
+
alias_method :ref!, :_cf_ref
|
37
|
+
|
38
|
+
# Fn::FindInMap generator
|
39
|
+
#
|
40
|
+
# @param thing [String, Symbol] thing to find
|
41
|
+
# @param key [String, Symbol] thing to search
|
42
|
+
# @param suffix [Object] additional args
|
43
|
+
# @return [Hash]
|
44
|
+
def _cf_map(thing, key, *suffix)
|
45
|
+
__t_stringish(thing)
|
46
|
+
suffix = suffix.map do |item|
|
47
|
+
if(item.is_a?(Symbol))
|
48
|
+
_process_key(item, :force)
|
49
|
+
else
|
50
|
+
item
|
51
|
+
end
|
52
|
+
end
|
53
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
54
|
+
if(key.is_a?(Symbol))
|
55
|
+
key = ref!(key)
|
56
|
+
end
|
57
|
+
{'Fn::FindInMap' => [thing, key, *suffix]}
|
58
|
+
end
|
59
|
+
alias_method :_cf_find_in_map, :_cf_map
|
60
|
+
alias_method :find_in_map!, :_cf_map
|
61
|
+
alias_method :map!, :_cf_map
|
62
|
+
|
63
|
+
# Fn::GetAtt generator
|
64
|
+
#
|
65
|
+
# @param [Object] pass through arguments
|
66
|
+
# @return [Hash]
|
67
|
+
def _cf_attr(*args)
|
68
|
+
__t_stringish(args.first)
|
69
|
+
args = args.map do |thing|
|
70
|
+
if(thing.is_a?(Symbol))
|
71
|
+
_process_key(thing, :force)
|
72
|
+
else
|
73
|
+
thing
|
74
|
+
end
|
75
|
+
end
|
76
|
+
{'Fn::GetAtt' => args}
|
77
|
+
end
|
78
|
+
alias_method :_cf_get_att, :_cf_attr
|
79
|
+
alias_method :get_att!, :_cf_attr
|
80
|
+
alias_method :attr!, :_cf_attr
|
81
|
+
|
82
|
+
# Fn::Base64 generator
|
83
|
+
#
|
84
|
+
# @param arg [Object] pass through
|
85
|
+
# @return [Hash]
|
86
|
+
def _cf_base64(arg)
|
87
|
+
{'Fn::Base64' => arg}
|
88
|
+
end
|
89
|
+
alias_method :base64!, :_cf_base64
|
90
|
+
|
91
|
+
# Fn::GetAZs generator
|
92
|
+
#
|
93
|
+
# @param region [String, Symbol] String will pass through. Symbol will be converted to ref
|
94
|
+
# @return [Hash]
|
95
|
+
def _cf_get_azs(region=nil)
|
96
|
+
region = case region
|
97
|
+
when Symbol
|
98
|
+
_cf_ref(region)
|
99
|
+
when NilClass
|
100
|
+
''
|
101
|
+
else
|
102
|
+
region
|
103
|
+
end
|
104
|
+
{'Fn::GetAZs' => region}
|
105
|
+
end
|
106
|
+
alias_method :get_azs!, :_cf_get_azs
|
107
|
+
alias_method :azs!, :_cf_get_azs
|
108
|
+
|
109
|
+
# Fn::Select generator
|
110
|
+
#
|
111
|
+
# @param index [String, Symbol, Integer] Symbol will be converted to ref
|
112
|
+
# @param item [Object, Symbol] Symbol will be converted to ref
|
113
|
+
# @return [Hash]
|
114
|
+
def _cf_select(index, item)
|
115
|
+
index = index.is_a?(Symbol) ? _cf_ref(index) : index
|
116
|
+
item = _cf_ref(item) if item.is_a?(Symbol)
|
117
|
+
{'Fn::Select' => [index, item]}
|
118
|
+
end
|
119
|
+
alias_method :select!, :_cf_select
|
120
|
+
|
121
|
+
# Condition generator
|
122
|
+
#
|
123
|
+
# @param name [String, Symbol] symbol will be processed
|
124
|
+
# @return [Hash]
|
125
|
+
def _condition(name)
|
126
|
+
__t_stringish(name)
|
127
|
+
{'Condition' => name.is_a?(Symbol) ? _process_key(name, :force) : name}
|
128
|
+
end
|
129
|
+
alias_method :condition!, :_condition
|
130
|
+
|
131
|
+
# Condition setter
|
132
|
+
#
|
133
|
+
# @param name [String, Symbol] condition name
|
134
|
+
# @return [SparkleStruct]
|
135
|
+
# @note this is used to set a {"Condition" => "Name"} into the
|
136
|
+
# current context, generally the top level of a resource
|
137
|
+
def _on_condition(name)
|
138
|
+
_set(*_condition(name).to_a.flatten)
|
139
|
+
end
|
140
|
+
alias_method :on_condition!, :_on_condition
|
141
|
+
|
142
|
+
# Fn::If generator
|
143
|
+
#
|
144
|
+
# @param cond [String, Symbol] symbol will be case processed
|
145
|
+
# @param true_value [Object]
|
146
|
+
# @param false_value [Object]
|
147
|
+
# @return [Hash]
|
148
|
+
def _if(cond, true_value, false_value)
|
149
|
+
cond = cond.is_a?(Symbol) ? _process_key(cond) : cond
|
150
|
+
{'Fn::If' => _array(cond, true_value, false_value)}
|
151
|
+
end
|
152
|
+
alias_method :if!, :_if
|
153
|
+
|
154
|
+
# Fn::And generator
|
155
|
+
#
|
156
|
+
# @param args [Object]
|
157
|
+
# @return [Hash]
|
158
|
+
# @note symbols will be processed and set as condition. strings
|
159
|
+
# will be set as condition directly. procs will be evaluated
|
160
|
+
def _and(*args)
|
161
|
+
{
|
162
|
+
'Fn::And' => _array(
|
163
|
+
*args.map{|v|
|
164
|
+
if(v.is_a?(Symbol) || v.is_a?(String))
|
165
|
+
_condition(v)
|
166
|
+
else
|
167
|
+
v
|
168
|
+
end
|
169
|
+
}
|
170
|
+
)
|
171
|
+
}
|
172
|
+
end
|
173
|
+
alias_method :and!, :_and
|
174
|
+
|
175
|
+
# Fn::Equals generator
|
176
|
+
#
|
177
|
+
# @param v1 [Object]
|
178
|
+
# @param v2 [Object]
|
179
|
+
# @return [Hash]
|
180
|
+
def _equals(v1, v2)
|
181
|
+
{'Fn::Equals' => _array(v1, v2)}
|
182
|
+
end
|
183
|
+
alias_method :equals!, :_equals
|
184
|
+
|
185
|
+
# Fn::Not generator
|
186
|
+
#
|
187
|
+
# @param arg [Object]
|
188
|
+
# @return [Hash]
|
189
|
+
def _not(arg)
|
190
|
+
if(arg.is_a?(String) || arg.is_a?(Symbol))
|
191
|
+
arg = _condition(arg)
|
192
|
+
else
|
193
|
+
arg = _array(arg).first
|
194
|
+
end
|
195
|
+
{'Fn::Not' => [arg]}
|
196
|
+
end
|
197
|
+
alias_method :not!, :_not
|
198
|
+
|
199
|
+
# Fn::Or generator
|
200
|
+
#
|
201
|
+
# @param v1 [Object]
|
202
|
+
# @param v2 [Object]
|
203
|
+
# @return [Hash]
|
204
|
+
def _or(*args)
|
205
|
+
{
|
206
|
+
'Fn::Or' => _array(
|
207
|
+
*args.map{|v|
|
208
|
+
if(v.is_a?(Symbol) || v.is_a?(String))
|
209
|
+
_condition(v)
|
210
|
+
else
|
211
|
+
v
|
212
|
+
end
|
213
|
+
}
|
214
|
+
)
|
215
|
+
}
|
216
|
+
end
|
217
|
+
alias_method :or!, :_or
|
218
|
+
|
219
|
+
# No value generator
|
220
|
+
#
|
221
|
+
# @return [String]
|
222
|
+
def _no_value
|
223
|
+
_ref('AWS::NoValue')
|
224
|
+
end
|
225
|
+
alias_method :no_value!, :_no_value
|
226
|
+
|
227
|
+
# Region generator
|
228
|
+
#
|
229
|
+
# @return [Hash]
|
230
|
+
def _region
|
231
|
+
_ref('AWS::Region')
|
232
|
+
end
|
233
|
+
alias_method :region!, :_region
|
234
|
+
|
235
|
+
# Notification ARNs generator
|
236
|
+
#
|
237
|
+
# @return [Hash]
|
238
|
+
def _notification_arns
|
239
|
+
_ref('AWS::NotificationARNs')
|
240
|
+
end
|
241
|
+
alias_method :notification_arns!, :_notification_arns
|
242
|
+
|
243
|
+
# Account ID generator
|
244
|
+
#
|
245
|
+
# @return [Hash]
|
246
|
+
def _account_id
|
247
|
+
_ref('AWS::AccountId')
|
248
|
+
end
|
249
|
+
alias_method :account_id!, :_account_id
|
250
|
+
|
251
|
+
# Stack ID generator
|
252
|
+
#
|
253
|
+
# @return [Hash]
|
254
|
+
def _stack_id
|
255
|
+
_ref('AWS::StackId')
|
256
|
+
end
|
257
|
+
alias_method :stack_id!, :_stack_id
|
258
|
+
|
259
|
+
# Stack name generator
|
260
|
+
#
|
261
|
+
# @return [Hash]
|
262
|
+
def _stack_name
|
263
|
+
_ref('AWS::StackName')
|
264
|
+
end
|
265
|
+
alias_method :stack_name!, :_stack_name
|
266
|
+
|
267
|
+
# Resource dependency generator
|
268
|
+
#
|
269
|
+
# @param [Symbol, String, Array<Symbol, String>] resource names
|
270
|
+
# @return [Array<String>]
|
271
|
+
def _depends_on(*args)
|
272
|
+
_set('DependsOn', [args].flatten.compact.map{|s| _process_key(s)})
|
273
|
+
end
|
274
|
+
alias_method :depends_on!, :_depends_on
|
275
|
+
|
276
|
+
# Reference output value from nested stack
|
277
|
+
#
|
278
|
+
# @param stack_name [String, Symbol] logical resource name of stack
|
279
|
+
# @apram output_name [String, Symbol] stack output name
|
280
|
+
def _stack_output(stack_name, output_name)
|
281
|
+
_cf_attr(_process_key(stack_name), "Outputs.#{_process_key(output_name)}")
|
282
|
+
end
|
283
|
+
alias_method :stack_output!, :_stack_output
|
284
|
+
|
285
|
+
# @return [TrueClass, FalseClass] resource can be tagged
|
286
|
+
def taggable?
|
287
|
+
if(self[:type])
|
288
|
+
resource = _self.lookup(self[:type].gsub('::', '_').downcase)
|
289
|
+
resource && resource[:properties].include?('Tags')
|
290
|
+
else
|
291
|
+
if(_parent)
|
292
|
+
_parent.taggable?
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Set tags on a resource
|
298
|
+
#
|
299
|
+
# @param hash [Hash] Key/value pair tags
|
300
|
+
# @return [SparkleStruct]
|
301
|
+
def _tags(hash)
|
302
|
+
_set('Tags',
|
303
|
+
hash.map{ |k, v|
|
304
|
+
key = k.is_a?(Symbol) ? _process_key(k, :force) : k
|
305
|
+
{'Key' => key, 'Value' => v}
|
306
|
+
}
|
307
|
+
)
|
308
|
+
end
|
309
|
+
alias_method :tags!, :_tags
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
end
|