sunzi 1.5.2 → 2.0.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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +7 -0
  4. data/README.md +14 -37
  5. data/bin/console +14 -0
  6. data/bin/setup +8 -0
  7. data/{bin → exe}/sunzi +0 -0
  8. data/lib/sunzi.rb +18 -22
  9. data/lib/sunzi/actions.rb +35 -0
  10. data/lib/sunzi/cli.rb +6 -139
  11. data/lib/sunzi/command.rb +113 -0
  12. data/lib/sunzi/core_ext.rb +10 -0
  13. data/lib/sunzi/dependency.rb +26 -29
  14. data/lib/sunzi/endpoint.rb +17 -0
  15. data/lib/sunzi/plugin.rb +17 -0
  16. data/sunzi.gemspec +9 -9
  17. data/{lib/templates → templates}/create/.gitignore +0 -0
  18. data/{lib/templates → templates}/create/files/.gitkeep +0 -0
  19. data/{lib/templates → templates}/create/install.sh +13 -7
  20. data/{lib/templates → templates}/create/recipes/sunzi.sh +0 -0
  21. data/{lib/templates → templates}/create/roles/db.sh +0 -0
  22. data/{lib/templates → templates}/create/roles/web.sh +0 -0
  23. data/templates/create/sunzi.yml +27 -0
  24. data/templates/dependency/gemfile.erb +6 -0
  25. data/templates/dependency/install.erb +6 -0
  26. metadata +45 -36
  27. data/lib/sunzi/cloud.rb +0 -24
  28. data/lib/sunzi/cloud/base.rb +0 -98
  29. data/lib/sunzi/cloud/digital_ocean.rb +0 -78
  30. data/lib/sunzi/cloud/linode.rb +0 -154
  31. data/lib/sunzi/dns.rb +0 -25
  32. data/lib/sunzi/dns/base.rb +0 -7
  33. data/lib/sunzi/dns/linode.rb +0 -26
  34. data/lib/sunzi/dns/route53.rb +0 -25
  35. data/lib/sunzi/logger.rb +0 -17
  36. data/lib/sunzi/utility.rb +0 -17
  37. data/lib/templates/create/sunzi.yml +0 -30
  38. data/lib/templates/setup/digital_ocean/digital_ocean.yml +0 -28
  39. data/lib/templates/setup/linode/linode.yml +0 -42
  40. data/test/test_cli.rb +0 -40
@@ -0,0 +1,10 @@
1
+ class Object
2
+ def abort_with(text)
3
+ abort text.color(:red).bright
4
+ end
5
+
6
+ def exit_with(text)
7
+ puts text.color(:green).bright
8
+ exit
9
+ end
10
+ end
@@ -1,39 +1,36 @@
1
1
  module Sunzi
2
- class Dependency
3
- def self.all
4
- {
5
- 'linode' => { :require => 'linode', :version => '>= 0.7.9' },
6
- 'highline' => { :require => 'highline', :version => '>= 1.6.11'},
7
- 'route53' => { :require => 'route53', :version => '>= 0.2.1' },
8
- 'digital_ocean' => { :require => 'digital_ocean', :version => '>= 1.0.0' },
9
- }
10
- end
2
+ class Dependency < Struct.new(:name, :version)
3
+
4
+ @list = {}
11
5
 
12
- def self.load(name)
13
- begin
14
- gem(name, all[name][:version])
15
- require(all[name][:require])
16
- rescue LoadError
17
- if $!.to_s =~ /Gemfile/
18
- Logger.error <<-EOS
19
- Dependency missing: #{name}
20
- Add this line to your application's Gemfile.
6
+ def initialize(*args)
7
+ super
8
+ self.class.list[name] = self
9
+ end
21
10
 
22
- gem '#{name}', '#{all[name][:version]}'
11
+ class << self
12
+ attr_accessor :list
23
13
 
