convection 2.2.9 → 2.2.10

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/convection +65 -2
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 885a2657be20ba62b8093c5e9a1a40ba1e07d00a
4
- data.tar.gz: ef6fa45e59e1f5c5cb638a25aee3d988d6e8df84
3
+ metadata.gz: f7c478ce35a94d9130d3d2657a092bdb5436f505
4
+ data.tar.gz: d5dff048c6a317a79b0b8df5743f148768e0b368
5
5
  SHA512:
6
- metadata.gz: bfb48a30b72cfd48182128f4844ffa1545135b197366777b517ed4c7273068324252427e268268c37c593b444cb50420c01b92fc7bcc07fc710c0d6c963ce708
7
- data.tar.gz: 857133927e3ca14e847c663c93523073595514e03116c830a02b5cf24c6a821224569f26fe6a849233ee2104e5989053506acc45378d29bef90f6c177810c22c
6
+ metadata.gz: 4690a2b22a2988cd38cb7ae2d8e2dceac1bdd7f0b2080d3a2a42190b2ff2ed6033733b6ddfad97e6afd44c409e92a0c5a97f8220346f62f68ca37e871f03de7f
7
+ data.tar.gz: 1104ceadddfcc37b30dc12804e8e65b3fd580328421788da03fd6f90a3eb5f5df0ecac2da0bafa1d1a535668c7c4ba30092365521365d0fe28d544662f61b779
data/bin/convection CHANGED
@@ -13,6 +13,7 @@ module Convection
13
13
  include Thor::Actions
14
14
 
15
15
  DEFAULT_MODULE_PATH = 'root'.freeze
16
+ S3_URI_REGEX = %r(^s3://(?<bucket>[^/]+)/(?<key>.+)).freeze
16
17
 
17
18
  def initialize(*args)
18
19
  super
@@ -119,6 +120,38 @@ module Convection
119
120
  describe_stack_resources(options[:stack], options[:format], options[:properties], options[:type])
120
121
  end
121
122
 
123
+ desc 'terraForm-compare-resources', 'Compare resources in CloudFormation and in terraform state'
124
+ option :stack_name, desc: 'The CloudFormation stack name (Stack#cloud_name)'
125
+ option :stack_region, desc: 'The region where the stack resides', required: true
126
+ option :state, desc: 'The source terraform state file (can be an s3:// uri)', required: true
127
+ option :state_region, desc: 'The region where the state resides (required to load remote state)'
128
+ def terraform_compare_resources
129
+ terraform_resources = tfstate['modules'].flat_map { |m|
130
+ m['resources'].reject { |k, _| k.start_with?('data.') }
131
+ }.reduce({}, &:merge)
132
+ cf = Aws::CloudFormation::Client.new(region: options[:stack_region])
133
+ cf_resources = cf.describe_stack_resources(stack_name: options[:stack_name]).stack_resources
134
+ cf_resources.each do |cf_resource|
135
+ say "Resource '#{cf_resource.physical_resource_id}':"
136
+ say " * CloudFormation Logical ID #{cf_resource.logical_resource_id}"
137
+
138
+ tf_resource_name, tf_resource = terraform_resources.find do |_, tf_resource|
139
+ next true if tf_resource['primary'].key(cf_resource.physical_resource_id)
140
+ tf_resource['primary'].values.any? { |v| v.is_a?(String) && v.include?(cf_resource.physical_resource_id) }
141
+ end
142
+ tf_key = tf_resource && tf_resource['primary'].key(cf_resource.physical_resource_id)
143
+ fuzzy_match = tf_key.nil?
144
+ tf_key ||= tf_resource && tf_resource['primary'].find { |v| v.include?(cf_resource.physical_resource_id) }
145
+ if tf_key && fuzzy_match
146
+ say " * Found physical ID included in Terraform resource #{tf_resource_name} under attribute #{tf_key} with value '#{tf_resource['primary'][tf_key]}'. Please validate this resource is included in state and configuration.", :yellow
147
+ elsif tf_key && !fuzzy_match
148
+ say " * Found physical ID exactly in Terraform resource #{tf_resource_name} under attribute #{tf_key} with value '#{tf_resource['primary'][tf_key]}'.", :cyan
149
+ else
150
+ say " * Unable to find physical ID in the provided Terraform state.", :red
151
+ end
152
+ end
153
+ end
154
+
122
155
  # rubocop:disable Style/AsciiComments
123
156
 
124
157
  desc 'terraform-export STACK', 'Create terraform configuration for a given stack (including `terraform import` commands)'
@@ -140,7 +173,8 @@ module Convection
140
173
  end
141
174
 
142
175
  init_cloud
143
- template = @cloud.stacks.fetch(stack_name).template
176
+ @stack = @cloud.stacks.fetch(stack_name)
177
+ template = @stack.template
144
178
 
145
179
  # Beware of 🐲. This patches this instance to include terraform compatible intrinsic functions where possible.
146
180
  #
@@ -243,6 +277,32 @@ module Convection
243
277
 
244
278
  private
245
279
 
280
+ def load_local_terraform_state(statefile)
281
+ JSON.load(File.open(statefile))
282
+ end
283
+
284
+ def load_remote_terraform_state(bucket, key)
285
+ unless options[:state_region] && !options[:state_region].empty?
286
+ say 'ERROR: --state-region must be specified to load remote state.', :red
287
+ exit 1
288
+ end
289
+
290
+ s3 = Aws::S3::Client.new(region: options[:state_region])
291
+ object = s3.get_object(bucket: bucket, key: key)
292
+ JSON.load(object.body)
293
+ end
294
+
295
+ def tfstate
296
+ return @tfstate if @tfstate
297
+
298
+ match_data = options[:state].match(S3_URI_REGEX)
299
+ if match_data
300
+ @tfstate = load_remote_terraform_state(match_data['bucket'], match_data['key'])
301
+ else
302
+ @tfstate = load_local_terraform_state(options[:state])
303
+ end
304
+ end
305
+
246
306
  def import_resources(_resource_name, resource)
247
307
  empty_directory options[:output_directory] if resource.respond_to?(:to_hcl_json) || resource.respond_to?(:additional_hcl_files)
248
308
  if resource.respond_to?(:to_hcl_json)
@@ -263,7 +323,9 @@ module Convection
263
323
  end
264
324
 
265
325
  if resource.respond_to?(:terraform_import_commands)
266
- resource.terraform_import_commands(module_path: options[:module_path]).each do |line|
326
+ destination = File.join(options[:output_directory], "terraform-import-#{resource_name.underscore}-#{@stack._original_region}-#{@stack._original_cloud}.sh")
327
+ lines = resource.terraform_import_commands(module_path: options[:module_path])
328
+ lines.each do |line|
267
329
  comment = line.start_with?('#')
268
330
  if options[:omit_comments]
269
331
  next if comment || line.strip.empty?
@@ -272,6 +334,7 @@ module Convection
272
334
  color = comment ? :bold : :cyan
273
335
  say line, color
274
336
  end
337
+ create_file destination, lines.join("\n")
275
338
  else
276
339
  say "# Unable to determine terraform import commands for #{resource.class}. Define #{resource.class}#terraform_import_commands to do so.", :yellow
277
340
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convection
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.9
4
+ version: 2.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Manero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-20 00:00:00.000000000 Z
11
+ date: 2017-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport