convection 2.2.12 → 2.2.13

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06fa6942996ee32f586741975300cad7ddd11e83
4
- data.tar.gz: f393211f45deac206370eaa9c5c7163547b563da
3
+ metadata.gz: cc4c4bbe225ec33757f900d24c62f5629644e4ae
4
+ data.tar.gz: b3e00e9748782113a6a7491cacb12cdc0b2f71e0
5
5
  SHA512:
6
- metadata.gz: '0801e86aef339edd14e256942d10c641ade985171fca98f15db341a0ef18652230cb0a8c9762dda1f048a68ac47f27164cf08bcbba7397a4fd1aa8ffeac885f7'
7
- data.tar.gz: d110b282f788d2479e8984f3117ed339244019ea51efaa284be93bee0cc021967b07357ff172bb5ba82c4b7d9a113c83147d4cc53b55e3f7aa9a8b38e1149057
6
+ metadata.gz: 731c78af0486d452e249a27c40499bbe4d44d44df7a5fd35c7501c6104ddb4720ccdf60b870574f2b3808510a85870530351e241a20aa6167fe712116a21d09f
7
+ data.tar.gz: 88af87c51fa62ca1be9e73748d90abfe9a0bbb63b0946d028fe3a5a2ae01eb218b6285ae4145faf4fb40acac07cf2cfb864697dad6678a7e156679a6529bc653
data/bin/convection CHANGED
@@ -130,22 +130,19 @@ module Convection
130
130
  m['resources'].reject { |k, _| k.start_with?('data.') }
131
131
  }.reduce({}, &:merge)
132
132
  cf = Aws::CloudFormation::Client.new(region: options[:stack_region])
133
- cf_resources = cf.describe_stack_resources(stack_name: options[:stack_name]).stack_resources
133
+ cf_resources = cf.describe_stack_resources(stack_name: options[:stack_name]).stack_resources.map do |r|
134
+ { logical_resource_id: r.logical_resource_id, physical_resource_id: r.physical_resource_id, type: r.resource_type }
135
+ end
134
136
  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
137
+ response = ask_tf_physical_id(cf_resource)
138
+ cf_resource[:physical_resource_id] = response unless response.empty?
139
+ say "Resource #{cf_resource[:physical_resource_id].inspect} #{cf_resource[:logical_resource_id].inspect}:"
140
+
141
+ tf_resource = tf_resource_for(physical_resource_id: cf_resource[:physical_resource_id], resources: terraform_resources)
142
+ if tf_resource[:attribute_key] && tf_resource[:partial]
143
+ say " * Found physical ID included in Terraform resource #{tf_resource[:logical_resource_id].inspect} under attribute #{tf_resource[:attribute_key].inspect} with value #{tf_resource[:value].inspect}. Please validate this resource is included in state and configuration.", :yellow
144
+ elsif tf_resource[:attribute_key] && !tf_resource[:partial]
145
+ say " * Found physical ID exactly in Terraform resource #{tf_resource[:logical_resource_id].inspect} under attribute #{tf_resource[:attribute_key].inspect} with value #{tf_resource[:value].inspect}.", :green
149
146
  else
150
147
  say " * Unable to find physical ID in the provided Terraform state.", :red
151
148
  end
@@ -280,6 +277,18 @@ module Convection
280
277
 
281
278
  private
282
279
 
280
+ def ask_tf_physical_id(cf_resource)
281
+ question = case cf_resource[:type]
282
+ when 'AWS::IAM::Policy'
283
+ "What is the <role-name>:<policy-name> for the #{cf_resource[:logical_resource_id].inspect} IAM policy?"
284
+ when 'AWS::S3::BucketPolicy'
285
+ "What is the name of the bucket that the #{cf_resource[:logical_resource_id].inspect} policy belongs to?"
286
+ end
287
+ return '' unless question
288
+
289
+ ask(question, :yellow).chomp
290
+ end
291
+
283
292
  def load_local_terraform_state(statefile)
284
293
  JSON.load(File.open(statefile))
285
294
  end
@@ -306,6 +315,20 @@ module Convection
306
315
  end
307
316
  end
308
317
 
