sunzi 0.3.0 → 0.4.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.
- data/README.md +21 -11
- data/bin/sunzi +1 -0
- data/lib/sunzi.rb +10 -1
- data/lib/sunzi/cli.rb +13 -6
- data/lib/sunzi/cloud/base.rb +38 -0
- data/lib/sunzi/cloud/ec2.rb +15 -0
- data/lib/sunzi/cloud/linode.rb +248 -0
- data/lib/sunzi/dependency.rb +38 -0
- data/lib/sunzi/version.rb +1 -1
- data/lib/templates/{remote → create/remote}/install.sh +0 -0
- data/lib/templates/{remote → create/remote}/recipes/ssh_key.sh +0 -0
- data/lib/templates/{sunzi.yml → create/sunzi.yml} +0 -0
- data/lib/templates/setup/linode/linode.yml +34 -0
- metadata +12 -8
- data/lib/sunzi/base.rb +0 -9
data/README.md
CHANGED
@@ -27,7 +27,7 @@ Go to your project directory, then:
|
|
27
27
|
|
28
28
|
$ sunzi create
|
29
29
|
|
30
|
-
It generates a `sunzi` folder along with subdirectories and templates. Inside `sunzi`, there's `
|
30
|
+
It generates a `sunzi` folder along with subdirectories and templates. Inside `sunzi`, there's `sunzi.yml`, which defines dynamic attributes to be used from recipes. Also there's the `remote` folder, which will be transferred to the remote server, that contains recipes and dynamic variables compiled from `sunzi.yml`.
|
31
31
|
|
32
32
|
Go into the `sunzi` directory, then run the `sunzi deploy`:
|
33
33
|
|
@@ -38,7 +38,7 @@ Now, what it actually does is:
|
|
38
38
|
|
39
39
|
1. SSH to `example.com` and login as `root`
|
40
40
|
1. Transfer the content of the `remote` directory to the remote server and extract in `$HOME/sunzi`
|
41
|
-
1. Run `install.sh`
|
41
|
+
1. Run `install.sh` on the remote server
|
42
42
|
|
43
43
|
As you can see, what you need to do is edit `install.sh` and add some shell commands. That's it.
|
44
44
|
|
@@ -61,13 +61,13 @@ sunzi/
|
|
61
61
|
How do you pass dynamic values to a recipe?
|
62
62
|
-------------------------------------------
|
63
63
|
|
64
|
-
In the compile phase, `
|
64
|
+
In the compile phase, attributes defined in `sunzi.yml` are split into multiple files, one per attribute. We use filesystem as a sort of key-value storage so that it's easy to use from shell scripts.
|
65
65
|
|
66
66
|
The convention for argument passing to a recipe is to use `$1`, `$2`, etc. and put a comment line for each argument.
|
67
67
|
|
68
68
|
For instance, given a recipe `greeting.sh`:
|
69
69
|
|
70
|
-
```
|
70
|
+
```bash
|
71
71
|
# Greeting
|
72
72
|
# $1: Name for goodbye
|
73
73
|
# $2: Name for hello
|
@@ -77,14 +77,14 @@ echo "Goodbye $1, Hello $2!"
|
|
77
77
|
|
78
78
|
With `attributes.yml`:
|
79
79
|
|
80
|
-
```
|
80
|
+
```yaml
|
81
81
|
goodbye: Chef
|
82
82
|
hello: Sunzi
|
83
83
|
```
|
84
84
|
|
85
85
|
Then, include the recipe in `install.sh`:
|
86
86
|
|
87
|
-
```
|
87
|
+
```bash
|
88
88
|
source recipes/greeting.sh $(cat attributes/goodbye) $(cat attributes/hello)
|
89
89
|
```
|
90
90
|
|
@@ -97,16 +97,26 @@ Goodbye Chef, Hello Sunzi!
|
|
97
97
|
Remote Recipes
|
98
98
|
--------------
|
99
99
|
|
100
|
-
Recipes can be retrieved remotely via HTTP. Put a URL in `
|
100
|
+
Recipes can be retrieved remotely via HTTP. Put a URL in the recipes section of `sunzi.yml`, and Sunzi will automatically load the content and put it into the `remote/recipes` folder in the compile phase.
|
101
101
|
|
102
|
-
For instance, if you have the following line in `
|
102
|
+
For instance, if you have the following line in `sunzi.yml`,
|
103
103
|
|
104
|
-
```
|
105
|
-
|
104
|
+
```yaml
|
105
|
+
recipes:
|
106
|
+
rvm: https://raw.github.com/kenn/sunzi-recipes/master/ruby/rvm.sh
|
106
107
|
```
|
107
108
|
|
108
109
|
`rvm.sh` will be available and you can refer to that recipe by `source recipes/rvm.sh`.
|
109
110
|
|
111
|
+
Cloud Support
|
112
|
+
-------------
|
113
|
+
|
114
|
+
You can setup a new VM / teardown an existing VM interactively. Use `sunzi setup` and `sunzi teardown` for that.
|
115
|
+
|
116
|
+
The following screenshot says it all.
|
117
|
+
|
118
|
+