24
- Please try again after running "bundle install".
25
- EOS
26
- else
27
- Logger.error <<-EOS
28
- Dependency missing: #{name}
29
- To install the gem, issue the following command:
14
+ def load(key)
15
+ unless dependency = @list[key]
16
+ fail "#{key} is not initialized. Run Sunzi::Dependency.new('#{key}', '~> ...')"
17
+ end
30
18
 
31
- gem install #{name} -v '#{all[name][:version]}'
19
+ name, version = dependency.name, dependency.version
32
20
 
33
- Please try again after installing the missing dependency.
34
- EOS
21
+ begin
22
+ gem(name, version)
23
+ require(name)
24
+ rescue LoadError
25
+ base = GemRoot.join('templates/dependency')
26
+ which = if $!.to_s =~ /Gemfile/
27
+ 'gemfile'
28
+ else
29
+ 'install'
30
+ end
31
+ text = ERB.new(base.join("#{which}.erb").read, nil, '-').result(binding)
32
+ abort_with text
35
33
  end
36
- abort
37
34
  end
38
35
  end
39
36
  end
@@ -0,0 +1,17 @@
1
+ require 'net/ssh'
2
+
3
+ module Sunzi
4
+ class Endpoint
5
+ attr_reader :user, :host, :port
6
+
7
+ def initialize(input)
8
+ input.match(/(.*@)?(.*?)(:.*)?$/)
9
+ # Load ssh config if it exists
10
+ ssh = Net::SSH::Config.for($2)
11
+
12
+ @user = $1 && $1.delete('@') || ssh[:user] || 'root'
13
+ @host = ssh[:host_name] || $2
14
+ @port = $3 && $3.delete(':') || ssh[:port] && ssh[:port].to_s || '22'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Sunzi
2
+ module Plugin
3
+ class << self
4
+ # Find gems that start with "sunzi-*" and require them automatically.
5
+ # If that gem is a plugin, it will call the register method on load.
6
+
7
+ def load
8
+ plugins = Gem::Specification.find_all.select{|plugin| plugin.name =~ /sunzi-.+/ }
9
+ plugins.each do |plugin|
10
+ require plugin.name.gsub('-','/')
11
+
12
+ Sunzi.thor.source_paths << Pathname.new(plugin.gem_dir)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,22 +2,22 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'sunzi'
5
- spec.version = '1.5.2' # retrieve this value by: Gem.loaded_specs['sunzi'].version.to_s
5
+ spec.version = '2.0.0' # retrieve this value by: Gem.loaded_specs['sunzi'].version.to_s
6
6
  spec.authors = ['Kenn Ejima']
7
7
  spec.email = ['kenn.ejima@gmail.com']
8
- spec.homepage = 'http://github.com/kenn/sunzi'
9
8
  spec.summary = %q{Server provisioning utility for minimalists}
10
9
  spec.description = %q{Server provisioning utility for minimalists}
10
+ spec.homepage = 'https://github.com/kenn/sunzi'
11
11
  spec.license = 'MIT'
12
-
13
- spec.files = `git ls-files`.split($/)
14
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
12
+ spec.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) }
13
+ spec.bindir = 'exe'
14
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
16
15
  spec.require_paths = ['lib']
17
16
 
18
- spec.add_runtime_dependency 'thor'
19
- spec.add_runtime_dependency 'rainbow'
20
- spec.add_runtime_dependency 'net-ssh'
17
+ spec.add_dependency 'thor', '~> 0.20'
18
+ spec.add_dependency 'rainbow', '~> 2.2'
19
+ spec.add_dependency 'net-ssh', '< 5' # 4.x only supports ruby-2.0
20
+ spec.add_dependency 'hashugar'
21
21
  spec.add_development_dependency 'rake'
22
22
  spec.add_development_dependency 'minitest'
23
23
  end
@@ -1,5 +1,4 @@
1
1
  #!/bin/bash
