kumogata 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: 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