some 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +112 -0
- data/Rakefile +1 -1
- data/TODO +5 -2
- data/VERSION +1 -1
- data/bin/some +20 -37
- data/lib/some.rb +80 -56
- metadata +10 -10
- data/README.rdoc +0 -123
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# some - sumo clone for NIFTY Cloud
|
2
|
+
|
3
|
+
## 概要
|
4
|
+
|
5
|
+
[adamwiggins/sumo](http://github.com/adamwiggins/sumo) の NIFTY Cloud バージョンです。
|
6
|
+
NIFTY Cloud 上で手軽にサーバーを立ち上げることができます。
|
7
|
+
|
8
|
+
$ some launch
|
9
|
+
---> Launch instance... 4acef29d (7.9s)
|
10
|
+
---> Acquire hostname... XXX.XXX.XXX.XXX (79.2s)
|
11
|
+
---> Wait for ssh... done (0.0s)
|
12
|
+
|
13
|
+
Logging you in via ssh. Type 'exit' or Ctrl-D to return to your local system.
|
14
|
+
------------------------------------------------------------------------------
|
15
|
+
Enter passphrase for key '/home/tily/.some/keypair.pem':
|
16
|
+
[root@localhost ~]#
|
17
|
+
|
18
|
+
要らなくなったらすぐに削除できます。
|
19
|
+
|
20
|
+
$ some terminate XXX.XXX.XXX.XXX
|
21
|
+
---> Wait to stop... done (16.2s)
|
22
|
+
XXX.XXX.XXX.XXX scheduled for termination
|
23
|
+
|
24
|
+
一覧を取得して SSH ログインしたりも簡単にできます。
|
25
|
+
|
26
|
+
$ some list
|
27
|
+
XXX.XXX.XXX.XXX 21b61298 running
|
28
|
+
YYY.YYY.YYY.YYY 923d7772 running
|
29
|
+
ZZZ.ZZZ.ZZZ.ZZZ dec83cd3 running
|
30
|
+
$ some ssh 21b61298
|
31
|
+
Enter passphrase for key '/home/tily/.some/keypair.pem':
|
32
|
+
Last login: Fri Apr 5 16:24:02 2013 from AAA.AAA.AAA.AAA
|
33
|
+
[root@localhost ~]#
|
34
|
+
|
35
|
+
## インストール・設定
|
36
|
+
|
37
|
+
下記コマンドでインストールできます。
|
38
|
+
|
39
|
+
gem install some
|
40
|
+
|
41
|
+
インストールが終わったら ~/.sumo/config.yml に設定ファイルを作成しましょう。
|
42
|
+
最小限下記を書けば使えます。
|
43
|
+
|
44
|
+
---
|
45
|
+
access_key: (ここにアクセスキーを書く)
|
46
|
+
secret_key: (ここにシークレットキーを書く)
|
47
|
+
|
48
|
+
設定できる項目をフルで書くとこんな感じになります。
|
49
|
+
|
50
|
+
---
|
51
|
+
access_key: (デフォルト値なし)
|
52
|
+
secret_key: (デフォルト値なし)
|
53
|
+
user: root (デフォルト値)
|
54
|
+
password: password (デフォルト値)
|
55
|
+
instance_size: mini (デフォルト値)
|
56
|
+
ami: 26 (デフォルト値)
|
57
|
+
availability_zone: west-11 (デフォルト値)
|
58
|
+
cookbooks_url: (デフォルト値なし、次節参照)
|
59
|
+
role: (デフォルト値なし、次節参照)
|
60
|
+
|
61
|
+
## Chef でサービスをインストールする
|
62
|
+
|
63
|
+
少し頑張れば vagrant みたいなこともできます。
|
64
|
+
まずはグローバルからアクセスできる場所に cookbooks.tgz を置きましょう。
|
65
|
+
例:http://some.ncss.nifty.com/cookbooks.tgz
|
66
|
+
|
67
|
+
次に設定ファイル (~/.sumo/config.yml) にロールを定義しておきます。
|
68
|
+
|
69
|
+
cookbooks_url: http://some.ncss.nifty.com/cookbooks.tgz
|
70
|
+
role:
|
71
|
+
mysql: |
|
72
|
+
{
|
73
|
+
"run_list": [
|
74
|
+
"recipe[mysql::server]"
|
75
|
+
],
|
76
|
+
"mysql": {
|
77
|
+
"server_root_password": "mysql",
|
78
|
+
"server_debian_password": "mysql",
|
79
|
+
"server_repl_password": "mysql"
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
ここまでやればコマンド一発でサーバー作成・Chef インストール・Chef 実行まで行えます。
|
84
|
+
|
85
|
+
$ some launch mysql
|
86
|
+
---> Launch instance... d7f764b7 (7.6s)
|
87
|
+
---> Acquire hostname... 175.184.23.139 (89.4s)
|
88
|
+
---> Wait for ssh... done (0.0s)
|
89
|
+
---> Bootstrap chef... done (42.8s)
|
90
|
+
---> Setup mysql... done (195.0s)
|
91
|
+
|
92
|
+
なお、上記を個別に実施することも可能です。
|
93
|
+
|
94
|
+
$ some launch
|
95
|
+
---> Launch instance... 923d7772 (8.0s)
|
96
|
+
---> Acquire hostname... XXX.XXX.XXX.XXX (90.5s)
|
97
|
+
---> Wait for ssh... done (0.0s)
|
98
|
+
|
99
|
+
$ some bootstrap 923d7772
|
100
|
+
---> Bootstrap chef... done (46.0s)
|
101
|
+
|
102
|
+
$ some role mysql 923d7772
|
103
|
+
---> Setup mysql... done (184.6s)
|
104
|
+
|
105
|
+
## 詳細
|
106
|
+
|
107
|
+
* サーバー作成の際に something という名前の SSH キーと FW を作成します
|
108
|
+
* SSH キーは ~/.some/keypair.pem に保存されます
|
109
|
+
|
110
|
+
## ライセンス
|
111
|
+
|
112
|
+
[sumo](http://github.com/adamwiggins/sumo) と同じく MIT ライセンスで公開します。
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ Jeweler::Tasks.new do |s|
|
|
10
10
|
s.rubyforge_project = "some"
|
11
11
|
s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
|
12
12
|
s.executables = %w(some)
|
13
|
-
s.add_dependency "nifty-cloud-sdk"
|
13
|
+
s.add_dependency "nifty-cloud-sdk", "1.11.beta1"
|
14
14
|
s.add_dependency "thor"
|
15
15
|
end
|
16
16
|
|
data/TODO
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/bin/some
CHANGED
@@ -14,21 +14,7 @@ class CLI < Thor
|
|
14
14
|
|
15
15
|
if role
|
16
16
|
task("Bootstrap chef") { some.bootstrap_chef(host) }
|
17
|
-
role.
|
18
|
-
task("Setup #{role}") { some.setup_role(host, role) }
|
19
|
-
end
|
20
|
-
|
21
|
-
resources = some.resources(host)
|
22
|
-
unless resources.empty?
|
23
|
-
task("Open firewall") do
|
24
|
-
ports = resources.map { |r| r.match(/:(\d+)\//)[1] }
|
25
|
-
ports.each { |port| some.open_firewall(port) }
|
26
|
-
"ports " + ports.join(", ")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
puts
|
31
|
-
display_resources(host)
|
17
|
+
task("Setup #{role}") { some.setup_role(host, role) }
|
32
18
|
else
|
33
19
|
puts "\nLogging you in via ssh. Type 'exit' or Ctrl-D to return to your local system."
|
34
20
|
puts '-' * 78
|
@@ -43,13 +29,6 @@ class CLI < Thor
|
|
43
29
|
connect_ssh hostname
|
44
30
|
end
|
45
31
|
|
46
|
-
desc "resources [<instance_id or hostname>]", "show resources exported by an instance"
|
47
|
-
def resources(id=nil)
|
48
|
-
inst = some.find(id) || some.running.first || abort("No running instances")
|
49
|
-
hostname = inst[:hostname] || wait_for_hostname(inst[:instance_id])
|
50
|
-
display_resources(inst[:hostname])
|
51
|
-
end
|
52
|
-
|
53
32
|
desc "bootstrap", "bootstrap chef and cookbooks"
|
54
33
|
def bootstrap(id=nil)
|
55
34
|
inst = some.find(id) || some.running.first || abort("No running instances")
|
@@ -76,15 +55,29 @@ class CLI < Thor
|
|
76
55
|
desc "terminate [<instance_id or hostname>]", "terminate specified instance or first available"
|
77
56
|
def terminate(id=nil)
|
78
57
|
inst = some.find(id) || (some.running | some.pending).first || abort("No running or pending instances")
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
58
|
+
if inst[:status] != 'stopped'
|
59
|
+
task 'Wait to stop' do
|
60
|
+
some.wait_to_stop(inst[:instance_id])
|
61
|
+
end
|
62
|
+
end
|
84
63
|
some.terminate(inst[:instance_id])
|
85
64
|
puts "#{inst[:hostname] || inst[:instance_id]} scheduled for termination"
|
86
65
|
end
|
87
66
|
|
67
|
+
desc "openfw <port>", "open firewall"
|
68
|
+
def openfw(port)
|
69
|
+
raise ArgumentError unless port
|
70
|
+
some.open_firewall(port)
|
71
|
+
puts "port #{port} scheduled for open"
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "closefw <port>", "close firewall"
|
75
|
+
def closefw(port)
|
76
|
+
raise ArgumentError unless port
|
77
|
+
some.close_firewall(port)
|
78
|
+
puts "port #{port} scheduled for open"
|
79
|
+
end
|
80
|
+
|
88
81
|
no_tasks do
|
89
82
|
def some
|
90
83
|
@some ||= Some.new
|
@@ -111,16 +104,6 @@ class CLI < Thor
|
|
111
104
|
puts "\nType 'some terminate' if you're done with this instance."
|
112
105
|
end
|
113
106
|
end
|
114
|
-
|
115
|
-
def display_resources(host)
|
116
|
-
resources = some.resources(host)
|
117
|
-
unless resources.empty?
|
118
|
-
puts "Your instance is exporting the following resources:"
|
119
|
-
resources.each do |resource|
|
120
|
-
puts " #{resource}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
107
|
end
|
125
108
|
end
|
126
109
|
|
data/lib/some.rb
CHANGED
@@ -19,7 +19,8 @@ class Some
|
|
19
19
|
:key_name => 'something',
|
20
20
|
:security_group => 'something',
|
21
21
|
:availability_zone => config['availability_zone'],
|
22
|
-
|
22
|
+
:disable_api_termination => false,
|
23
|
+
:accounting_type => 2
|
23
24
|
)
|
24
25
|
result.instancesSet.item[0].instanceId
|
25
26
|
end
|
@@ -149,13 +150,11 @@ class Some
|
|
149
150
|
|
150
151
|
def wait_to_stop(instance_id)
|
151
152
|
raise ArgumentError unless instance_id
|
152
|
-
|
153
|
-
puts "waiting for #{instance_id} to stop "
|
153
|
+
api.stop_instances(:instance_id => [ instance_id ])
|
154
154
|
loop do
|
155
|
-
print '.'
|
156
155
|
if inst = instance_info(instance_id)
|
157
156
|
if inst[:status] == 'stopped'
|
158
|
-
|
157
|
+
break
|
159
158
|
end
|
160
159
|
end
|
161
160
|
sleep 5
|
@@ -177,45 +176,30 @@ class Some
|
|
177
176
|
|
178
177
|
def bootstrap_chef(hostname)
|
179
178
|
commands = [
|
180
|
-
|
181
|
-
|
182
|
-
|
179
|
+
"curl -L https://www.opscode.com/chef/install.sh | bash",
|
180
|
+
"mkdir -p /var/chef/cookbooks /etc/chef",
|
181
|
+
"echo json_attribs \\'/etc/chef/dna.json\\' > /etc/chef/solo.rb"
|
183
182
|
]
|
184
183
|
ssh(hostname, commands)
|
185
184
|
end
|
186
185
|
|
187
186
|
def setup_role(hostname, role)
|
188
187
|
commands = [
|
189
|
-
|
188
|
+
"echo \'#{config['role'][role]}\' > /etc/chef/dna.json",
|
190
189
|
"chef-solo -r #{config['cookbooks_url']}"
|
191
190
|
]
|
192
191
|
ssh(hostname, commands)
|
193
192
|
end
|
194
193
|
|
195
194
|
def ssh(hostname, cmds)
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
def resources(hostname)
|
205
|
-
@resources ||= {}
|
206
|
-
@resources[hostname] ||= fetch_resources(hostname)
|
207
|
-
end
|
208
|
-
|
209
|
-
def fetch_resources(hostname)
|
210
|
-
cmd = "ssh -i #{keypair_file} #{config['user']}@#{hostname} 'cat /root/resources' 2>&1"
|
211
|
-
out = IO.popen(cmd, 'r') { |pipe| pipe.read }
|
212
|
-
abort "failed to read resources, output:\n#{out}" unless $?.success?
|
213
|
-
parse_resources(out, hostname)
|
214
|
-
end
|
215
|
-
|
216
|
-
def parse_resources(raw, hostname)
|
217
|
-
raw.split("\n").map do |line|
|
218
|
-
line.gsub(/localhost/, hostname)
|
195
|
+
STDOUT.puts
|
196
|
+
Net::SSH.start(hostname, config['user'], :keys => [keypair_file], :passphrase => config['password']) do |ssh|
|
197
|
+
File.open("#{ENV['HOME']}/.some/ssh.log", 'w') do |f|
|
198
|
+
ssh.exec!(cmds.join(' && ')) do |ch, stream, data|
|
199
|
+
f.write(data)
|
200
|
+
STDOUT.print data
|
201
|
+
end
|
202
|
+
end
|
219
203
|
end
|
220
204
|
end
|
221
205
|
|
@@ -232,7 +216,7 @@ class Some
|
|
232
216
|
'user' => 'root',
|
233
217
|
'ami' => 26,
|
234
218
|
'availability_zone' => 'east-12',
|
235
|
-
|
219
|
+
'password' => 'password'
|
236
220
|
}
|
237
221
|
end
|
238
222
|
|
@@ -259,37 +243,77 @@ class Some
|
|
259
243
|
def create_security_group
|
260
244
|
api.create_security_group(:group_name => 'something', :group_description => 'Something')
|
261
245
|
rescue NIFTY::ResponseError => e
|
262
|
-
|
263
|
-
|
264
|
-
|
246
|
+
if e.message != "The groupName 'something' already exists."
|
247
|
+
raise e
|
248
|
+
end
|
265
249
|
end
|
266
250
|
|
267
251
|
def open_firewall(port)
|
268
|
-
|
252
|
+
target = {
|
269
253
|
:group_name => 'something',
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
254
|
+
:ip_permissions => {
|
255
|
+
:ip_protocol => 'TCP',
|
256
|
+
:in_out => 'IN',
|
257
|
+
:from_port => port,
|
258
|
+
:to_port => port,
|
259
|
+
:cidr_ip => '0.0.0.0/0'
|
260
|
+
}
|
261
|
+
}
|
262
|
+
return if find_security_group_ingress(target)
|
263
|
+
api.authorize_security_group_ingress(target)
|
264
|
+
end
|
265
|
+
|
266
|
+
def close_firewall(port)
|
267
|
+
target = {
|
268
|
+
:group_name => 'something',
|
269
|
+
:ip_permissions => {
|
270
|
+
:ip_protocol => 'TCP',
|
271
|
+
:in_out => 'IN',
|
272
|
+
:from_port => port,
|
273
|
+
:to_port => port,
|
274
|
+
:cidr_ip => '0.0.0.0/0'
|
275
|
+
}
|
276
|
+
}
|
277
|
+
return unless find_security_group_ingress(target)
|
278
|
+
api.revoke_security_group_ingress(target)
|
279
|
+
end
|
280
|
+
|
281
|
+
def find_security_group_ingress(target)
|
282
|
+
res = api.describe_security_groups
|
283
|
+
security_group = res.securityGroupInfo.item.find {|security_group|
|
284
|
+
security_group.groupName == target[:group_name]
|
285
|
+
}
|
286
|
+
return nil if !security_group || !security_group.ipPermissions
|
287
|
+
security_group.ipPermissions.item.find {|ip_permission|
|
288
|
+
flag = (
|
289
|
+
ip_permission.ipProtocol == target[:ip_permissions][:ip_protocol] &&
|
290
|
+
ip_permission.inOut == target[:ip_permissions][:in_out]
|
291
|
+
)
|
292
|
+
# also compare from_port when ip_protocol is not ICMP but TCP or UDP
|
293
|
+
if target[:ip_permissions][:ip_protocol] != 'ICMP'
|
294
|
+
flag = flag && (ip_permission.fromPort == target[:ip_permissions][:from_port].to_s)
|
295
|
+
end
|
296
|
+
if ip_permission.groups
|
297
|
+
flag = flag && (ip_permission.groups.item.first.groupName == target[:ip_permissions][:group_name])
|
298
|
+
else
|
299
|
+
flag = flag && (ip_permission.ipRanges.item.first.cidrIp == target[:ip_permissions][:cidr_ip])
|
300
|
+
end
|
301
|
+
flag
|
302
|
+
}
|
279
303
|
end
|
280
304
|
|
281
305
|
def api
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
306
|
+
@api ||= NIFTY::Cloud::Base.new(
|
307
|
+
:access_key => config['access_key'],
|
308
|
+
:secret_key => config['secret_key'],
|
309
|
+
:server => server,
|
310
|
+
:path => '/api'
|
311
|
+
)
|
288
312
|
end
|
289
313
|
|
290
314
|
def server
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
315
|
+
zone = config['availability_zone']
|
316
|
+
host = zone.slice(0, zone.length - 1)
|
317
|
+
"#{host}.cp.cloud.nifty.com"
|
318
|
+
end
|
295
319
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: some
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-06 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nifty-cloud-sdk
|
16
|
-
requirement: &
|
16
|
+
requirement: &75338600 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - =
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.11.beta1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *75338600
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: thor
|
27
|
-
requirement: &
|
27
|
+
requirement: &75337980 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,17 +32,17 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *75337980
|
36
36
|
description: sumo clone for NIFTY Cloud
|
37
37
|
email: tidnlyam@gmail.com
|
38
38
|
executables:
|
39
39
|
- some
|
40
40
|
extensions: []
|
41
41
|
extra_rdoc_files:
|
42
|
-
- README.
|
42
|
+
- README.md
|
43
43
|
- TODO
|
44
44
|
files:
|
45
|
-
- README.
|
45
|
+
- README.md
|
46
46
|
- Rakefile
|
47
47
|
- TODO
|
48
48
|
- VERSION
|
data/README.rdoc
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
= Tired of wrestling with server provisioning? Sumo!
|
2
|
-
|
3
|
-
Want to fire up a one-off EC2 instance, pronto? ec2-run-instances got you down? Try Sumo.
|
4
|
-
|
5
|
-
$ sumo launch
|
6
|
-
---> Launching instance... i-4f809c26 (1.5s)
|
7
|
-
---> Acquiring hostname... ec2-67-202-17-178.compute-1.amazonaws.com (26.7s)
|
8
|
-
|
9
|
-
Logging you in via ssh. Type 'exit' or Ctrl-D to return to your local system.
|
10
|
-
------------------------------------------------------------------------------
|
11
|
-
Linux domU-12-31-39-04-31-37 2.6.21.7-2.fc8xen #1 SMP Fri Feb 15 12:39:36 EST 2008 i686
|
12
|
-
...
|
13
|
-
root@domU-12-31-39-04-31-37:~#
|
14
|
-
|
15
|
-
Later...
|
16
|
-
|
17
|
-
$ sumo terminate
|
18
|
-
ec2-67-202-17-178.compute-1.amazonaws.com scheduled for termination
|
19
|
-
|
20
|
-
You can manage multiple instances via "sumo list" and specifying hostname or instance id as arguments to the ssh or terminate commands.
|
21
|
-
|
22
|
-
== Service installation with Chef
|
23
|
-
|
24
|
-
The launch command takes an argument, which is a server role (from roles/#{role}.json inside your cookbooks repo):
|
25
|
-
|
26
|
-
$ sumo launch redis
|
27
|
-
---> Launch instance... i-b96c73d0 (1.3s)
|
28
|
-
---> Acquire hostname... ec2-75-101-191-220.compute-1.amazonaws.com (36.1s)
|
29
|
-
---> Wait for ssh... done (9.0s)
|
30
|
-
---> Bootstrap chef... done (61.3s)
|
31
|
-
---> Setup redis... done (11.9s)
|
32
|
-
---> Opening firewall... ports 6379 (5.2s)
|
33
|
-
|
34
|
-
Your instance is exporting the following resources:
|
35
|
-
Redis: redis://:8452cdd98f428c972f08@ec2-75-101-191-220.compute-1.amazonaws.com:6379/0
|
36
|
-
|
37
|
-
The instance can assume multiple roles if you like:
|
38
|
-
|
39
|
-
$ sumo launch redis,solr,couchdb
|
40
|
-
|
41
|
-
== Setup
|
42
|
-
|
43
|
-
Dependencies:
|
44
|
-
|
45
|
-
$ sudo gem install amazon-ec2 thor
|
46
|
-
|
47
|
-
Then create ~/.sumo/config.yml containing:
|
48
|
-
|
49
|
-
---
|
50
|
-
access_id: <your amazon access key id>
|
51
|
-
access_secret: <your amazon secret access key>
|
52
|
-
|
53
|
-
Optional config you can include any of the following in your config.yml:
|
54
|
-
|
55
|
-
user: root
|
56
|
-
ami: ami-ed46a784
|
57
|
-
availability_zone: us-east-1b
|
58
|
-
cookbooks_url: git://github.com/adamwiggins/chef-cookbooks.git
|
59
|
-
|
60
|
-
You'll need Bacon and Mocha if you want to run the specs, and Jewler if you want to create gems.
|
61
|
-
|
62
|
-
== Managing volumes
|
63
|
-
|
64
|
-
Create and attach a volume to your running instance:
|
65
|
-
|
66
|
-
$ sumo create_volume
|
67
|
-
---> Create 5MB volume... vol-8a9c6ae3 (1.1s)
|
68
|
-
$ sumo volumes
|
69
|
-
vol-8a9c6ae3 5MB available
|
70
|
-
$ sumo attach
|
71
|
-
---> Attach vol-8a9c6ae3 to i-bc32cbd4 as /dev/sdc1... done (0.6s)
|
72
|
-
|
73
|
-
Log in to format and mount the volume:
|
74
|
-
|
75
|
-
$ sumo ssh
|
76
|
-
root@ip-10-251-122-175:~# mkfs.ext3 /dev/sdc1
|
77
|
-
mke2fs 1.41.4 (27-Jan-2009)
|
78
|
-
Filesystem label=
|
79
|
-
OS type: Linux
|
80
|
-
Block size=4096 (log=2)
|
81
|
-
...
|
82
|
-
$ mkdir /myvol
|
83
|
-
$ mount /dev/sdc1 /myvol
|
84
|
-
$ echo "I'm going to persist to a volume" > /myvol/hello.txt
|
85
|
-
|
86
|
-
To detach from a running instance (perhaps so you can attach elsewhere):
|
87
|
-
|
88
|
-
$ sumo detatch
|
89
|
-
---> Detach vol-8a9c6ae3... done (0.6s)
|
90
|
-
|
91
|
-
Destroy it if you no longer want the data stored on it:
|
92
|
-
|
93
|
-
$ sumo destroy_volume
|
94
|
-
---> Destroy volume... done (0.8s)
|
95
|
-
|
96
|
-
== Some details you might want to know
|
97
|
-
|
98
|
-
Sumo creates its own keypair named sumo, which is stored in ~/.ssh/keypair.pem. Amazon doesn't let you upload your own ssh public key, which is lame, so this is the best option for making the launch-and-connect process a single step.
|
99
|
-
|
100
|
-
It will also create an Amazon security group called sumo, so that it can lower the firewall for services you configure via cookbook roles.
|
101
|
-
|
102
|
-
If you run any production machines from your EC2 account, I recommend setting up a separate account for use with Sumo. It does not prompt for confirmation when terminating an instance or differentiate between instances started by it vs. instances started by other tools.
|
103
|
-
|
104
|
-
== Anti-features
|
105
|
-
|
106
|
-
Sumo is not a cloud management tool, a monitor tool, or anything more than a way to get an instance up right quick. If you're looking for a way to manage a cluster of production instances, try one of these fine tools.
|
107
|
-
|
108
|
-
* Pool Party
|
109
|
-
* RightScale
|
110
|
-
* Engine Yard Cloud
|
111
|
-
* Cloudkick
|
112
|
-
|
113
|
-
== Meta
|
114
|
-
|
115
|
-
Created by Adam Wiggins
|
116
|
-
|
117
|
-
Patches contributed by Orion Henry, Blake Mizerany, Jesse Newland, Gert Goet,
|
118
|
-
and Tim Lossen
|
119
|
-
|
120
|
-
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
|
121
|
-
|
122
|
-
http://github.com/adamwiggins/sumo
|
123
|
-
|