2
- set -e
3
2
 
4
3
  # Load base utility functions like sunzi.mute() and sunzi.install()
5
4
  source recipes/sunzi.sh
@@ -8,9 +7,14 @@ source recipes/sunzi.sh
8
7
  # Remove if you're not on Debian/Ubuntu.
9
8
  export DEBIAN_FRONTEND=noninteractive
10
9
 
11
- # Add Dotdeb repository. Recommended if you're using Debian. See http://www.dotdeb.org/about/
12
- # source recipes/dotdeb.sh
13
- # source recipes/backports.sh
10
+ # Import initial SSH keys from Github
11
+ if [ -f ~/.ssh/authorized_keys ]; then
12
+ echo 'authorized_keys already exists'
13
+ else
14
+ mkdir -p ~/.ssh
15
+ wget -O - https://github.com/<%= @vars.github_username %>.keys > ~/.ssh/authorized_keys
16
+ chmod 600 ~/.ssh/authorized_keys
17
+ fi
14
18
 
15
19
  # Update apt catalog and upgrade installed packages
16
20
  sunzi.mute "apt-get update"
@@ -26,7 +30,7 @@ if sunzi.install "sysstat"; then
26
30
  fi
27
31
 
28
32
  # Set RAILS_ENV
29
- environment=<%= @attributes.environment %>
33
+ environment=<%= @vars.environment %>
30
34
 
31
35
  if ! grep -Fq "RAILS_ENV" ~/.bash_profile; then
32
36
  echo 'Setting up RAILS_ENV...'
@@ -34,9 +38,11 @@ if ! grep -Fq "RAILS_ENV" ~/.bash_profile; then
34
38
  source ~/.bash_profile
35
39
  fi
36
40
 
37
- # Install Ruby using RVM
41
+ # Install RVM using RVM recipe
38
42
  source recipes/rvm.sh
39
- ruby_version=<%= @attributes.ruby_version %>
43
+
44
+ # Install Ruby
45
+ ruby_version=<%= @vars.ruby_version %>
40
46
 
41
47
  if [[ "$(which ruby)" != /usr/local/rvm/rubies/ruby-$ruby_version* ]]; then
42
48
  echo "Installing ruby-$ruby_version"
@@ -0,0 +1,27 @@
1
+ ---
2
+ # Dynamic variables here will be accessible from shell scripts using ERB templates.
3
+ vars:
4
+ github_username: kenn
5
+ environment: production
6
+ ruby_version: 2.5
7
+
8
+ # Remote recipes here will be downloaded to compiled/recipes.
9
+ recipes:
10
+ rvm: https://raw.githubusercontent.com/kenn/sunzi-recipes/master/ruby/rvm.sh
11
+ # dotdeb: https://raw.githubusercontent.com/kenn/sunzi-recipes/master/debian/dotdeb-wheezy.sh
12
+ # backports: https://raw.githubusercontent.com/kenn/sunzi-recipes/master/debian/backports-wheezy.sh
13
+ # mongodb-10gen: https://raw.githubusercontent.com/kenn/sunzi-recipes/master/debian/mongodb-10gen.sh
14
+
15
+ # Files specified here will be copied to compiled/files.
16
+ # files:
17
+ # - ~/.ssh/id_rsa.pub
18
+
19
+ # Fine tune how Sunzi should work.
20
+ preferences:
21
+ # Erase the generated folder on the server after deploy.
22
+ # Turn on when you are done with testing and ready for production use.
23
+ erase_remote_folder: true
24
+
25
+ # Skip retrieving remote recipes when local copies already exist. This setting helps
26
+ # iterative deploy testing considerably faster, when you have a lot of remote recipes.
27
+ cache_remote_recipes: false
@@ -0,0 +1,6 @@
1
+ Dependency missing: <%= name %>
2
+ Add this line to your application's Gemfile.
3
+
4
+ gem '<%= name %>', '<%= version %>'
5
+
6
+ Please try again after running "bundle install".
@@ -0,0 +1,6 @@
1
+ Dependency missing: <%= name %>
2
+ To install the gem, issue the following command:
3
+
4
+ gem install <%= name %> -v '<%= version %>'
5
+
6
+ Please try again after installing the missing dependency.
metadata CHANGED
@@ -1,45 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunzi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenn Ejima
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-05-19 00:00:00.000000000 Z
11
+ date: 2018-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '0.20'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '0.20'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rainbow
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '2.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: net-ssh
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hashugar
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
@@ -94,32 +108,28 @@ files:
94
108
  - Gemfile