318
+ def tf_resource_for(physical_resource_id:, resources:)
319
+ logical_id, resource = resources.find do |_, resource|
320
+ next true if resource['primary'].key(physical_resource_id)
321
+ resource['primary'].values.any? { |v| v.is_a?(String) && v.include?(physical_resource_id) }
322
+ end
323
+ return {} unless logical_id && resource
324
+
325
+ key = resource['primary'].key(physical_resource_id)
326
+ return { attribute_key: key, logical_id: logical_id, partial: false, value: physical_resource_id } if key
327
+
328
+ key, value = value['primary'].find { |v| v.include?(physical_resource_id) }
329
+ return { attribute_key: key, logical_id: logical_id, partial: true, value: value }
330
+ end
331
+
309
332
  def import_resources(resource_name, resource)
310
333
  empty_directory options[:output_directory] if resource.respond_to?(:to_hcl_json) || resource.respond_to?(:additional_hcl_files)
311
334
  if resource.respond_to?(:to_hcl_json)
@@ -41,6 +41,22 @@ module Convection
41
41
  @resource_collection_dsl_methods ||= {}
42
42
  end
43
43
  end
44
+
45
+ def _terraform_module_dir_to_flag(dir)
46
+ return 'root' if dir.empty?
47
+
48
+ parts = dir.split('/')
49
+ parts[0] = 'module' if parts[0] == 'modules'
50
+ parts.join('.')
51
+ end
52
+
53
+ def _terraform_module_flag_to_dir(flag)
54
+ return '' if flag == 'root'
55
+
56
+ parts = flag.split('.')
57
+ parts[0] = 'modules'
58
+ parts.join('/')
59
+ end
44
60
  end
45
61
 
46
62
  include DSL::Helpers
@@ -116,6 +116,58 @@ module Convection
116
116
  render_tags(resource)
117
117
  end
118
118
  end
119
+
120
+ def to_hcl_json(*)
121
+ tf_sg_name = name.underscore
122
+ tf_sg_var_id = "${aws_security_group.#{tf_sg_name}.id}"
123
+ tf_resources = []
124
+
125
+ # Define the security group resource.
126
+ tf_resources << {
127
+ aws_security_group: {
128
+ tf_sg_name => {
129
+ vpc_id: vpc,
130
+ description: description,
131
+ tags: tags.reject { |_, v| v.nil? }
132
+ }.reject { |_, v| v.nil? }
133
+ }
134
+ }
135
+
136
+ tf_sg_rules = {}
137
+
138
+ # Define helper functions to map Convection rules to Terraform ones.
139
+ sg_rule_to_tf = lambda do |rule_type, item, index|
140
+ tf_sg_rule_name = "#{tf_sg_name}_#{rule_type}_#{index}"
141
+
142
+ tf_sg_rules[tf_sg_rule_name] = {
143
+ type: rule_type,
144
+ security_group_id: tf_sg_var_id,
145
+ from_port: item.from,
146
+ to_port: item.to,
147
+ protocol: item.protocol,
148
+ cidr_block: item.source,
149
+ # TODO: Missing attribs & checks. Should probably be defined as a
150
+ # seperate function to reuse for egress.
151
+ }.reject { |_, v| v.nil? }
152
+ end
153
+
154
+ # Map the contained rules to TF.
155
+ security_group_ingress.each_with_index { |item, obj| sg_rule_to_tf.call('ingress', item, obj) }
156
+ security_group_egress.each_with_index { |item, obj| sg_rule_to_tf.call('egress', item, obj) }
157
+
158
+ tf_resources << { aws_security_group_rule: tf_sg_rules }
159
+
160
+ # Return the JSON representation of this resource.
161
+ { resource: tf_resources }.to_json
162
+ end
163
+
164
+ def terraform_import_commands(module_path: 'root')
165
+ prefix = "#{module_path}." unless module_path == 'root'
166
+ resource_id = stack.resources[name] && stack.resources[name].physical_resource_id
167
+ commands = ['# Import the security group:']
168
+ commands << "terraform import #{prefix}aws_security_group.#{name.underscore} #{resource_id}"
169
+ commands
170
+ end
119
171
  end
120
172
  end
121
173
  end
@@ -63,6 +63,61 @@ module Convection
63
63
  property :path, 'Path'
64
64
  property :policies, 'Policies', :type => :list
65
65
  property :user_name, 'UserName'