|
119
|
+
|
110
120
|
Vagrant
|
111
121
|
-------
|
112
122
|
|
@@ -124,7 +134,7 @@ end
|
|
124
134
|
|
125
135
|
with `chpasswd.sh`:
|
126
136
|
|
127
|
-
```
|
137
|
+
```bash
|
128
138
|
#!/bin/bash
|
129
139
|
|
130
140
|
sudo echo 'root:vagrant' | /usr/sbin/chpasswd
|
data/bin/sunzi
CHANGED
data/lib/sunzi.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
LIB_PATH = File.join(File.dirname(__FILE__), 'sunzi')
|
2
2
|
|
3
|
+
require 'thor'
|
4
|
+
require 'yaml'
|
5
|
+
|
3
6
|
module Sunzi
|
4
|
-
autoload :Base, File.join(LIB_PATH, 'base')
|
5
7
|
autoload :Cli, File.join(LIB_PATH, 'cli')
|
8
|
+
autoload :Dependency, File.join(LIB_PATH, 'dependency')
|
6
9
|
autoload :Version, File.join(LIB_PATH, 'version')
|
10
|
+
|
11
|
+
module Cloud
|
12
|
+
autoload :Base, File.join(LIB_PATH, 'cloud', 'base')
|
13
|
+
autoload :Linode, File.join(LIB_PATH, 'cloud', 'linode')
|
14
|
+
autoload :EC2, File.join(LIB_PATH, 'cloud', 'ec2')
|
15
|
+
end
|
7
16
|
end
|
data/lib/sunzi/cli.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'thor'
|
2
|
-
require 'yaml'
|
3
|
-
require 'fileutils'
|
4
1
|
require 'open3'
|
5
2
|
|
6
3
|
module Sunzi
|
@@ -23,9 +20,9 @@ module Sunzi
|
|
23
20
|
empty_directory project
|
24
21
|
empty_directory "#{project}/remote"
|
25
22
|
empty_directory "#{project}/remote/recipes"
|
26
|
-
template "templates/sunzi.yml", "#{project}/sunzi.yml"
|
27
|
-
template "templates/remote/install.sh", "#{project}/remote/install.sh"
|
28
|
-
template "templates/remote/recipes/ssh_key.sh", "#{project}/remote/recipes/ssh_key.sh"
|
23
|
+
template "templates/create/sunzi.yml", "#{project}/sunzi.yml"
|
24
|
+
template "templates/create/remote/install.sh", "#{project}/remote/install.sh"
|
25
|
+
template "templates/create/remote/recipes/ssh_key.sh", "#{project}/remote/recipes/ssh_key.sh"
|
29
26
|
end
|
30
27
|
|
31
28
|
desc "deploy example.com (or user@example.com:2222)", "Deploy sunzi project"
|
@@ -87,6 +84,16 @@ module Sunzi
|
|
87
84
|
end
|
88
85
|
end
|
89
86
|
|
87
|
+
desc "setup [linode|ec2]", "Setup a new VM"
|
88
|
+
def setup(target)
|
89
|
+
Cloud::Base.choose(target).setup
|
90
|
+
end
|
91
|
+
|
92
|
+
desc "teardown [linode|ec2] [name]", "Teardown an existing VM"
|
93
|
+
def teardown(target, name)
|
94
|
+
Cloud::Base.choose(target).teardown(name)
|
95
|
+
end
|
96
|
+
|
90
97
|
no_tasks do
|
91
98
|
def parse_target(target)
|
92
99
|
target.match(/(.*@)?(.*?)(:.*)?$/)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Sunzi::Dependency.load('highline')
|
2
|
+
|
3
|
+
module Sunzi
|
4
|
+
module Cloud
|
5
|
+
class Base < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def source_root
|
10
|
+
File.expand_path('../../../',__FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
def choose(target)
|
14
|
+
case target
|
15
|
+
when 'linode'
|
16
|
+
Cloud::Linode.new
|
17
|
+
when 'ec2'
|
18
|
+
Cloud::EC2.new
|
19
|
+
else
|
20
|
+
say shell.set_color("#{target} is not valid!", :red, true)
|
21
|
+
abort
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(*args)
|
27
|
+
@ui = HighLine.new
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
no_tasks do
|
32
|
+
def ask(question, answer_type, &details)
|
33
|
+
@ui.ask(@ui.color(question, :green, :bold), answer_type, &details)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sunzi
|
2
|
+
module Cloud
|
3
|
+
class EC2 < Base
|
4
|
+
no_tasks do
|
5
|
+
def setup
|
6
|
+
say shell.set_color('EC2 is not implemented yet!', :red, true)
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown(target)
|
10
|
+
say shell.set_color('EC2 is not implemented yet!', :red, true)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
Sunzi::Dependency.load('linode')
|
2
|
+
|
3
|
+
# Workaround the bug: https://github.com/rick/linode/issues/12
|
4
|
+
YAML::ENGINE.yamler = 'syck'
|
5
|
+
|
6
|
+
module Sunzi
|
7
|
+
module Cloud
|
8
|
+
class Linode < Base
|
9
|
+
no_tasks do
|
10
|
+
|
11
|
+
def setup
|
12
|
+
# Only run for the first time
|
13
|
+
unless File.exist? 'linode/linode.yml'
|
14
|
+
empty_directory 'linode'
|
15
|
+
empty_directory 'linode/instances'
|
16
|
+
template 'templates/setup/linode/linode.yml', 'linode/linode.yml'
|
17
|
+
say shell.set_color('Now go ahead and edit linode.yml, then run this command again!', :green, true)
|
18
|
+
abort
|
19
|
+
end
|
20
|
+
|
21
|
+
@config = YAML.load(File.read('linode/linode.yml'))
|
22
|
+
|
23
|
+
if @config['fqdn']['zone'] == 'example.com'
|
24
|
+
say shell.set_color('You must have your own settings in linode.yml', :red, true)
|
25
|
+
abort
|
26
|
+
end
|
27
|
+
|
28
|
+
# When route53 is specified for DNS, check if it's properly configured and if not, fail earlier.
|
29
|
+
setup_route53 if @config['dns'] == 'route53'
|
30
|
+
|
31
|
+
@ui = HighLine.new
|
32
|
+
|
33
|
+
@sshkey = File.read(File.expand_path(@config['root_sshkey_path'])).chomp
|
34
|
+
if @sshkey.match(/\n/)
|
35
|
+
say shell.set_color("RootSSHKey #{@sshkey.inspect} must not be multi-line! Check inside \"#{@config['root_sshkey_path']}\"", :red, true)
|
36
|
+
abort
|
37
|
+
end
|
38
|
+
|
39
|
+
# Ask environment and hostname
|
40
|
+
@env = ask("environment? (#{@config['environments'].join(' / ')}): ", String) {|q| q.in = @config['environments'] }.to_s
|
41
|
+
@host = ask('hostname? (only the last part of subdomain): ', String).to_s
|
42
|
+
|
43
|
+
@fqdn = @config['fqdn'][@env].gsub(/%{host}/, @host)
|
44
|
+
@label = @config['label'][@env].gsub(/%{host}/, @host)
|
45
|
+
@group = @config['group'][@env]
|
46
|
+
@api = ::Linode.new(:api_key => @config['api_key'])
|
47
|
+
|
48
|
+
# Choose a plan
|
49
|
+
result = @api.avail.linodeplans
|
50
|
+
result.each{|i| say "#{i.planid}: #{i.ram}MB, $#{i.price}" }
|
51
|
+
@planid = ask('which plan?: ', Integer) {|q| q.in = result.map(&:planid); q.default = result.first.planid }
|
52
|
+
@plan_label = result.find{|i| i.planid == @planid }.label
|
53
|
+
|
54
|
+
# Choose a datacenter
|
55
|
+
result = @api.avail.datacenters
|
56
|
+
result.each{|i| say "#{i.datacenterid}: #{i.location}" }
|
57
|
+
@datacenterid = ask('which datacenter?: ', Integer) {|q| q.in = result.map(&:datacenterid); q.default = result.first.datacenterid }
|
58
|
+
@datacenter_location = result.find{|i| i.datacenterid == @datacenterid }.location
|
59
|
+
|
60
|
+
# Choose a distribution
|
61
|
+
result = @api.avail.distributions
|
62
|
+
if @config['distributions_filter']
|
63
|
+
result = result.select{|i| i.label.match Regexp.new(@config['distributions_filter'], Regexp::IGNORECASE) }
|
64
|
+
end
|
65
|
+
result.each{|i| say "#{i.distributionid}: #{i.label}" }
|
66
|
+
@distributionid = ask('which distribution?: ', Integer) {|q| q.in = result.map(&:distributionid); q.default = result.first.distributionid }
|
67
|
+
@distribution_label = result.find{|i| i.distributionid == @distributionid }.label
|
68
|
+
|
69
|
+
# Choose a kernel
|
70
|
+
result = @api.avail.kernels
|
71
|
+
if @config['kernels_filter']
|
72
|
+
result = result.select{|i| i.label.match Regexp.new(@config['kernels_filter'], Regexp::IGNORECASE) }
|
73
|
+
end
|
74
|
+
result.each{|i| say "#{i.kernelid}: #{i.label}" }
|
75
|
+
@kernelid = ask('which kernel?: ', Integer) {|q| q.in = result.map(&:kernelid); q.default = result.first.kernelid }
|
76
|
+
@kernel_label = result.find{|i| i.kernelid == @kernelid }.label
|
77
|
+
|
78
|
+
# Choose swap size
|
79
|
+
@swap_size = ask('swap size in MB? (default: 256MB): ', Integer) { |q| q.default = 256 }
|
80
|
+
|
81
|
+
# Go ahead?
|
82
|
+
moveon = ask("Are you sure to go ahead and create #{@fqdn}? (y/n) ", String) {|q| q.in = ['y','n']}
|
83
|
+
exit unless moveon == 'y'
|
84
|
+
|
85
|
+
# Create
|
86
|
+
say "creating a new linode..."
|
87
|
+
result = @api.linode.create(:DatacenterID => @datacenterid, :PlanID => @planid, :PaymentTerm => @config['payment_term'])
|
88
|
+
@linodeid = result.linodeid
|
89
|
+
say "created a new instance: linodeid = #{@linodeid}"
|
90
|
+
|
91
|
+
result = @api.linode.list.select{|i| i.linodeid == @linodeid }.first
|
92
|
+
@totalhd = result.totalhd
|
93
|
+
|
94
|
+
# Update settings
|
95
|
+
say "Updating settings..."
|
96
|
+
result = @api.linode.update(
|
97
|
+
:LinodeID => @linodeid,
|
98
|
+
:Label => @label,
|
99
|
+
:lpm_displayGroup => @group,
|
100
|
+
# :Alert_cpu_threshold => 90,
|
101
|
+
# :Alert_diskio_threshold => 1000,
|
102
|
+
# :Alert_bwin_threshold => 5,
|
103
|
+
# :Alert_bwout_threshold => 5,
|
104
|
+
# :Alert_bwquota_threshold => 80,
|
105
|
+
)
|
106
|
+
|
107
|
+
# Create a root disk
|
108
|
+
say "Creating a root disk..."
|
109
|
+
result = @api.linode.disk.createfromdistribution(
|
110
|
+
:LinodeID => @linodeid,
|
111
|
+
:DistributionID => @distributionid,
|
112
|
+
:Label => "#{@distribution_label} Image",
|
113
|
+
:Size => @totalhd - @swap_size,
|
114
|
+
:rootPass => @config['root_pass'],
|
115
|
+
:rootSSHKey => @sshkey
|
116
|
+
)
|
117
|
+
@root_diskid = result.diskid
|
118
|
+
|
119
|
+
# Create a swap disk
|
120
|
+
say "Creating a swap disk..."
|
121
|
+
result = @api.linode.disk.create(
|
122
|
+
:LinodeID => @linodeid,
|
123
|
+
:Label => "#{@swap_size}MB Swap Image",
|
124
|
+
:Type => 'swap',
|
125
|
+
:Size => @swap_size
|
126
|
+
)
|
127
|
+
@swap_diskid = result.diskid
|
128
|
+
|
129
|
+
# Create a config profiile
|
130
|
+
say "Creating a config profile..."
|
131
|
+
result = @api.linode.config.create(
|
132
|
+
:LinodeID => @linodeid,
|
133
|
+
:KernelID => @kernelid,
|
134
|
+
:Label => "#{@distribution_label} Profile",
|
135
|
+
:DiskList => [ @root_diskid, @swap_diskid ].join(',')
|
136
|
+
)
|
137
|
+
@config_id = result.configid
|
138
|
+
|
139
|
+
# Add a private IP
|
140
|
+
say "Adding a private IP..."
|
141
|
+
result = @api.linode.ip.list(:LinodeID => @linodeid)
|
142
|
+
@public_ip = result.first.ipaddress
|
143
|
+
result = @api.linode.ip.addprivate(:LinodeID => @linodeid)
|
144
|
+
result = @api.linode.ip.list(:LinodeID => @linodeid).find{|i| i.ispublic == 0 }
|
145
|
+
@private_ip = result.ipaddress
|
146
|
+
|
147
|
+
# Register IP to DNS
|
148
|
+
case @config['dns']
|
149
|
+
when 'linode'
|
150
|
+
# Set the public IP to Linode DNS Manager
|
151
|
+
say "Setting the public IP to Linode DNS Manager..."
|
152
|
+
@domainid = @api.domain.list.find{|i| i.domain == @config['fqdn']['zone'] }.domainid
|
153
|
+
@api.domain.resource.create(:DomainID => @domainid, :Type => 'A', :Name => @fqdn, :Target => @public_ip)
|
154
|
+
when 'route53'
|
155
|
+
# Set the public IP to AWS Route 53
|
156
|
+
say "Setting the public IP to AWS Route 53..."
|
157
|
+
Route53::DNSRecord.new(@fqdn, "A", "300", [@public_ip], @route53_zone).create
|
158
|
+
end
|
159
|
+
|
160
|
+
# Boot
|
161
|
+
say shell.set_color("Done. Booting...", :green, true)
|
162
|
+
@api.linode.boot(:LinodeID => @linodeid)
|
163
|
+
|
164
|
+
hash = {
|
165
|
+
:linode_id => @linodeid,
|
166
|
+
:env => @env,
|
167
|
+
:host => @host,
|
168
|
+
:fqdn => @fqdn,
|
169
|
+
:label => @label,
|
170
|
+
:group => @group,
|
171
|
+
:plan_id => @planid,
|
172
|
+
:datacenter_id => @datacenterid,
|
173
|
+
:datacenter_location => @datacenter_location,
|
174
|
+
:distribution_id => @distributionid,
|
175
|
+
:distribution_label => @distribution_label,
|
176
|
+
:kernel_id => @kernelid,
|
177
|
+
:kernel_label => @kernel_label,
|
178
|
+
:swap_size => @swap_size,
|
179
|
+
:totalhd => @totalhd,
|
180
|
+
:root_diskid => @root_diskid,
|
181
|
+
:swap_diskid => @swap_diskid,
|
182
|
+
:config_id => @config_id,
|
183
|
+
:public_ip => @public_ip,
|
184
|
+
:private_ip => @private_ip,
|
185
|
+
}
|
186
|
+
|
187
|
+
File.open("linode/instances/#{@label}.yml",'w') do |file|
|
188
|
+
file.write YAML.dump(hash)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def teardown(name)
|
193
|
+
unless File.exist?("linode/instances/#{name}.yml")
|
194
|
+
say shell.set_color("#{name}.yml was not found in the instances directory.", :red, true)
|
195
|
+
abort
|
196
|
+
end
|
197
|
+
@config = YAML.load(File.read('linode/linode.yml'))
|
198
|
+
setup_route53 if @config['dns'] == 'route53'
|
199
|
+
|
200
|
+
@instance = YAML.load(File.read("linode/instances/#{name}.yml"))
|
201
|
+
@api = ::Linode.new(:api_key => @config['api_key'])
|
202
|
+
|
203
|
+
# Shutdown first or disk deletion will fail
|
204
|
+
say shell.set_color("shutting down...", :green, true)
|
205
|
+
@api.linode.shutdown(:LinodeID => @instance[:linode_id])
|
206
|
+
sleep 10
|
207
|
+
|
208
|
+
# Delete the disks. It is required - http://www.linode.com/api/linode/linode%2Edelete
|
209
|
+
say shell.set_color("deleting root disk...", :green, true)
|
210
|
+
@api.linode.disk.delete(:LinodeID => @instance[:linode_id], :DiskID => @instance[:root_diskid]) rescue nil
|
211
|
+
say shell.set_color("deleting swap disk...", :green, true)
|
212
|
+
@api.linode.disk.delete(:LinodeID => @instance[:linode_id], :DiskID => @instance[:swap_diskid]) rescue nil
|
213
|
+
sleep 5
|
214
|
+
|
215
|
+
# Delete the instance
|
216
|
+
say shell.set_color("deleting linode...", :green, true)
|
217
|
+
@api.linode.delete(:LinodeID => @instance[:linode_id])
|
218
|
+
|
219
|
+
# Delete DNS record
|
220
|
+
case @config['dns']
|
221
|
+
when 'linode'
|
222
|
+
# Set the public IP to Linode DNS Manager
|
223
|
+
say "deleting the public IP to Linode DNS Manager..."
|
224
|
+
@domainid = @api.domain.list.find{|i| i.domain == @config['fqdn']['zone'] }.domainid
|
225
|
+
@resource = @api.domain.resource.list(:DomainID => @domainid).find{|i| i.target == @instance[:public_ip] }
|
226
|
+
@api.domain.resource.delete(:DomainID => @domainid, :ResourceID => @resource.resourceid)
|
227
|
+
when 'route53'
|
228
|
+
# Set the public IP to AWS Route 53
|
229
|
+
say "deleting the public IP to AWS Route 53..."
|
230
|
+
@record = @route53_zone.get_records.find{|i| i.values.first == @instance[:public_ip] }
|
231
|
+
@record.delete
|
232
|
+
end
|
233
|
+
|
234
|
+
# Remove the instance config file
|
235
|
+
remove_file "linode/instances/#{name}.yml"
|
236
|
+
|
237
|
+
say shell.set_color("Done.", :green, true)
|
238
|
+
end
|
239
|
+
|
240
|
+
def setup_route53
|
241
|
+
Sunzi::Dependency.load('route53')
|
242
|
+
route53 = Route53::Connection.new(@config['route53']['key'], @config['route53']['secret'])
|
243
|
+
@route53_zone = route53.get_zones.find{|i| i.name.sub(/\.$/,'') == @config['fqdn']['zone'] }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Sunzi
|
2
|
+
class Dependency
|
3
|
+
def self.all
|
4
|
+
{
|
5
|
+
'linode' => {
|
6
|
+
:require => 'linode',
|
7
|
+
:version => '>= 0.7.7',
|
8
|
+
},
|
9
|
+
'highline' => {
|
10
|
+
:require => 'highline',
|
11
|
+
:version => '>= 1.6.11',
|
12
|
+
},
|
13
|
+
'route53' => {
|
14
|
+
:require => 'route53',
|
15
|
+
:version => '>= 0.2.1',
|
16
|
+
},
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load(name)
|
21
|
+
begin
|
22
|
+
gem(name, all[name][:version])
|
23
|
+
require(all[name][:require])
|
24
|
+
rescue LoadError
|
25
|
+
puts <<-EOS
|
26
|
+
Dependency missing: #{name}
|
27
|
+
To install the gem, issue the following command:
|
28
|
+
|
29
|
+
gem install #{name} -v '#{all[name][:version]}'
|
30
|
+
|
31
|
+
Please try again after installing the missing dependency.
|
32
|
+
EOS
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/sunzi/version.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
---
|
2
|
+
api_key: your_api_key
|
3
|
+
root_pass: your_root_password
|
4
|
+
root_sshkey_path: ~/.ssh/id_rsa.pub
|
5
|
+
|
6
|
+
# payment_term must be 1, 12 or 24
|
7
|
+
payment_term: 1
|
8
|
+
|
9
|
+
# Add / remove environments
|
10
|
+
environments:
|
11
|
+
- production
|
12
|
+
- staging
|
13
|
+
fqdn:
|
14
|
+
zone: example.com
|
15
|
+
production: %{host}.example.com
|
16
|
+
staging: %{host}.staging.example.com
|
17
|
+
label:
|
18
|
+
production: example-%{host}
|
19
|
+
staging: example-staging-%{host}
|
20
|
+
group:
|
21
|
+
production: example
|
22
|
+
staging: example-staging
|
23
|
+
|
24
|
+
# Filter out large lists by keyword
|
25
|
+
distributions_filter: debian
|
26
|
+
kernels_filter: latest
|
27
|
+
|
28
|
+
# dns takes either "linode" or "route53"
|
29
|
+
dns: linode
|
30
|
+
|
31
|
+
# only used when route53 is chosen for DNS
|
32
|
+
route53:
|
33
|
+
key: your_aws_key
|
34
|
+
secret: your_aws_secret
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunzi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156460860 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156460860
|
25
25
|
description: Server provisioning utility for minimalists
|
26
26
|
email:
|
27
27
|
- kenn.ejima@gmail.com
|
@@ -36,12 +36,16 @@ files:
|
|
36
36
|
- Rakefile
|
37
37
|
- bin/sunzi
|
38
38
|
- lib/sunzi.rb
|
39
|
-
- lib/sunzi/base.rb
|
40
39
|
- lib/sunzi/cli.rb
|
40
|
+
- lib/sunzi/cloud/base.rb
|
41
|
+
- lib/sunzi/cloud/ec2.rb
|
42
|
+
- lib/sunzi/cloud/linode.rb
|
43
|
+
- lib/sunzi/dependency.rb
|
41
44
|
- lib/sunzi/version.rb
|
42
|
-
- lib/templates/remote/install.sh
|
43
|
-
- lib/templates/remote/recipes/ssh_key.sh
|
44
|
-
- lib/templates/sunzi.yml
|
45
|
+
- lib/templates/create/remote/install.sh
|
46
|
+
- lib/templates/create/remote/recipes/ssh_key.sh
|
47
|
+
- lib/templates/create/sunzi.yml
|
48
|
+
- lib/templates/setup/linode/linode.yml
|
45
49
|
- sunzi.gemspec
|
46
50
|
- test/test_cli.rb
|
47
51
|
homepage: http://github.com/kenn/sunzi
|