95
109
  - README.md
96
110
  - Rakefile
97
- - bin/sunzi
111
+ - bin/console
112
+ - bin/setup
113
+ - exe/sunzi
98
114
  - lib/sunzi.rb
115
+ - lib/sunzi/actions.rb
99
116
  - lib/sunzi/cli.rb
100
- - lib/sunzi/cloud.rb
101
- - lib/sunzi/cloud/base.rb
102
- - lib/sunzi/cloud/digital_ocean.rb
103
- - lib/sunzi/cloud/linode.rb
117
+ - lib/sunzi/command.rb
118
+ - lib/sunzi/core_ext.rb
104
119
  - lib/sunzi/dependency.rb
105
- - lib/sunzi/dns.rb
106
- - lib/sunzi/dns/base.rb
107
- - lib/sunzi/dns/linode.rb
108
- - lib/sunzi/dns/route53.rb
109
- - lib/sunzi/logger.rb
110
- - lib/sunzi/utility.rb
111
- - lib/templates/create/.gitignore
112
- - lib/templates/create/files/.gitkeep
113
- - lib/templates/create/install.sh
114
- - lib/templates/create/recipes/sunzi.sh
115
- - lib/templates/create/roles/db.sh
116
- - lib/templates/create/roles/web.sh
117
- - lib/templates/create/sunzi.yml
118
- - lib/templates/setup/digital_ocean/digital_ocean.yml
119
- - lib/templates/setup/linode/linode.yml
120
+ - lib/sunzi/endpoint.rb
121
+ - lib/sunzi/plugin.rb
120
122
  - sunzi.gemspec
121
- - test/test_cli.rb
122
- homepage: http://github.com/kenn/sunzi
123
+ - templates/create/.gitignore
124
+ - templates/create/files/.gitkeep
125
+ - templates/create/install.sh
126
+ - templates/create/recipes/sunzi.sh
127
+ - templates/create/roles/db.sh
128
+ - templates/create/roles/web.sh
129
+ - templates/create/sunzi.yml
130
+ - templates/dependency/gemfile.erb
131
+ - templates/dependency/install.erb
132
+ homepage: https://github.com/kenn/sunzi
123
133
  licenses:
124
134
  - MIT
125
135
  metadata: {}
@@ -139,9 +149,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
149
  version: '0'
140
150
  requirements: []
141
151
  rubyforge_project:
142
- rubygems_version: 2.2.2
152
+ rubygems_version: 2.7.3
143
153
  signing_key:
144
154
  specification_version: 4
145
155
  summary: Server provisioning utility for minimalists