66
+
67
+ def additional_hcl_files(module_path: 'root')
68
+ module_prefix = module_path.tr('.', '-') if module_path == 'root'
69
+ result = {}
70
+
71
+ user = user_name
72
+ user ||= stack.resources[name] && stack.resources[name].physical_resource_id
73
+ result["#{stack._original_region}-#{stack._original_cloud}-#{name.underscore}.tf.json"] = {
74
+ module: [{
75
+ name.underscore => {
76
+ source: _terraform_module_flag_to_dir(module_path),
77
+ managed_policy_arns: managed_policy_arn,
78
+ name: user,
79
+ path: path
80
+ }
81
+ }]
82
+ }
83
+
84
+ result["#{module_prefix}#{name.underscore}-variables.tf.json"] = {
85
+ variable: [
86
+ { managed_policy_arns: { description: 'A list of ARNs for managed policies to attach to this user.', default: [] } },
87
+ { name: { description: 'The name of the user' } },
88
+ { path: { description: 'The path for the IAM user', path: '/' } }
89
+ ]
90
+ }
91
+
92
+ result["#{module_prefix}#{name.underscore}-user.tf.json"] = {
93
+ resource: [
94
+ {
95
+ aws_iam_user: {
96
+ name.underscore => {
97
+ managed_policy_arns: '${var.managed_policy_arns}',
98
+ name: '${var.name}',
99
+ path: '${var.path}'
100
+ }
101
+ }
102
+ }
103
+ ]
104
+ }
105
+
106
+ policy_resources = policies.map do |policy|
107
+ {
108
+ aws_iam_user_policy: {
109
+ policy.name.underscore => {
110
+ name: policy.name,
111
+ policy: policy.render.to_json,
112
+ user: "${aws_iam_user.#{name.underscore}.id}"
113
+ }
114
+ }
115
+ }
116
+ end
117
+ result["#{module_prefix}#{name.underscore}-policy.tf.json"] = { resource: policy_resources }
118
+
119
+ result
120
+ end
66
121
  end
67
122
  end
68
123
  end
@@ -50,6 +50,30 @@ module Convection
50
50
  properties['WebsiteConfiguration'].set(config)
51
51
  end
52
52
 
53
+ def terraform_import_commands(module_path: 'root')
54
+ commands = ['# Run the following commands to import your infrastructure into terraform management.', '# ensure :module_path is set correctly', '']
55
+ module_prefix = "#{module_path}." unless module_path == 'root'
56
+
57
+ commands << '# Import s3 bucket and s3 bucket policy: '
58
+ commands << "terraform import #{module_prefix}aws_s3_bucket.#{name.underscore} #{stack.resources[name].physical_resource_id}"
59
+ commands << ''
60
+ commands
61
+ end
62
+
63
+ def to_hcl_json(*)
64
+ bucket_resource = {
65
+ name.underscore => {
66
+ bucket: stack.resources[name].physical_resource_id,
67
+ acl: 'private',
68
+ force_destroy: false
69
+ }
70
+ }
71
+
72
+ data = [{ aws_region: { current: { current: true } } }]
73
+ vars = [{ cloud: { description: 'The cloud name for this resource.' } }]
74
+ { resource: [{ aws_s3_bucket: bucket_resource }], data: data, variable: vars }.to_json
75
+ end
76
+
53
77
  def render(*args)
54
78
  super.tap do |resource|
55
79
  render_tags(resource)
@@ -30,6 +30,28 @@ module Convection
30
30
  @document = Model::Mixin::Policy.new(:name => false, :template => @template)
31
31
  end
32
32
 
33
+ def terraform_import_commands(*)
34
+ commands = ['# Run the following commands to import your infrastructure into terraform management.', '# ensure :module_path is set correctly', '']
35
+ commands << '# Import s3 bucket and s3 bucket policy: '
36
+ # commands << "terraform import #{module_prefix}aws_s3_bucket.#{name.underscore} #{stack.resources[name].physical_resource_id}"
37
+ commands << ''
38
+ commands
39
+ end
40
+
41
+ def to_hcl_json(*)
42
+ policy_json = resources[name] && resources[name].document.document.to_json.gsub(stack.resources[name].physical_resource_id, bucket)
43
+ policy_resource = {
44
+ name.underscore => {
45
+ bucket: bucket,
46
+ policy: policy_json
47
+ }
48
+ }
49
+
50
+ data = [{ aws_region: { current: { current: true } } }]
51
+ vars = [{ cloud: { description: 'The cloud name for this resource.' } }]
52
+ { resource: { aws_s3_bucket_policy: policy_resource }, data: data, variable: vars }.to_json
53
+ end
54
+
33
55
  def render
34
56
  super.tap do |r|
35
57
  document.render(r['Properties'])
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.12
4
+ version: 2.2.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Manero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-10 00:00:00.000000000 Z
11
+ date: 2018-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport