some 0.0.1 → 0.0.2
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 +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
|
-
|