146
- test_files:
147
- - test/test_cli.rb
156
+ test_files: []
@@ -1,24 +0,0 @@
1
- module Sunzi
2
- class Cloud
3
- include Sunzi::Utility
4
-
5
- def initialize(cli, provider)
6
- @subject = case provider
7
- when 'linode'
8
- Sunzi::Cloud::Linode.new(cli, provider)
9
- when 'digital_ocean'
10
- Sunzi::Cloud::DigitalOcean.new(cli, provider)
11
- else
12
- abort_with "Provider #{provider} is not valid!"
13
- end
14
- end
15
-
16
- def method_missing(sym, *args, &block)
17
- @subject.send sym, *args, &block
18
- end
19
-
20
- def respond_to?(method)
21
- @subject.respond_to?(sym) || super
22
- end
23
- end
24
- end
@@ -1,98 +0,0 @@
1
- Sunzi::Dependency.load('highline')
2
-
3
- module Sunzi
4
- class Cloud
5
- class Base
6
- include Sunzi::Utility
7
-
8
- def initialize(cli, provider)
9
- @provider = provider
10
- @cli = cli
11
- @ui = HighLine.new
12
- end
13
-
14
- def setup
15
- unless File.exist? provider_config_path
16
- @cli.empty_directory "#{@provider}/instances"
17
- @cli.template "templates/setup/#{provider_config_path}", provider_config_path
18
- exit_with "Now go ahead and edit #{@provider}.yml, then run this command again!"
19
- end
20
-
21
- assign_config_and_dns
22
-
23
- if @config['fqdn']['zone'] == 'example.com'
24
- abort_with "You must have your own settings in #{@provider}.yml"
25
- end
26
-
27
- # Ask environment and hostname
28
- @env = ask("environment? (#{@config['environments'].join(' / ')}): ", String) {|q| q.in = @config['environments'] }.to_s
29
- @host = ask('hostname? (only the first part of subdomain): ', String).to_s
30
-
31
- abort_with '"label" field in linode.yml is no longer supported. rename it to "name".' if @config['label']
32
- @fqdn = @config['fqdn'][@env].gsub(/%{host}/, @host)
33
- @name = @config['name'][@env].gsub(/%{host}/, @host)
34
- abort_with "#{@name} already exists!" if instance_config_path.exist?
35
-
36
- assign_api
37
- @attributes = {}
38
- do_setup
39
-
40
- # Save instance info
41
- @cli.create_file instance_config_path, YAML.dump(@instance)
42
-
43
- # Register IP to DNS
44
- @dns.add(@fqdn, @public_ip) if @dns
45
- end
46
-
47
- def teardown
48
- names = Dir.glob("#{@provider}/instances/*.yml").map{|i| i.split('/').last.sub('.yml','') }
49
- abort_with "No match found with #{@provider}/instances/*.yml" if names.empty?
50
-
51
- names.each{|i| say i }
52
- @name = ask("which instance?: ", String) {|q| q.in = names }
53
-
54
- assign_config_and_dns
55
-
56
- @instance = YAML.load(instance_config_path.read)
57
-
58
- # Are you sure?
59
- moveon = ask("Are you sure about deleting #{@instance[:fqdn]} permanently? (y/n) ", String) {|q| q.in = ['y','n']}
60
- exit unless moveon == 'y'
61
-
62
- # Run Linode / DigitalOcean specific tasks
63
- assign_api
64
- do_teardown
65
-
66
- # Delete DNS record
67
- @dns.delete(@instance[ip_key]) if @dns
68
-
69
- # Remove the instance config file
70
- @cli.remove_file instance_config_path
71
-
72
- say 'Done.'
73
- end
74
-
75
- def assign_config_and_dns
76
- @config = YAML.load(provider_config_path.read)
77
- @dns = Sunzi::DNS.new(@config, @provider) if @config['dns']
78
- end
79
-
80
- def provider_config_path
81
- Pathname.new "#{@provider}/#{@provider}.yml"
82
- end
83
-
84
- def instance_config_path
85
- Pathname.new "#{@provider}/instances/#{@name}.yml"
86
- end
87
-
88
- def ask(question, answer_type, &details)
89
- @ui.ask(@ui.color(question, :green, :bold), answer_type, &details)
90
- end
91
-
92
- def proceed?
93
- moveon = ask("Are you ready to go ahead and create #{@fqdn}? (y/n) ", String) {|q| q.in = ['y','n']}
94
- exit unless moveon == 'y'
95
- end
96
- end
97
- end
98
- end