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 +4 -4
- data/bin/convection +38 -15
- data/lib/convection/model/template.rb +16 -0
- data/lib/convection/model/template/resource/aws_ec2_security_group.rb +52 -0
- data/lib/convection/model/template/resource/aws_iam_user.rb +55 -0
- data/lib/convection/model/template/resource/aws_s3_bucket.rb +24 -0
- data/lib/convection/model/template/resource/aws_s3_bucket_policy.rb +22 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc4c4bbe225ec33757f900d24c62f5629644e4ae
|
4
|
+
data.tar.gz: b3e00e9748782113a6a7491cacb12cdc0b2f71e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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.
|
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-
|
11
|
+
date: 2018-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|