cfndk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/cfndk ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'rainbow/ext/string'
6
+ require 'optparse'
7
+ require 'fileutils'
8
+ require 'pathname'
9
+ require 'erb'
10
+ require 'yaml'
11
+ require 'json'
12
+ require 'aws-sdk'
13
+ require 'terminal-table'
14
+ require 'securerandom'
15
+
16
+ require 'cfndk.rb'
17
+
18
+ cur_dir = Dir.getwd
19
+
20
+ option = {
21
+ config_path: "#{cur_dir}/cfndk.yml",
22
+ uuid: ENV['CFNDK_UUID'] || nil,
23
+ properties: {},
24
+ }
25
+
26
+ opt = OptionParser.new do |o|
27
+ o.version = CFnDK::VERSION
28
+ o.summary_indent = ' ' * 4
29
+ o.banner = 'Usage: cfndk [cmd] [options]'
30
+ o.on_head('[cmd]',
31
+ ' init create config YAML file',
32
+ ' create create stacks',
33
+ ' update update stacks',
34
+ ' create-or-changeset create stacks or create changeset',
35
+ ' destroy destroy stacks',
36
+ ' generate-uuid generate UUID',
37
+ ' report-event report stack event',
38
+ ' report-stack report stack',
39
+ ' report-stack-resource report stack resource',
40
+ '[enviroment variables]',
41
+ " AWS_PROFILE: #{ENV['AWS_PROFILE']}",
42
+ " AWS_DEFAULT_REGION: #{ENV['AWS_DEFAULT_REGION']}",
43
+ " AWS_REGION: #{ENV['AWS_REGION']}",
44
+ " AWS_ACCESS_KEY_ID: #{ENV['AWS_ACCESS_KEY_ID']}",
45
+ " AWS_SECRET_ACCESS_KEY: #{ENV['AWS_SECRET_ACCESS_KEY']}",
46
+ " AWS_SESSION_TOKEN: #{ENV['AWS_SECRET_ACCESS_KEY']}",
47
+ " AWS_CONTAINER_CREDENTIALS_RELATIVE_URI: #{ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']}",
48
+ '[options]')
49
+ o.on('-v', '--verbose', 'verbose mode') { |v| option[:v] = v }
50
+ o.on('-c', '--config_path <cfndi.yml>', "config path (default: #{option[:config_path]})") { |v| option[:config_path] = v }
51
+ o.on('-p', '--properties <name>=<value>', 'properties') do |v|
52
+ md = v.match(/^([a-zA-Z_]+[a-zA-Z0-9_]*)=(.*)$/)
53
+ if md
54
+ option[:properties][md[0]] = md[1]
55
+ else
56
+ raise "invalid properties: '#{v}'" unless md
57
+ end
58
+ end
59
+ o.on('-a', '--auto-uuid') { option[:uuid] = SecureRandom.uuid }
60
+ o.on('-u', '--uuid <uuid>') { |v| option[:uuid] = v }
61
+ o.permute!(ARGV)
62
+ end
63
+
64
+ if ARGV.length != 1
65
+ puts opt.help
66
+ exit 1
67
+ elsif ARGV[0] == 'generate-uuid'
68
+ puts SecureRandom.uuid
69
+ exit 0
70
+ end
71
+
72
+ unless File.file?(option[:config_path]) || ARGV[0] == 'init'
73
+ puts "File does not exist. #{option[:config_path]}".color :red
74
+ exit 1
75
+ end
76
+
77
+ $LOAD_PATH.unshift "#{cur_dir}/lib"
78
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
79
+
80
+ data = open(option[:config_path], 'r') { |f| YAML.load(f) } if File.file?(option[:config_path]) && ARGV[0] != 'init'
81
+
82
+ credentials = CFnDK::Aws::CredentialProviderChain.new.resolve
83
+ client = Aws::CloudFormation::Client.new(credentials: credentials)
84
+ stacks = CFnDK::Stacks.new(data, option, client)
85
+
86
+ if ARGV[0] == 'create'
87
+ puts 'create...'.color :green
88
+ stacks.create
89
+ elsif ARGV[0] == 'update'
90
+ puts 'update...'.color :green
91
+ stacks.update
92
+ elsif ARGV[0] == 'create-or-changeset'
93
+ puts 'create or changeset...'.color :green
94
+ stacks.create_or_changeset
95
+ elsif ARGV[0] == 'destroy'
96
+ puts 'destroy...'.color :green
97
+ stacks.destroy
98
+ elsif ARGV[0] == 'report-event'
99
+ puts 'report event...'.color :green
100
+ stacks.report_event
101
+ elsif ARGV[0] == 'report-stack'
102
+ puts 'report stack...'.color :green
103
+ stacks.report_stack
104
+ elsif ARGV[0] == 'report-stack-resource'
105
+ puts 'report stack resource...'.color :green
106
+ stacks.report_stack_resource
107
+ elsif ARGV[0] == 'init'
108
+ if File.file?(option[:config_path])
109
+ puts "File exist. #{option[:config_path]}".color :red
110
+ exit 1
111
+ end
112
+ puts 'init...'.color :green
113
+ FileUtils.cp_r(Dir.glob(File.dirname(__FILE__) + '/../skel/*'), './')
114
+ puts "create #{option[:config_path]}".color :green
115
+ else
116
+ puts opt.help
117
+ exit 1
118
+ end
119
+
120
+ exit 0
data/cfndk.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cfndk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cfndk'
8
+ spec.version = CFnDK::VERSION
9
+ spec.authors = ['Yoshihisa AMAKATA']
10
+ spec.email = ['amakata@gmail.com']
11
+ spec.summary = 'cfndk is AWS Cloud Formation Development Kit'
12
+ spec.description = 'cfndk is AWS Cloud Formation Development Kit'
13
+ spec.homepage = 'https://github.com/Amakata/cfndk'
14
+ spec.license = 'http://www.apache.org/licenses/license-2.0'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 11.1.2'
23
+
24
+ spec.add_dependency 'rainbow', '~> 2.1.0'
25
+ spec.add_dependency 'aws-sdk', '~> 3'
26
+ spec.add_dependency 'camelizable', '~> 0.0.3'
27
+ spec.add_dependency 'terminal-table', '~> 1'
28
+ end
@@ -0,0 +1,115 @@
1
+ module CFnDK
2
+ module Aws
3
+ class CredentialProviderChain
4
+ def initialize(config = nil)
5
+ @config = config
6
+ end
7
+
8
+ def resolve
9
+ providers.each do |method_name, options|
10
+ provider = send(method_name, options.merge(config: @config))
11
+ return provider if provider && provider.set?
12
+ end
13
+ nil
14
+ end
15
+
16
+ private
17
+
18
+ def providers
19
+ [
20
+ [:static_credentials, {}],
21
+ [:env_credentials, {}],
22
+ [:assume_role_credentials, {}],
23
+ [:shared_credentials, {}],
24
+ [:process_credentials, {}],
25
+ [:instance_profile_credentials, {
26
+ retries: @config ? @config.instance_profile_credentials_retries : 0,
27
+ http_open_timeout: @config ? @config.instance_profile_credentials_timeout : 1,
28
+ http_read_timeout: @config ? @config.instance_profile_credentials_timeout : 1,
29
+ }],
30
+ ]
31
+ end
32
+
33
+ def static_credentials(options)
34
+ if options[:config]
35
+ ::Aws::Credentials.new(
36
+ options[:config].access_key_id,
37
+ options[:config].secret_access_key,
38
+ options[:config].session_token)
39
+ else
40
+ nil
41
+ end
42
+ end
43
+
44
+ def env_credentials(options)
45
+ key = %w(AWS_ACCESS_KEY_ID AMAZON_ACCESS_KEY_ID AWS_ACCESS_KEY)
46
+ secret = %w(AWS_SECRET_ACCESS_KEY AMAZON_SECRET_ACCESS_KEY AWS_SECRET_KEY)
47
+ token = %w(AWS_SESSION_TOKEN AMAZON_SESSION_TOKEN)
48
+ ::Aws::Credentials.new(envar(key), envar(secret), envar(token))
49
+ end
50
+
51
+ def envar(keys)
52
+ keys.each do |key|
53
+ return ENV[key] if ENV.key?(key)
54
+ end
55
+ nil
56
+ end
57
+
58
+ def shared_credentials(options)
59
+ if options[:config]
60
+ ::Aws::SharedCredentials.new(profile_name: options[:config].profile)
61
+ else
62
+ ::Aws::SharedCredentials.new(
63
+ profile_name: ENV['AWS_PROFILE'].nil? ? 'default' : ENV['AWS_PROFILE'])
64
+ end
65
+ rescue ::Aws::Errors::NoSuchProfileError
66
+ nil
67
+ end
68
+
69
+ def process_credentials(options)
70
+ profile_name = options[:config].profile if options[:config]
71
+ profile_name ||= ENV['AWS_PROFILE'].nil? ? 'default' : ENV['AWS_PROFILE']
72
+
73
+ config = ::Aws.shared_config
74
+ if config.config_enabled? && process_provider = config.credentials_process(profile_name)
75
+ ::Aws::ProcessCredentials.new(process_provider)
76
+ else
77
+ nil
78
+ end
79
+ rescue ::Aws::Errors::NoSuchProfileError
80
+ nil
81
+ end
82
+
83
+ def assume_role_credentials(options)
84
+ if ::Aws.shared_config.config_enabled?
85
+ profile = nil
86
+ region = nil
87
+ if options[:config]
88
+ profile = options[:config].profile
89
+ region = options[:config].region
90
+ assume_role_with_profile(options[:config].profile, options[:config].region)
91
+ end
92
+ assume_role_with_profile(profile, region)
93
+ else
94
+ nil
95
+ end
96
+ end
97
+
98
+ def instance_profile_credentials(options)
99
+ if ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
100
+ ::Aws::ECSCredentials.new(options)
101
+ else
102
+ ::Aws::InstanceProfileCredentials.new(options)
103
+ end
104
+ end
105
+
106
+ def assume_role_with_profile(prof, region)
107
+ ::Aws.shared_config.assume_role_credentials_from_config(
108
+ profile: prof,
109
+ region: region,
110
+ chain_config: @config
111
+ )
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,22 @@
1
+ module CFnDK
2
+ class ParameterString
3
+ attr_reader :uuid, :properties
4
+ def initialize(str, option)
5
+ @erb = ERB.new(str, nil, '-')
6
+ @properties = option[:properties]
7
+ @uuid = option[:uuid]
8
+ end
9
+
10
+ def value
11
+ @erb.result(binding)
12
+ end
13
+
14
+ def append_uuid(glue = '-')
15
+ if uuid
16
+ glue + uuid
17
+ else
18
+ ''
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ module CFnDK
2
+ class Stack
3
+ attr_reader :template_file, :parameter_input, :capabilities, :depends, :timeout_in_minutes
4
+ def initialize(name, data, option)
5
+ @name = name
6
+ @template_file = data['template_file'] || ''
7
+ @parameter_input = data['parameter_input'] || ''
8
+ @capabilities = data['capabilities'] || []
9
+ @depends = data['depends'] || []
10
+ @timeout_in_minutes = data['timeout_in_minutes'] || 1
11
+ @override_parameters = data['parameters'] || {}
12
+ @option = option
13
+ end
14
+
15
+ def name
16
+ [@name, @option[:uuid]].compact.join('-')
17
+ end
18
+
19
+ def template_body
20
+ File.open(@template_file, 'r').read
21
+ end
22
+
23
+ def parameters
24
+ json = JSON.load(open(@parameter_input).read)
25
+ json['Parameters'].map do |item|
26
+ next if item.empty?
27
+ {
28
+ parameter_key: item['ParameterKey'],
29
+ parameter_value: eval_override_parameter(item['ParameterKey'], item['ParameterValue']),
30
+ }
31
+ end.compact
32
+ end
33
+
34
+ private
35
+
36
+ def eval_override_parameter(k, v)
37
+ if @override_parameters[k]
38
+ CFnDK::ParameterString.new(@override_parameters[k], @option).value
39
+ else
40
+ v
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,308 @@
1
+ module CFnDK
2
+ class Stacks
3
+ def initialize(data, option, cfn_client)
4
+ @option = option
5
+ @cfn_client = cfn_client
6
+ create_stack data
7
+ create_sequence
8
+ end
9
+
10
+ def create
11
+ @sequence.each do |stacks|
12
+ stacks.each do |name|
13
+ puts(('creating ' + name).color(:green))
14
+ puts('Name :' + @stacks[name].name) if @option[:v]
15
+ puts('Parametres :' + @stacks[name].parameters.inspect) if @option[:v]
16
+ puts('Capabilities:' + @stacks[name].capabilities.inspect) if @option[:v]
17
+ puts('timeout :' + @stacks[name].timeout_in_minutes.to_s) if @option[:v]
18
+ @cfn_client.create_stack(
19
+ stack_name: @stacks[name].name,
20
+ template_body: @stacks[name].template_body,
21
+ parameters: @stacks[name].parameters,
22
+ capabilities: @stacks[name].capabilities,
23
+ timeout_in_minutes: @stacks[name].timeout_in_minutes
24
+ )
25
+ end
26
+ stacks.each do |name|
27
+ begin
28
+ @cfn_client.wait_until(
29
+ :stack_create_complete,
30
+ stack_name: @stacks[name].name
31
+ )
32
+ puts(('created ' + name).color(:green))
33
+ rescue Aws::Waiters::Errors::FailureStateError => ex
34
+ puts ex.message
35
+ report_event
36
+ raise ex
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def update
43
+ @sequence.each do |stacks|
44
+ updating_stacks = []
45
+ stacks.each do |name|
46
+ puts(('updating ' + name).color(:green))
47
+ puts('Name :' + @stacks[name].name) if @option[:v]
48
+ puts('Parametres :' + @stacks[name].parameters.inspect) if @option[:v]
49
+ puts('Capabilities:' + @stacks[name].capabilities.inspect) if @option[:v]
50
+ puts('timeout :' + @stacks[name].timeout_in_minutes.to_s) if @option[:v]
51
+ begin
52
+ @cfn_client.update_stack(
53
+ stack_name: @stacks[name].name,
54
+ template_body: @stacks[name].template_body,
55
+ parameters: @stacks[name].parameters,
56
+ capabilities: @stacks[name].capabilities
57
+ )
58
+ updating_stacks.push name
59
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
60
+ puts ex.message.color :red
61
+ end
62
+ end
63
+ updating_stacks.each do |name|
64
+ @cfn_client.wait_until(
65
+ :stack_update_complete,
66
+ stack_name: @stacks[name].name
67
+ )
68
+ puts(('updated ' + name).color(:green))
69
+ end
70
+ end
71
+ end
72
+
73
+ def create_or_changeset
74
+ @sequence.each do |stacks|
75
+ create_stacks = []
76
+ changeset_stacks = []
77
+ stacks.each do |name|
78
+ begin
79
+ @cfn_client.describe_stacks(
80
+ stack_name: @stacks[name].name
81
+ )
82
+ puts(('creating ' + name + @option[:uuid]).color(:green))
83
+ puts('Name :' + @stacks[name].name) if @option[:v]
84
+ puts('Parametres :' + @stacks[name].parameters.inspect) if @option[:v]
85
+ puts('Capabilities:' + @stacks[name].capabilities.inspect) if @option[:v]
86
+ @cfn_client.create_change_set(
87
+ stack_name: @stacks[name].name,
88
+ template_body: @stacks[name].template_body,
89
+ parameters: @stacks[name].parameters,
90
+ capabilities: @stacks[name].capabilities,
91
+ change_set_name: @stacks[name].name + @option[:uuid]
92
+ )
93
+ changeset_stacks.push name
94
+ rescue Aws::CloudFormation::Errors::ValidationError
95
+ puts(('creating ' + name).color(:green))
96
+ puts('Name :' + @stacks[name].name) if @option[:v]
97
+ puts('Parametres :' + @stacks[name].parameters.inspect) if @option[:v]
98
+ puts('Capabilities:' + @stacks[name].capabilities.inspect) if @option[:v]
99
+ puts('timeout :' + @stacks[name].timeout_in_minutes.to_s) if @option[:v]
100
+ @cfn_client.create_stack(
101
+ stack_name: @stacks[name].name,
102
+ template_body: @stacks[name].template_body,
103
+ parameters: @stacks[name].parameters,
104
+ capabilities: @stacks[name].capabilities,
105
+ timeout_in_minutes: @stacks[name].timeout_in_minutes
106
+ )
107
+ create_stacks.push name
108
+ end
109
+ end
110
+ create_stacks.each do |name|
111
+ @cfn_client.wait_until(
112
+ :stack_create_complete,
113
+ stack_name: @stacks[name].name
114
+ )
115
+ puts(('created ' + name).color(:green))
116
+ end
117
+ changeset_stacks.each do |name|
118
+ begin
119
+ @cfn_client.wait_until(
120
+ :change_set_create_complete,
121
+ stack_name: @stacks[name].name,
122
+ change_set_name: @stacks[name].name + @option[:uuid]
123
+ )
124
+ puts(('created ' + @stacks[name].name + @option[:uuid]).color(:green))
125
+ rescue Aws::Waiters::Errors::FailureStateError => ex
126
+ resp = @cfn_client.describe_change_set(
127
+ change_set_name: @stacks[name].name + @option[:uuid],
128
+ stack_name: @stacks[name].name
129
+ )
130
+ if resp.status_reason != "The submitted information didn't contain changes. Submit different information to create a change set."
131
+ puts ex.message.color :red
132
+ raise ex
133
+ else
134
+ puts(('failed ' + @stacks[name].name + @option[:uuid]).color(:red))
135
+ puts resp.status_reason
136
+ @cfn_client.delete_change_set(
137
+ change_set_name: @stacks[name].name + @option[:uuid],
138
+ stack_name: @stacks[name].name
139
+ )
140
+ puts(('deleted ' + @stacks[name].name + @option[:uuid]).color(:red))
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def report_stack
148
+ rows = @sequence.flat_map do |stacks|
149
+ stacks.flat_map do |name|
150
+ rows = []
151
+ begin
152
+ rows = @cfn_client.describe_stacks(
153
+ stack_name: @stacks[name].name
154
+ ).stacks.map do |item|
155
+ [
156
+ item.stack_name,
157
+ item.creation_time,
158
+ item.deletion_time,
159
+ case item.stack_status
160
+ when 'CREATE_FAILED' then
161
+ item.stack_status.color :red
162
+ when 'ROLLBACK_IN_PROGRESS' then
163
+ item.stack_status.color :red
164
+ when 'ROLLBACK_COMPLETE' then
165
+ item.stack_status.color :red
166
+ when 'CREATE_COMPLETE' then
167
+ item.stack_status.color :green
168
+ when 'DELETE_COMPLETE' then
169
+ item.stack_status.color :gray
170
+ else
171
+ item.stack_status.color :orange
172
+ end,
173
+ item.stack_status_reason]
174
+ end
175
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
176
+ puts ex.message
177
+ end
178
+ rows
179
+ end
180
+ end
181
+ table = Terminal::Table.new headings: %w(Name Creation Deletion Status Reason), rows: rows
182
+ puts table
183
+ end
184
+
185
+ def report_stack_resource
186
+ @sequence.each do |stacks|
187
+ stacks.each do |name|
188
+ puts(('stack ' + name).color(:green))
189
+ puts('Name :' + @stacks[name].name) if @option[:v]
190
+ begin
191
+ rows = @cfn_client.describe_stack_resources(
192
+ stack_name: @stacks[name].name
193
+ ).stack_resources.map do |item|
194
+ [
195
+ item.logical_resource_id,
196
+ item.physical_resource_id,
197
+ item.resource_type,
198
+ item.timestamp,
199
+ case item.resource_status
200
+ when 'CREATE_FAILED' then
201
+ item.resource_status.color :red
202
+ when 'ROLLBACK_IN_PROGRESS' then
203
+ item.resource_status.color :red
204
+ when 'ROLLBACK_COMPLETE' then
205
+ item.resource_status.color :red
206
+ when 'CREATE_COMPLETE' then
207
+ item.resource_status.color :green
208
+ when 'DELETE_COMPLETE' then
209
+ item.resource_status.color :gray
210
+ else
211
+ item.resource_status.color :orange
212
+ end,
213
+ item.resource_status_reason,
214
+ item.description,
215
+ ]
216
+ end
217
+ table = Terminal::Table.new headings: %w(L-name P-name Type Timestamp Status Reason Desc), rows: rows
218
+ puts table
219
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
220
+ puts ex.message
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ def report_event
227
+ @sequence.each do |stacks|
228
+ stacks.each do |name|
229
+ puts(('stack ' + name).color(:green))
230
+ puts('Name :' + @stacks[name].name) if @option[:v]
231
+ begin
232
+ rows = @cfn_client.describe_stack_events(
233
+ stack_name: @stacks[name].name
234
+ ).stack_events.map do |item|
235
+ [
236
+ item.resource_type,
237
+ item.timestamp,
238
+ case item.resource_status
239
+ when 'CREATE_FAILED' then
240
+ item.resource_status.color :red
241
+ when 'ROLLBACK_IN_PROGRESS' then
242
+ item.resource_status.color :red
243
+ when 'ROLLBACK_COMPLETE' then
244
+ item.resource_status.color :red
245
+ when 'CREATE_COMPLETE' then
246
+ item.resource_status.color :green
247
+ when 'DELETE_COMPLETE' then
248
+ item.resource_status.color :gray
249
+ else
250
+ item.resource_status.color :orange
251
+ end,
252
+ item.resource_status_reason]
253
+ end
254
+ table = Terminal::Table.new headings: %w(Type Time Status Reason), rows: rows
255
+ puts table
256
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
257
+ puts ex.message
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ def destroy
264
+ @sequence.reverse_each do |stacks|
265
+ stacks.each do |name|
266
+ puts(('deleting ' + name).color(:green))
267
+ puts('Name :' + @stacks[name].name) if @option[:v]
268
+ @cfn_client.delete_stack(
269
+ stack_name: @stacks[name].name
270
+ )
271
+ end
272
+ stacks.each do |name|
273
+ @cfn_client.wait_until(
274
+ :stack_delete_complete,
275
+ stack_name: @stacks[name].name
276
+ )
277
+ puts(('deleted ' + name).color(:green))
278
+ end
279
+ end
280
+ end
281
+
282
+ private
283
+
284
+ def create_stack(data)
285
+ @stacks = {}
286
+ data['stacks'].each do |name, properties|
287
+ @stacks[name] = Stack.new(name, properties, @option)
288
+ end
289
+ end
290
+
291
+ def create_sequence
292
+ @sequence = []
293
+ names_of_upprocessed_stack = @stacks.keys
294
+ names_of_processed_stack = []
295
+ until names_of_upprocessed_stack.empty?
296
+ names = names_of_upprocessed_stack.select do |name|
297
+ @stacks[name].depends.all? do |depend_name|
298
+ names_of_processed_stack.include? depend_name
299
+ end
300
+ end
301
+ raise 'There are cyclic dependency.' if names.empty?
302
+ names_of_processed_stack += names
303
+ names_of_upprocessed_stack -= names
304
+ @sequence.push names
305
+ end
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,3 @@
1
+ module CFnDK
2
+ VERSION = '0.0.1'.freeze
3
+ end
data/lib/cfndk.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'cfndk/version'
2
+ require 'cfndk/stack'
3
+ require 'cfndk/stacks'
4
+ require 'cfndk/parameter_string'
5
+ require 'cfndk/aws/credential_provider_chain'
6
+
7
+ module CFnDK
8
+ end
data/sample/cfndk.yml ADDED
@@ -0,0 +1,39 @@
1
+ stacks:
2
+ Network:
3
+ template_file: network/network.yaml
4
+ parameter_input: network/prod.json
5
+ parameters:
6
+ VpcName: Prod<%= append_uuid %>
7
+ InternalDnsName: prod<%= append_uuid %>.local
8
+ timeout_in_minutes: 8
9
+ Iam:
10
+ template_file: iam/iam.yaml
11
+ parameter_input: iam/prod.json
12
+ parameters:
13
+ WebRoleName: WebRole<%= append_uuid %>
14
+ WebInstanceProfileName: WebInstanceProfile<%= append_uuid %>
15
+ capabilities:
16
+ - CAPABILITY_IAM
17
+ - CAPABILITY_NAMED_IAM
18
+ timeout_in_minutes: 3
19
+ Sg:
20
+ template_file: sg/sg.yaml
21
+ parameter_input: sg/prod.json
22
+ parameters:
23
+ depends:
24
+ - Network
25
+ Web:
26
+ template_file: web/web.yaml
27
+ parameter_input: web/prod.json
28
+ parameters:
29
+ depends:
30
+ - Sg
31
+ - Iam
32
+ timeout_in_minutes: 2
33
+ Db:
34
+ template_file: db/db.yaml
35
+ parameter_input: db/prod.json
36
+ parameters:
37
+ depends:
38
+ - Sg
39
+ timeout_in_minutes: 30