sunzi 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Sunzi for Linode](http://farm8.staticflickr.com/7210/6783789868_ab89010d5c.jpg)
|
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
|