cfn-model 0.4.12 → 0.4.13

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: a1706430755f12f30280c2a2baebb5566d50898ede81ec20e503ef91642e08b6
4
- data.tar.gz: 30075abf14b456b2ebed049d9af2b68cfee7be938f8bcf9b8936170e651f8eeb
3
+ metadata.gz: 82992d31bca207f0fdccac49ce35cd26042703ea19c9cccd6c84166c534fcb30
4
+ data.tar.gz: c73dfff8dc47c2112b3d7c31ed9ff9c88d00cb7e9519495383b54d924d4110e9
5
5
  SHA512:
6
- metadata.gz: a7223fce1ad56a488c37cfc27c0b35a2b5f0df76c4d3dc7b55ca2d46139b8f2f479e5ae981549ac91844d710cabf2519a73fbc1507426e0ee254976cf0a328d6
7
- data.tar.gz: a1e9d39a1f17aa3f0ed0238cb8abc098a2880f3873ff3270ff9f2e6dc6c8dbdc017c96e3c0e6ca30531de5be8adf7a3494cd97b843476a8300ebda657fea977a
6
+ metadata.gz: 0de79a70b411c0655e60e0fbc61454b4fd8b662a132a66ec56512c5ce9dce7a338c3994dd8df1fa988bc281defed281e0300197b23383034bb147b05e8dec399
7
+ data.tar.gz: 02a845a5e38a29d9d097ec1a31fdd6be34ce28760150c381e7070776fb864864a70659b58ed409eacb1b02185ec17d8debdfe00d18348c0f9da2b20e9c1f8d47
@@ -3,7 +3,7 @@
3
3
  require_relative 'references'
4
4
 
5
5
  class CfnModel
6
- attr_reader :resources, :parameters, :line_numbers
6
+ attr_reader :resources, :parameters, :line_numbers, :conditions
7
7
 
8
8
  ##
9
9
  # if you really want it, here it is - the raw Hash from YAML.load. you'll have to mess with structural nits of
@@ -14,6 +14,7 @@ class CfnModel
14
14
  def initialize
15
15
  @parameters = {}
16
16
  @resources = {}
17
+ @conditions = {}
17
18
  @raw_model = nil
18
19
  @line_numbers = {}
19
20
  end
@@ -24,6 +25,9 @@ class CfnModel
24
25
  # the Hash is a clone
25
26
  def copy
26
27
  new_cfn_model = CfnModel.new
28
+ @conditions.each do |k,v|
29
+ new_cfn_model.conditions[k] = v
30
+ end
27
31
  @parameters.each do |k,v|
28
32
  new_cfn_model.parameters[k] = v
29
33
  end
@@ -38,8 +38,8 @@ class CfnParser
38
38
  ##
39
39
  # Given raw json/yml CloudFormation template, returns a CfnModel object
40
40
  # or raise ParserErrors if something is amiss with the format
41
- def parse(cloudformation_yml, parameter_values_json=nil, with_line_numbers=false)
42
- cfn_model = parse_without_parameters(cloudformation_yml, with_line_numbers)
41
+ def parse(cloudformation_yml, parameter_values_json=nil, with_line_numbers=false, condition_values_json=nil)
42
+ cfn_model = parse_without_parameters(cloudformation_yml, with_line_numbers, condition_values_json)
43
43
 
44
44
  apply_parameter_values(cfn_model, parameter_values_json)
45
45
 
@@ -54,7 +54,7 @@ class CfnParser
54
54
  ToRubyWithLineNumbers.create.accept(handler.root).first
55
55
  end
56
56
 
57
- def parse_without_parameters(cloudformation_yml, with_line_numbers=false)
57
+ def parse_without_parameters(cloudformation_yml, with_line_numbers=false, condition_values_json=nil)
58
58
  pre_validate_model cloudformation_yml
59
59
 
60
60
  cfn_hash =
@@ -73,6 +73,8 @@ class CfnParser
73
73
  cfn_model = CfnModel.new
74
74
  cfn_model.raw_model = cfn_hash
75
75
 
76
+ process_conditions cfn_hash, cfn_model, condition_values_json
77
+
76
78
  # pass 1: wire properties into ModelElement objects
77
79
  if with_line_numbers
78
80
  transform_hash_into_model_elements_with_numbers cfn_hash, cfn_model
@@ -89,6 +91,24 @@ class CfnParser
89
91
 
90
92
  private
91
93
 
94
+ def process_conditions(cfn_hash, cfn_model, condition_values_json)
95
+ if cfn_hash.key?('Conditions')
96
+ if condition_values_json.nil?
97
+ condition_values = {}
98
+ else
99
+ condition_values = JSON.load condition_values_json
100
+ end
101
+
102
+ cfn_hash['Conditions'].each do |condition_key, _|
103
+ if condition_values.key?(condition_key) && [true, false].include?(condition_values[condition_key])
104
+ cfn_model.conditions[condition_key] = condition_values[condition_key]
105
+ else
106
+ cfn_model.conditions[condition_key] = true
107
+ end
108
+ end
109
+ end
110
+ end
111
+
92
112
  def apply_parameter_values(cfn_model, parameter_values_json)
