cfndk 0.0.1

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.
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