cfn-model 0.4.31 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1af7ad2e0d6f1ccc44f948bbeed9ecac11264ce1aff4bf9ef824461810cbf65e
4
- data.tar.gz: 7d62f46f1cefd0f5f6347e5bfa25e10767250f81679eab502200262c82a6d8ef
3
+ metadata.gz: e4980780e48883af420ef019bce841105f1c4c33f96e090c491296a2b9f74199
4
+ data.tar.gz: 21a4292366a0363bec0a92113033f4f759399ca6e0c29063c0d6b5e17525ab90
5
5
  SHA512:
6
- metadata.gz: d714c8be48de3d60fa59a55948b407a8bed0875e7b8dc75bf872905caa38408858b8ebd51d57f603e90cc9b85148844e66cba7e44febb6118ff0a43370c2c4ff
7
- data.tar.gz: d32238875efa9fb50d60f0d64ffce415117fb749145e80fcfa43dd11cf7eca2a4462a5fb82b1aea6527c14587baf58029e159e33d19a1b51aeb6bd202861ecbc
6
+ metadata.gz: bc7e5193fd227a66df09aa86e8810fb019313e32e48834cee1a22931493887b4f8351370017a410058ffb2c149c91adafdc167757eff59904bd957846da2ebf9
7
+ data.tar.gz: 312c9e00357b034832815b4d0b8148a00a33293de6b4055548b877305e0b9319e41a15a3f928470d02a48eb3c9c7af499f7984d834bf7ba4058779a7aedcab41
@@ -9,6 +9,10 @@ require 'cfn-model/parser/parser_error'
9
9
  # references yet... in the meantime pile things up here and hope a pattern becomes
10
10
  # clear
11
11
  module References
12
+ def self.unsupported_passthru?(value)
13
+ value.has_key?('Fn::GetAtt') || value.has_key?('Fn::ImportValue') || value.has_key?('Fn::Transform') || value.has_key?('Fn::Cidr')
14
+ end
15
+
12
16
  def self.resolve_value(cfn_model, value)
13
17
  if value.is_a? Hash
14
18
  if value.has_key?('Ref')
@@ -17,7 +21,21 @@ module References
17
21
  resolve_map(cfn_model, value)
18
22
  elsif value.has_key?('Fn::If')
19
23
  resolve_if(cfn_model, value)
20
- else
24
+ elsif value.has_key?('Fn::Sub')
25
+ resolve_sub(cfn_model, value)
26
+ elsif value.has_key?('Fn::GetAZs')
27
+ resolve_getazs(cfn_model, value)
28
+ elsif value.has_key?('Fn::Split')
29
+ resolve_split(cfn_model, value)
30
+ elsif value.has_key?('Fn::Join')
31
+ resolve_join(cfn_model, value)
32
+ elsif value.has_key?('Fn::Base64')
33
+ resolve_base64(cfn_model, value)
34
+ elsif value.has_key?('Fn::Select')
35
+ resolve_select(cfn_model, value)
36
+ elsif unsupported_passthru?(value)
37
+ value
38
+ else # another mapping
21
39
  value.map do |k,v|
22
40
  [k, resolve_value(cfn_model, v)]
23
41
  end.to_h
@@ -101,6 +119,107 @@ module References
101
119
 
102
120
  private
103
121
 
