kumogata 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 28f500bbe000bfcca855c3e8d44d60f2fbba233d
4
+ data.tar.gz: 378508af2ad72d1911de56ed05f25a9672fa7b22
5
+ SHA512:
6
+ metadata.gz: 4ddbe3c73b965c5d95a1439a15ab9da7d4862b6f1bdbe3b36aa0cc6fede3d3f61a801278fd14ff6ded443dc4dd9e2effa5f901989002f5af9b8c163bb98bd7d4
7
+ data.tar.gz: 8eff8eb5fd29490c27a8521fa03bc961ef7eff06ec3162dea3b055cf43cb87298443baddac8ce57f30a5091bf36b140712abe5514d39c4356cfe0518eb95ce7e
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ packer_cache
19
+ test.rb
20
+ result.json
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kumogata.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # Kumogata
2
+
3
+ Kumogata is a tool for AWS CroudFormation.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/kumogata.png?201403021953)](http://badge.fury.io/rb/kumogata)
6
+ [![Build Status](https://drone.io/github.com/winebarrel/kumogata/status.png?201403021953)](https://drone.io/github.com/winebarrel/kumogata/latest)
7
+
8
+ It can define a template in Ruby DSL, such as:
9
+
10
+ ```ruby
11
+ Parameters do
12
+ InstanceType do
13
+ Default "t1.micro"
14
+ Description "Instance Type"
15
+ Type "String"
16
+ end
17
+ end
18
+
19
+ Resources do
20
+ myEC2Instance do
21
+ Type "AWS::EC2::Instance"
22
+ Properties do
23
+ ImageId "ami-XXXXXXXX"
24
+ InstanceType { Ref "InstanceType" }
25
+ KeyName "your_key_name"
26
+
27
+ UserData _user_data(<<-EOS)
28
+ #!/bin/bash
29
+ yum install -y httpd
30
+ service httpd start
31
+ EOS
32
+ end
33
+ end
34
+ end
35
+
36
+ Outputs do
37
+ AZ do
38
+ Value do
39
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
40
+ end
41
+ end
42
+ end
43
+ ```
44
+
45
+ ## Installation
46
+
47
+ $ gem install kumogata
48
+
49
+ ## Usage
50
+
51
+ ```
52
+ Usage: kumogata <command> [args] [options]
53
+
54
+ Commands:
55
+ create PATH_OR_URL [STACK_NAME] Create resources as specified in the template
56
+ validate PATH_OR_URL Validate a specified template
57
+ convert PATH_OR_URL Convert a template format
58
+ update PATH_OR_URL STACK_NAME Update a stack as specified in the template
59
+ delete STACK_NAME Delete a specified stack
60
+ list [STACK_NAME] List summary information for stacks
61
+
62
+ Options:
63
+ -k, --access-key ACCESS_KEY
64
+ -s, --secret-key SECRET_KEY
65
+ -r, --region REGION
66
+ --skip-replace-underscore
67
+ --skip-delete-stack
68
+ -p, --parameters KEY_VALUES
69
+ --capabilities CAPABILITIES
70
+ --disable-rollback
71
+ --notify SNS_TOPICS
72
+ --timeout MINUTES
73
+ --result-log PATH
74
+ --force
75
+ --no-color
76
+ --debug
77
+ ```
78
+
79
+ ### Create resources
80
+
81
+ $ kumogata creat template.rb
82
+
83
+ If you want to save the stack, please specify the stack name:
84
+
85
+ $ kumogata creat template.rb any_stack_name
86
+
87
+ If you want to pass parameters, please use `-p` option:
88
+
89
+ $ kumogata creat template.rb -p "InstanceType=m1.large,KeyName=any_other_key"
90
+
91
+
92
+ **Notice**
93
+
94
+ **The stack will be delete if you do not specify the stack name explicitly.**
95
+ (And only the resources will remain)
96
+
97
+ I think the stack that manage resources is not required in many case...
98
+
99
+ ### Convert JSON to Ruby
100
+
101
+ JSON template can be converted to Ruby template.
102
+
103
+ $ kumogata convert https://s3.amazonaws.com/cloudformation-templates-us-east-1/Drupal_Single_Instance.template
104
+
105
+ * Data that cannot be converted will be converted to Array and Hash
106
+ * `::` is converted to `__`
107
+ * `Fn::GetAtt` => `Fn__GetAtt`
108
+ * `_{ ... }` is convered to Hash
109
+ * `SecurityGroups [_{Ref "WebServerSecurityGroup"}]` => `{"SecurityGroups": [{"Ref": "WebServerSecurityGroup"}]}`
110
+ * `_user_data()` creates Base64-encoded UserData
111
+ * `_path()` creates Hash that has a key of path
112
+ * `_path("/etc/passwd-s3fs") { content "..." }` => `{"/etc/passwd-s3fs": {"content": "..."}}`
113
+
114
+ ## Demo
115
+
116
+ * Create resources
117
+ * https://asciinema.org/a/7979
118
+ * Convert a template
119
+ * https://asciinema.org/a/7980
120
+
121
+ ## Contributing
122
+
123
+ 1. Fork it ( http://github.com/winebarrel/kumogata/fork )
124
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
125
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
126
+ 4. Push to the branch (`git push origin my-new-feature`)
127
+ 5. Create new Pull Request
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/kumogata ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
3
+ require 'rubygems'
4
+ require 'kumogata'
5
+
6
+ options = nil
7
+
8
+ begin
9
+ parsed = Kumogata::ArgumentParser.parse! {|parser, cmd, args, opts|
10
+ if (opts.access_key_id? and not opts.secret_access_key?) or
11
+ (not opts.access_key_id? and opts.secret_access_key?)
12
+ puts parser.help
13
+ exit 1
14
+ end
15
+ }
16
+
17
+ command, arguments, options = parsed
18
+
19
+ aws_opts = {}
20
+
21
+ [:access_key_id, :secret_access_key, :region].each do |key|
22
+ aws_opts[key] = options[key] if options[key]
23
+ end
24
+
25
+ AWS.config(aws_opts) unless aws_opts.empty?
26
+
27
+ String.colorize = options.color?
28
+
29
+ if options.debug?
30
+ Kumogata.logger.set_debug(true)
31
+
32
+ AWS.config({
33
+ :http_wire_trace => true,
34
+ :logger => Kumogata.logger,
35
+ })
36
+ end
37
+
38
+ out = Kumogata::Client.new(options).send(command, *arguments)
39
+ puts out if out
40
+ rescue => e
41
+ $stderr.puts("[ERROR] #{e.message}".red)
42
+
43
+ if options and options.debug?
44
+ raise e
45
+ end
46
+
47
+ exit 1
48
+ end
data/kumogata.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kumogata/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'kumogata'
8
+ spec.version = Kumogata::VERSION
9
+ spec.authors = ['Genki Sugawara']
10
+ spec.email = ['sgwr_dts@yahoo.co.jp']
11
+ spec.summary = %q{A tool for AWS CroudFormation.}
12
+ spec.description = %q{A tool for AWS CroudFormation. It can define a template in Ruby DSL.}
13
+ spec.homepage = 'https://github.com/winebarrel/kumogata'
14
+ spec.license = 'MIT'
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_dependency 'aws-sdk'
22
+ spec.add_dependency 'dslh', '>= 0.2.1'
23
+ spec.add_dependency 'hashie'
24
+ spec.add_dependency 'highline'
25
+ spec.add_dependency 'json'
26
+ spec.add_dependency 'term-ansicolor'
27
+ spec.add_dependency 'uuidtools'
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'rspec', '>= 2.11.0'
31
+ end
@@ -0,0 +1,142 @@
1
+ Version = Kumogata::VERSION
2
+
3
+ class Kumogata::ArgumentParser
4
+ DEFAULT_OPTIONS = {
5
+ :replace_underscore => true,
6
+ :delete_stack => true,
7
+ :result_log => File.join(Dir.pwd, 'result.json'),
8
+ :color => true,
9
+ :debug => false,
10
+ }
11
+
12
+ COMMANDS = {
13
+ :create => {
14
+ :description => 'Create resources as specified in the template',
15
+ :arguments => [:path_or_url, :stack_name?]
16
+ },
17
+ :validate => {
18
+ :description => 'Validate a specified template',
19
+ :arguments => [:path_or_url]
20
+ },
21
+ :convert => {
22
+ :description => 'Convert a template format',
23
+ :arguments => [:path_or_url]
24
+ },
25
+ :update => {
26
+ :description => 'Update a stack as specified in the template',
27
+ :arguments => [:path_or_url, :stack_name]
28
+ },
29
+ :delete => {
30
+ :description => 'Deletes a specified stack',
31
+ :arguments => [:stack_name]
32
+ },
33
+ :list => {
34
+ :description => 'List summary information for stacks',
35
+ :arguments => [:stack_name?]
36
+ },
37
+ }
38
+
39
+ class << self
40
+ def parse!(&block)
41
+ self.new.parse!(&block)
42
+ end
43
+ end # of class methods
44
+
45
+ def parse!
46
+ command = nil
47
+ arguments = nil
48
+ options = {}
49
+
50
+ ARGV.options do |opt|
51
+ update_usage(opt)
52
+
53
+ begin
54
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| options[:access_key_id] = v }
55
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| options[:secret_access_key] = v }
56
+ opt.on('-r', '--region REGION') {|v| options[:region] = v }
57
+ opt.on('' , '--skip-replace-underscore') { options[:replace_underscore] = false }
58
+ opt.on('' , '--skip-delete-stack') { options[:delete_stack] = false }
59
+ opt.on('-p', '--parameters KEY_VALUES', Array) {|v| options[:parameters] = v }
60
+ opt.on('' , '--capabilities CAPABILITIES', Array) {|v| options[:capabilities] = v }
61
+ opt.on('' , '--disable-rollback') { options[:disable_rollback] = true }
62
+ opt.on('' , '--notify SNS_TOPICS', Array) {|v| options[:notify] = v }
63
+ opt.on('' , '--timeout MINUTES', Integer) {|v| options[:timeout] = v }
64
+ opt.on('' , '--result-log PATH') {|v| options[:result_log] = v }
65
+ opt.on('' , '--force') { options[:force] = true }
66
+ opt.on('' , '--no-color') { options[:color] = false }
67
+ opt.on('' , '--debug') { options[:debug] = true }
68
+ opt.parse!
69
+
70
+ unless (command = ARGV.shift)
71
+ puts opt.help
72
+ exit 1
73
+ end
74
+
75
+ command = command.to_sym
76
+
77
+ unless COMMANDS.has_key?(command)
78
+ raise "Unknown command: #{command}"
79
+ end
80
+
81
+ arguments = ARGV.dup
82
+ validate_arguments(command, arguments)
83
+
84
+ options = DEFAULT_OPTIONS.merge(options)
85
+ options = Hashie::Mash.new(options)
86
+
87
+ if block_given?
88
+ yield(opt, command, arguments, options)
89
+ end
90
+ rescue => e
91
+ $stderr.puts("#{e.message}")
92
+ exit 1
93
+ end
94
+ end
95
+
96
+ [command, arguments, options]
97
+ end
98
+
99
+ private
100
+
101
+ def update_usage(opt)
102
+ opt.banner = "Usage: kumogata <command> [args] [options]"
103
+ opt.separator ''
104
+ opt.separator 'Commands:'
105
+
106
+ cmd_max = COMMANDS.keys.map {|i| i.to_s.length }.max
107
+
108
+ cmd_arg_descs = COMMANDS.map {|command, attributes|
109
+ arguments = attributes[:arguments]
110
+ description = attributes[:description]
111
+
112
+ [
113
+ '%-*s %s' % [cmd_max, command, arguments_to_message(arguments)],
114
+ description,
115
+ ]
116
+ }
117
+
118
+ cmd_arg_max = cmd_arg_descs.map {|i| i[0].length }.max
119
+
120
+ opt.separator(cmd_arg_descs.map {|cmd_arg, desc|
121
+ ' %-*s %-s' % [cmd_arg_max, cmd_arg, desc]
122
+ }.join("\n"))
123
+
124
+ opt.separator ''
125
+ opt.separator 'Options:'
126
+ end
127
+
128
+ def validate_arguments(command, arguments)
129
+ expected = COMMANDS[command][:arguments] || []
130
+
131
+ min = expected.count {|i| i.to_s !~ /\?\Z/ }
132
+ max = expected.length
133
+
134
+ if arguments.length < min or max < arguments.length
135
+ raise "Usage: kumogata #{command} #{arguments_to_message(expected)} [options]"
136
+ end
137
+ end
138
+
139
+ def arguments_to_message(arguments)
140
+ arguments.map {|i| i.to_s.sub(/(.+)\?\Z/) { "[#{$1}]" }.upcase }.join(' ')
141
+ end
142
+ end