kumogata2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e68a1cac5efe71e08f2d002ac2884c76818bb6fb
4
+ data.tar.gz: a6373ae6c26e04b76775d44e75d257d2be92e9eb
5
+ SHA512:
6
+ metadata.gz: 8851364eb886e8254f807432d5c33c4fe26988473d094b8e8a6b5a320ed27dafdda4d75b87b75be4727f87564a938e647f5a0a9d2f29a3ee3cfabbb15369b216
7
+ data.tar.gz: 5c1dc3f643cf26808396fc84a7c951e72109ec1e05f0c62773a6d6a84aefb3875d8fe40e2cfba84ee7b27b626786cceb192735c1abda7717fde38015a2b9cd3a
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.json
11
+ test.rb
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kumogata2.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Genki Sugawara
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # Kumogata2
2
+
3
+ Kumogata2 is a tool for [AWS CloudFormation](https://aws.amazon.com/cloudformation/).
4
+
5
+ This is a `format converter` + `useful tool`.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'kumogata2'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install kumogata2
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ Usage: kumogata2 <command> [args] [options]
27
+
28
+ Commands:
29
+ create PATH_OR_URL [STACK_NAME] Create resources as specified in the template
30
+ update PATH_OR_URL STACK_NAME Update a stack as specified in the template
31
+ delete STACK_NAME Delete a specified stack
32
+ validate PATH_OR_URL Validate a specified template
33
+ list [STACK_NAME] List summary information for stacks
34
+ export STACK_NAME Export a template from a specified stack
35
+ convert PATH_OR_URL Convert a template format
36
+ diff PATH_OR_URL1 PATH_OR_URL2 Compare templates logically (file, http://..., stack://...)
37
+ dry-run PATH_OR_URL STACK_NAME Create a change set and show it
38
+ show-events STACK_NAME Show events for a specified stack
39
+ show-outputs STACK_NAME Show outputs for a specified stack
40
+ show-resources STACK_NAME Show resources for a specified stack
41
+
42
+ Support Format:
43
+ json, js, template
44
+
45
+ Options:
46
+ -k, --access-key ACCESS_KEY
47
+ -s, --secret-key SECRET_KEY
48
+ -r, --region REGION
49
+ --profile PROFILE
50
+ --credentials-path PATH
51
+ --output-format FORMAT
52
+ -p, --parameters KEY_VALUES
53
+ -j, --json-parameters JSON
54
+ --[no-]deletion-policy-retain
55
+ --[no-]disable-rollback
56
+ --timeout-in-minutes TIMEOUT_IN_MINUTES
57
+ --notification-arns NOTIFICATION_ARNS
58
+ --capabilities CAPABILITIES
59
+ --resource-types RESOURCE_TYPES
60
+ --on-failure ON_FAILURE
61
+ --stack-policy-body STACK_POLICY_BODY
62
+ --stack-policy-url STACK_POLICY_URL
63
+ --[no-]use-previous-template
64
+ --stack-policy-during-update-body STACK_POLICY_DURING_UPDATE_BODY
65
+ --stack-policy-during-update-url STACK_POLICY_DURING_UPDATE_URL
66
+ --result-log PATH
67
+ --command-result-log PATH
68
+ --[no-]detach
69
+ --[no-]force
70
+ --[no-]color
71
+ --[no-]ignore-all-space
72
+ --[no-]debug
73
+ ```
74
+
75
+ ## Plugin
76
+
77
+ Kumogata2 can be extended with plug-ins, such as the following:
78
+
79
+ ```ruby
80
+ class Kumogata2::Plugin::JSON
81
+ Kumogata2::Plugin.register(:json, ['json', 'js', 'template'], self)
82
+
83
+ def initialize(options)
84
+ @options = options
85
+ end
86
+
87
+ def parse(str)
88
+ JSON.parse(str)
89
+ end
90
+
91
+ def dump(hash)
92
+ JSON.pretty_generate(hash).colorize_as(:json)
93
+ end
94
+ end
95
+ ```
96
+
97
+ see [kumogata2-plugin-ruby](https://github.com/winebarrel/kumogata2-plugin-ruby).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kumogata2"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/kumogata2 ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path('../../lib', __FILE__)
3
+ require 'kumogata2'
4
+ require 'kumogata2/cli/option_parser'
5
+
6
+ Version = Kumogata2::VERSION
7
+
8
+ def main(argv)
9
+ debug = true
10
+
11
+ begin
12
+ Kumogata2::Plugin.load_plugins
13
+
14
+ parsed = Kumogata2::CLI::OptionParser.parse!(argv)
15
+ command, arguments, options, output_result = parsed
16
+ debug = options.debug?
17
+
18
+ out = Kumogata2::Client.new(options).send(command, *arguments)
19
+
20
+ if [:create, :update, :delete].include?(command) and options.detach?
21
+ puts '[detached]'
22
+ elsif output_result and out
23
+ puts out
24
+ end
25
+ rescue => e
26
+ $stderr.puts("[ERROR] #{e.message}".red)
27
+
28
+ if debug
29
+ raise e
30
+ else
31
+ backtrace = Kumogata2::Utils.filter_backtrace(e.backtrace)
32
+
33
+ unless backtrace.empty?
34
+ $stderr.puts " from #{backtrace.first}".red
35
+ end
36
+ end
37
+
38
+ exit 1
39
+ end
40
+ end
41
+
42
+ main(ARGV)
data/kumogata2.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kumogata2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'kumogata2'
8
+ spec.version = Kumogata2::VERSION
9
+ spec.authors = ['Genki Sugawara']
10
+ spec.email = ['sugawara@cookpad.com']
11
+
12
+ spec.summary = %q{Kumogata2 is a tool for AWS CloudFormation.}
13
+ spec.description = %q{Kumogata2 is a tool for AWS CloudFormation.}
14
+ spec.homepage = 'https://github.com/winebarrel/kumogata2'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'aws-sdk', '~> 2.3.0'
23
+ spec.add_dependency 'coderay'
24
+ spec.add_dependency 'diffy'
25
+ spec.add_dependency 'hashie'
26
+ spec.add_dependency 'highline'
27
+ spec.add_dependency 'term-ansicolor'
28
+
29
+ spec.add_development_dependency 'bundler'
30
+ spec.add_development_dependency 'rake'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ spec.add_development_dependency 'kumogata2-plugin-ruby'
33
+ end
@@ -0,0 +1,260 @@
1
+ require 'optparse'
2
+ require 'hashie'
3
+
4
+ module Kumogata2::CLI
5
+ class OptionParser
6
+ DEFAULT_OPTIONS = {
7
+ result_log: File.join(Dir.pwd, 'result.json'),
8
+ command_result_log: File.join(Dir.pwd, 'command_result.json'),
9
+ color: $stdout.tty?,
10
+ }
11
+
12
+ COMMANDS = {
13
+ create: {
14
+ description: 'Create resources as specified in the template',
15
+ arguments: [:path_or_url, :stack_name?],
16
+ output: false,
17
+ },
18
+ update: {
19
+ description: 'Update a stack as specified in the template',
20
+ arguments: [:path_or_url, :stack_name],
21
+ output: false,
22
+ },
23
+ delete: {
24
+ description: 'Delete a specified stack',
25
+ arguments: [:stack_name],
26
+ output: false,
27
+ },
28
+ validate: {
29
+ description: 'Validate a specified template',
30
+ arguments: [:path_or_url],
31
+ output: false,
32
+ },
33
+ list: {
34
+ description: 'List summary information for stacks',
35
+ arguments: [:stack_name?],
36
+ },
37
+ export: {
38
+ description: 'Export a template from a specified stack',
39
+ arguments: [:stack_name],
40
+ },
41
+ convert: {
42
+ description: 'Convert a template format',
43
+ arguments: [:path_or_url],
44
+ },
45
+ diff: {
46
+ description: 'Compare templates logically (file, http://..., stack://...)',
47
+ arguments: [:path_or_url1, :path_or_url2],
48
+ },
49
+ dry_run: {
50
+ description: 'Create a change set and show it',
51
+ arguments: [:path_or_url, :stack_name],
52
+ },
53
+ show_events: {
54
+ description: 'Show events for a specified stack',
55
+ arguments: [:stack_name],
56
+ },
57
+ show_outputs: {
58
+ description: 'Show outputs for a specified stack',
59
+ arguments: [:stack_name],
60
+ },
61
+ show_resources: {
62
+ description: 'Show resources for a specified stack',
63
+ arguments: [:stack_name],
64
+ },
65
+ }
66
+
67
+ class << self
68
+ def parse!(argv)
69
+ self.new.parse!(argv)
70
+ end
71
+ end # of class methods
72
+
73
+ def parse!(argv)
74
+ command = nil
75
+ arguments = nil
76
+ options = {aws: {}}
77
+
78
+ opt = ::OptionParser.new
79
+ opt.summary_width = 65535
80
+ set_usage!(opt)
81
+
82
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| options[:aws][:access_key_id] = v }
83
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| options[:aws][:secret_access_key] = v }
84
+ opt.on('-r', '--region REGION') {|v| options[:aws][:region] = v }
85
+
86
+ opt.on('', '--profile PROFILE') do |v|
87
+ options[:aws][:credentials] ||= {}
88
+ options[:aws][:credentials][:profile_name] = v
89
+ end
90
+
91
+ opt.on('', '--credentials-path PATH') do |v|
92
+ options[:aws][:credentials] ||= {}
93
+ options[:aws][:credentials][:path] = v
94
+ end
95
+
96
+ opt.on('' , '--output-format FORMAT', Kumogata2::Plugin.plugin_exts) do |v|
97
+ options[:output_format] = v
98
+ end
99
+
100
+ opt.on('-p', '--parameters KEY_VALUES', Array) {|v| options[:parameters] = v }
101
+ opt.on('-j', '--json-parameters JSON') {|v| options[:json_parameters] = v }
102
+ opt.on('' , '--[no-]deletion-policy-retain') {|v| options[:deletion_policy_retain] = v }
103
+
104
+ {
105
+ disable_rollback: :boolean,
106
+ timeout_in_minutes: Integer,
107
+ notification_arns: Array,
108
+ capabilities: Array,
109
+ resource_types: Array,
110
+ on_failure: nil,
111
+ stack_policy_body: nil,
112
+ stack_policy_url: nil,
113
+ use_previous_template: :boolean,
114
+ stack_policy_during_update_body: nil,
115
+ stack_policy_during_update_url: nil,
116
+ }.each do |key, type|
117
+ opt_str = key.to_s.gsub('_', '-')
118
+ opt_val = key.to_s.upcase
119
+
120
+ case type
121
+ when :boolean
122
+ opt.on('', "--[no-]#{opt_str}") {|v| options[key] = v }
123
+ when nil
124
+ opt.on('', "--#{opt_str} #{opt_val}") {|v| options[key] = v }
125
+ else
126
+ opt.on('', "--#{opt_str} #{opt_val}", type) {|v| options[key] = v }
127
+ end
128
+ end
129
+
130
+ opt.on('' , '--result-log PATH') {|v| options[:result_log] = v }
131
+ opt.on('' , '--command-result-log PATH') {|v| options[:command] = v }
132
+ opt.on('' , '--[no-]detach') {|v| options[:detach] = v }
133
+ opt.on('' , '--[no-]force') {|v| options[:force] = v }
134
+ opt.on('' , '--[no-]color') {|v| options[:color] = v }
135
+ opt.on('' , '--[no-]ignore-all-space') {|v| options[:ignore_all_space] = v }
136
+ opt.on('' , '--[no-]debug') {|v| options[:debug] = v }
137
+
138
+ opt.parse!
139
+
140
+ unless (command = argv.shift)
141
+ puts opt.help
142
+ exit_parse!(1)
143
+ end
144
+
145
+ orig_command = command
146
+ command = command.gsub('-', '_').to_sym
147
+
148
+ unless COMMANDS.has_key?(command)
149
+ raise "Unknown command: #{orig_command}"
150
+ end
151
+
152
+ arguments = argv.dup
153
+ validate_arguments(command, arguments)
154
+
155
+ options = DEFAULT_OPTIONS.merge(options)
156
+ options = Hashie::Mash.new(options)
157
+
158
+ if options[:aws][:credentials]
159
+ credentials = Aws::SharedCredentials.new(options[:aws][:credentials])
160
+ options[:aws][:credentials] = credentials
161
+ end
162
+
163
+ Aws.config.update(options[:aws].dup)
164
+ options = Hashie::Mash.new(options)
165
+
166
+ String.colorize = options.color?
167
+ Diffy::Diff.default_format = options.color? ? :color : :text
168
+
169
+ if options.debug?
170
+ Kumogata2::Logger.instance.set_debug(options.debug?)
171
+
172
+ Aws.config.update(
173
+ :http_wire_trace => true,
174
+ :logger => Kumogata2::Logger.instance
175
+ )
176
+ end
177
+
178
+ update_parameters(options)
179
+ output = COMMANDS.fetch(command).fetch(:output, true)
180
+
181
+ options.command = command
182
+ options.arguments = arguments
183
+ options.output_result = output
184
+
185
+ [command, arguments, options, output]
186
+ rescue => e
187
+ $stderr.puts("[ERROR] #{e.message}")
188
+ raise e if options[:debug]
189
+ exit_parse!(1)
190
+ end
191
+
192
+ private
193
+
194
+ def exit_parse!(exit_code)
195
+ exit(exit_code)
196
+ end
197
+
198
+ def set_usage!(opt)
199
+ opt.banner = "Usage: kumogata2 <command> [args] [options]"
200
+ opt.separator ''
201
+ opt.separator 'Commands:'
202
+
203
+ cmd_max_len = COMMANDS.keys.map {|i| i.to_s.length }.max
204
+
205
+ cmd_arg_descs = COMMANDS.map do |command, attributes|
206
+ command = command.to_s.gsub('_', '-')
207
+ description = attributes.fetch(:description)
208
+ arguments = attributes.fetch(:arguments)
209
+
210
+ [
211
+ '%-*s %s' % [cmd_max_len, command, arguments_to_message(arguments)],
212
+ description,
213
+ ]
214
+ end
215
+
216
+ cmd_arg_max_len = cmd_arg_descs.map {|i| i[0].length }.max
217
+
218
+ opt.separator(cmd_arg_descs.map {|cmd_arg, desc|
219
+ ' %-*s %-s' % [cmd_arg_max_len, cmd_arg, desc]
220
+ }.join("\n"))
221
+
222
+ opt.separator ''
223
+ opt.separator 'Support Format: '
224
+ opt.separator ' ' + Kumogata2::Plugin.plugin_exts.join(', ')
225
+
226
+ opt.separator ''
227
+ opt.separator 'Options:'
228
+ end
229
+
230
+ def arguments_to_message(arguments)
231
+ arguments.map {|i| i.to_s.sub(/(.+)\?\z/) { "[#{$1}]" }.upcase }.join(' ')
232
+ end
233
+
234
+ def validate_arguments(command, arguments)
235
+ expected = COMMANDS[command][:arguments] || []
236
+
237
+ min = expected.count {|i| i.to_s !~ /\?\z/ }
238
+ max = expected.length
239
+
240
+ if arguments.length < min or max < arguments.length
241
+ raise "Usage: kumogata #{command} #{arguments_to_message(expected)} [options]"
242
+ end
243
+ end
244
+
245
+ def update_parameters(options)
246
+ parameters = {}
247
+
248
+ (options.parameters || []).each do |i|
249
+ key, value = i.split('=', 2)
250
+ parameters[key] = value
251
+ end
252
+
253
+ if options.json_parameters
254
+ parameters.merge!(JSON.parse(options.json_parameters))
255
+ end
256
+
257
+ options.parameters = parameters
258
+ end
259
+ end # OptionParser
260
+ end # Kumogata2::CLI