93
113
  ParameterSubstitution.new.apply_parameter_values(
94
114
  cfn_model,
@@ -119,7 +139,7 @@ class CfnParser
119
139
  resource_object.resource_type = resource['Type']
120
140
  resource_object.metadata = resource['Metadata']
121
141
 
122
- assign_fields_based_upon_properties resource_object, resource
142
+ assign_fields_based_upon_properties resource_object, resource, cfn_model
123
143
 
124
144
  cfn_model.resources[resource_name] = resource_object
125
145
  end
@@ -135,7 +155,7 @@ class CfnParser
135
155
  resource_object.resource_type = resource['Type']['value']
136
156
  resource_object.metadata = resource['Metadata']
137
157
 
138
- assign_fields_based_upon_properties resource_object, resource
158
+ assign_fields_based_upon_properties resource_object, resource, cfn_model
139
159
 
140
160
  cfn_model.resources[resource_name] = resource_object
141
161
  cfn_model.line_numbers[resource_name] = resource['Type']['line']
@@ -175,11 +195,31 @@ class CfnParser
175
195
  end
176
196
  end
177
197
 
178
- def assign_fields_based_upon_properties(resource_object, resource)
198
+ def deal_with_conditional_property_definitions(resource, cfn_model)
199
+ all_extra_concrete_properties = []
200
+ resource['Properties'].each do |property_name, property_value|
201
+ next if %w(Fn::Transform).include? property_name
202
+ if property_name == 'Fn::If'
203
+ concrete_properties = ExpressionEvaluator.new.evaluate(
204
+ {'Fn::If'=>property_value},
205
+ cfn_model.conditions
206
+ )
207
+ all_extra_concrete_properties << concrete_properties
208
+ end
209
+ end
210
+ all_extra_concrete_properties.each do |extra_concrete_properties|
211
+ resource['Properties'].merge!(extra_concrete_properties)
212
+ end
213
+ resource['Properties'].delete('Fn::If')
214
+ end
215
+
216
+ def assign_fields_based_upon_properties(resource_object, resource, cfn_model)
179
217
  unless resource['Properties'].nil?
218
+ deal_with_conditional_property_definitions(resource, cfn_model)
219
+
180
220
  resource['Properties'].each do |property_name, property_value|
181
- next if %w(Fn::Transform Fn::If).include? property_name
182
- resource_object.send("#{map_property_name_to_attribute(property_name)}=", property_value)
221
+ next if %w(Fn::Transform).include? property_name
222
+ resource_object.send("#{map_property_name_to_attribute(property_name)}=", map_property_value(property_value, cfn_model))
183
223
  end
184
224
  end
185
225
  end
@@ -194,6 +234,10 @@ class CfnParser
194
234
  resource_class
195
235
  end
196
236
 
237
+ def map_property_value(property_value, cfn_model)
238
+ ExpressionEvaluator.new.evaluate(property_value, cfn_model.conditions)
239
+ end
240
+
197
241
  def map_property_name_to_attribute(str)
198
242
  (str.slice(0).downcase + str[1..(str.length)]).gsub /-/, '_'
199
243
  end
@@ -0,0 +1,39 @@
1
+ class ExpressionEvaluator
2
+ FN_IF = 'Fn::If'
3
+
4
+ ##
5
+ # {'Fn::If'=>[Condition,X,Y]} returns X if conditions doesn't include Condition, otherwise it return X or Y depending
6
+ #
7
+ # Other than Fn::If, it just returns the value itself
8
+ def evaluate(expression, conditions)
9
+ if if_condition?(expression)
10
+ outcome(expression, conditions)
11
+ else
12
+ expression
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def outcome(expression, conditions)
19
+ if if_condition?(expression)
20
+ if_expression = expression[FN_IF]
21
+ condition_name = if_expression[0]
22
+ if conditions[condition_name]
23
+ outcome(if_expression[1], conditions)
24
+ else
25
+ outcome(if_expression[2], conditions)
26
+ end
27
+ elsif expression.is_a?(Hash) # plain dict
28
+ expression.each do |k,v|
29
+ expression[k] = outcome(v, conditions)
30
+ end
31
+ else
32
+ expression
33
+ end
34
+ end
35
+
36
+ def if_condition?(property_value)
37
+ property_value.is_a?(Hash) && property_value.key?(FN_IF) && property_value.size == 1
38
+ end
39
+ end
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.12
4
+ version: 0.4.13
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-01-13 00:00:00.000000000 Z
11
+ date: 2020-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -89,6 +89,7 @@ files:
89
89
  - lib/cfn-model/parser/cfn_parser.rb
90
90
  - lib/cfn-model/parser/ec2_instance_parser.rb
91
91
  - lib/cfn-model/parser/ec2_network_interface_parser.rb
92
+ - lib/cfn-model/parser/expression_evaluator.rb
92
93
  - lib/cfn-model/parser/iam_group_parser.rb
93
94
  - lib/cfn-model/parser/iam_role_parser.rb
94
95
  - lib/cfn-model/parser/iam_user_parser.rb