122
+ def self.resolve_sub(cfn_model, expression)
123
+ if expression['Fn::Sub'].is_a? String
124
+ resolve_shorthand_sub(cfn_model, expression)
125
+ elsif expression['Fn::Sub'].is_a? Array
126
+ resolve_longform_sub(cfn_model, expression)
127
+ else
128
+ expression
129
+ end
130
+ end
131
+
132
+ def self.resolve_select(cfn_model, reference)
133
+ index = reference['Fn::Select'][0]
134
+ collection = References.resolve_value(cfn_model, reference['Fn::Select'][1])
135
+ if collection.is_a? Array
136
+ collection[index]
137
+ else
138
+ reference
139
+ end
140
+ end
141
+
142
+ def self.resolve_base64(cfn_model, reference)
143
+ References.resolve_value(cfn_model, reference['Fn::Base64'])
144
+ end
145
+
146
+ def self.resolve_join(cfn_model, reference)
147
+ delimiter = reference['Fn::Join'][0]
148
+ items = References.resolve_value(cfn_model, reference['Fn::Join'][1])
149
+ return reference unless items.is_a?(Array)
150
+ items.join(delimiter)
151
+ end
152
+
153
+ def self.resolve_split(cfn_model, reference)
154
+ delimiter = reference['Fn::Split'][0]
155
+ target_string = References.resolve_value(cfn_model, reference['Fn::Split'][1])
156
+ return reference unless target_string.is_a?(String)
157
+ target_string.split(delimiter)
158
+ end
159
+
160
+ def self.resolve_getazs(cfn_model, reference)
161
+ number_azs = References.resolve_value(cfn_model, { 'Ref' => 'AWS::NumberAZs' })
162
+ region = reference['Fn::GetAZs']
163
+ if region == '' || region == { 'Ref' => 'AWS::Region' }
164
+ region = References.resolve_value(cfn_model, { 'Ref' => 'AWS::Region' })
165
+ end
166
+ (('a'.ord)..('a'.ord+number_azs)).map do |az_number|
167
+ "#{region}#{az_number.chr}"
168
+ end
169
+ end
170
+
171
+ def self.strip_cfn_interpolation(reference)
172
+ reference[2..-2]
173
+ end
174
+
175
+ def self.references_in_sub(string_value)
176
+ # ignore ${!foo} as cfn interprets that as the literal ${foo}
177
+ references = string_value.scan /\${[^!].*?}/
178
+ references.map { |reference| strip_cfn_interpolation(reference) }
179
+ end
180
+
181
+ def self.resolvable_reference?(cfn_model, reference)
182
+ resolved_value = References.resolve_value(cfn_model, {'Ref'=>reference})
183
+ resolved_value != {'Ref'=>reference}
184
+ end
185
+
186
+ def self.resolve_shorthand_sub(cfn_model, expression)
187
+ string_value = expression['Fn::Sub']
188
+ subbed_string_value = string_value
189
+ has_unresolved_references = false
190
+ references_in_sub(string_value).each do |reference|
191
+ if resolvable_reference?(cfn_model, reference)
192
+ subbed_string_value = subbed_string_value.gsub(
193
+ "${#{reference}}",
194
+ References.resolve_value(cfn_model, {'Ref'=>reference})
195
+ )
196
+ end
197
+ end
198
+ subbed_string_value
199
+ end
200
+
201
+ def self.resolve_longform_sub(cfn_model, expression)
202
+ array_value = expression['Fn::Sub']
203
+ subbed_string_value = array_value[0]
204
+ substitution_mapping = array_value[1]
205
+ references_in_sub(subbed_string_value).each do |reference|
206
+ if substitution_mapping.has_key? reference
207
+ if References.resolve_value(cfn_model, substitution_mapping[reference]).is_a?(String)
208
+ subbed_string_value = subbed_string_value.gsub(
209
+ "${#{reference}}",
210
+ References.resolve_value(cfn_model, substitution_mapping[reference])
211
+ )
212
+ end
213
+ elsif resolvable_reference?(cfn_model, reference)
214
+ subbed_string_value = subbed_string_value.gsub(
215
+ "${#{reference}}",
216
+ References.resolve_value(cfn_model, {'Ref'=>reference})
217
+ )
218
+ end
219
+ end
220
+ subbed_string_value
221
+ end
222
+
104
223
  def self.resolve_if(cfn_model, expression)
105
224
  if_expression = expression['Fn::If']
106
225
  condition_name = if_expression[0]
@@ -43,7 +43,8 @@ class ParameterSubstitution
43
43
  'AWS::AccountId' => '111111111111',
44
44
  'AWS::Region' => 'us-east-1',
45
45
  'AWS::StackId' => 'arn:aws:cloudformation:us-east-1:111111111111:stack/stackname/51af3dc0-da77-11e4-872e-1234567db123',
46
- 'AWS::StackName' => 'stackname'
46
+ 'AWS::StackName' => 'stackname',
47
+ 'AWS::NumberAZs' => 2
47
48
  }
48
49
  pseudo_function_defaults.each do |function_name, default_value|
49
50
  parameter = Parameter.new
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.31
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-04 00:00:00.000000000 Z
11
+ date: 2020-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop