sumo 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.rdoc +39 -6
  2. data/VERSION +1 -1
  3. data/bin/sumo +42 -1
  4. data/lib/sumo.rb +74 -2
  5. metadata +2 -2
data/README.rdoc CHANGED
@@ -50,24 +50,57 @@ Then create ~/.sumo/config.yml containing:
50
50
  access_id: <your amazon access key id>
51
51
  access_secret: <your amazon secret access key>
52
52
 
53
- Optional config you can include in config.yml:
53
+ Optional config you can include any of the following in your config.yml:
54
54
 
55
55
  user: root
56
56
  ami: ami-ed46a784
57
+ availability_zone: us-east-1b
57
58
  cookbooks_url: git://github.com/adamwiggins/chef-cookbooks.git
58
59
 
59
- 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.
60
-
61
60
  You'll need Bacon and Mocha if you want to run the specs, and Jewler if you want to create gems.
62
61
 
63
- == Features
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
64
85
 
65
- Launch, ssh to, and terminate instances.
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
66
97
 
67
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.
68
99
 
69
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.
70
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
+
71
104
  == Anti-features
72
105
 
73
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.
@@ -81,7 +114,7 @@ Sumo is not a cloud management tool, a monitor tool, or anything more than a way
81
114
 
82
115
  Created by Adam Wiggins
83
116
 
84
- Patches contributed by Blake Mizerany and Jesse Newland
117
+ Patches contributed by Orion Henry, Blake Mizerany, Jesse Newland, and Gert Goet
85
118
 
86
119
  Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
87
120
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.1
data/bin/sumo CHANGED
@@ -19,7 +19,7 @@ class CLI < Thor
19
19
 
20
20
  resources = sumo.resources(host)
21
21
  unless resources.empty?
22
- task("Opening firewall") do
22
+ task("Open firewall") do
23
23
  ports = resources.map { |r| r.match(/:(\d+)\//)[1] }
24
24
  ports.each { |port| sumo.open_firewall(port) }
25
25
  "ports " + ports.join(", ")
@@ -72,6 +72,13 @@ class CLI < Thor
72
72
  end
73
73
  end
74
74
 
75
+ desc "console [<instance_id or hostname>]", "get console output for instance or first available"
76
+ def console(id=nil)
77
+ inst = sumo.find(id) || (sumo.running | sumo.pending).first || abort("No running or pending instances")
78
+
79
+ puts sumo.console_output(inst[:instance_id]).inspect
80
+ end
81
+
75
82
  desc "terminate [<instance_id or hostname>]", "terminate specified instance or first available"
76
83
  def terminate(id=nil)
77
84
  inst = sumo.find(id) || (sumo.running | sumo.pending).first || abort("No running or pending instances")
@@ -90,6 +97,40 @@ class CLI < Thor
90
97
  end
91
98
  end
92
99
 
100
+ desc "volumes", "list all volumes"
101
+ def volumes
102
+ sumo.volumes.each do |v|
103
+ printf "%-10s %4sGB %10s %15s %15s\n", v[:volume_id], v[:size], v[:status], v[:instance], v[:device]
104
+ end
105
+ end
106
+
107
+ desc "create_volume [<megabytes>]", "create a volume"
108
+ def create_volume(size=5)
109
+ task("Create #{size}GB volume") { sumo.create_volume(size) }
110
+ end
111
+
112
+ desc "destroy_volume [<volume_id>]", "destroy a volume"
113
+ def destroy_volume(volume=nil)
114
+ vol_id = (sumo.find_volume(volume) || sumo.nondestroyed_volumes.first || abort("No volumes"))[:volume_id]
115
+ task("Destroy volume") { sumo.destroy_volume(vol_id) }
116
+ end
117
+
118
+ desc "attach [<volume_id>] [<instance_id or hostname>] [<device>]", "attach volume to running instance"
119
+ def attach(volume=nil, inst_id=nil, device=nil)
120
+ vol_id = (sumo.find_volume(volume) || sumo.available_volumes.first || abort("No available volumes"))[:volume_id]
121
+ inst_id = (sumo.find(inst_id) || sumo.running.first || abort("No running instances"))[:instance_id]
122
+ device ||= '/dev/sdc1'
123
+ task("Attach #{vol_id} to #{inst_id} as #{device}") do
124
+ sumo.attach(vol_id, inst_id, device)
125
+ end
126
+ end
127
+
128
+ desc "detach [<volume_id>]", "detach volume from instance"
129
+ def detach(volume=nil)
130
+ vol_id = (sumo.find_volume(volume) || sumo.attached_volumes.first || abort("No attached volumes"))[:volume_id]
131
+ task("Detach #{vol_id}") { sumo.detach(vol_id) }
132
+ end
133
+
93
134
  no_tasks do
94
135
  def sumo
95
136
  @sumo ||= Sumo.new
data/lib/sumo.rb CHANGED
@@ -16,7 +16,8 @@ class Sumo
16
16
  :image_id => ami,
17
17
  :instance_type => config['instance_size'] || 'm1.small',
18
18
  :key_name => 'sumo',
19
- :group_id => [ 'sumo' ]
19
+ :group_id => [ 'sumo' ],
20
+ :availability_zone => config['availability_zone']
20
21
  )
21
22
  result.instancesSet.item[0].instanceId
22
23
  end
@@ -25,6 +26,60 @@ class Sumo
25
26
  @list ||= fetch_list
26
27
  end
27
28
 
29
+ def volumes
30
+ result = ec2.describe_volumes
31
+ return [] unless result.volumeSet
32
+
33
+ result.volumeSet.item.map do |row|
34
+ {
35
+ :volume_id => row["volumeId"],
36
+ :size => row["size"],
37
+ :status => row["status"],
38
+ :device => (row["attachmentSet"]["item"].first["device"] rescue ""),
39
+ :instance_id => (row["attachmentSet"]["item"].first["instanceId"] rescue ""),
40
+ }
41
+ end
42
+ end
43
+
44
+ def available_volumes
45
+ volumes.select { |vol| vol[:status] == 'available' }
46
+ end
47
+
48
+ def attached_volumes
49
+ volumes.select { |vol| vol[:status] == 'in-use' }
50
+ end
51
+
52
+ def nondestroyed_volumes
53
+ volumes.select { |vol| vol[:status] != 'deleting' }
54
+ end
55
+
56
+ def attach(volume, instance, device)
57
+ result = ec2.attach_volume(
58
+ :volume_id => volume,
59
+ :instance_id => instance,
60
+ :device => device
61
+ )
62
+ "done"
63
+ end
64
+
65
+ def detach(volume)
66
+ result = ec2.detach_volume(:volume_id => volume, :force => "true")
67
+ "done"
68
+ end
69
+
70
+ def create_volume(size)
71
+ result = ec2.create_volume(
72
+ :availability_zone => config['availability_zone'],
73
+ :size => size.to_s
74
+ )
75
+ result["volumeId"]
76
+ end
77
+
78
+ def destroy_volume(volume)
79
+ ec2.delete_volume(:volume_id => volume)
80
+ "done"
81
+ end
82
+
28
83
  def fetch_list
29
84
  result = ec2.describe_instances
30
85
  return [] unless result.reservationSet
@@ -52,6 +107,15 @@ class Sumo
52
107
  end
53
108
  end
54
109
 
110
+ def find_volume(volume_id)
111
+ return unless volume_id
112
+ volume_id = volume_id.strip.downcase
113
+ volumes.detect do |volume|
114
+ volume[:volume_id] == volume_id or
115
+ volume[:volume_id].gsub(/^vol-/, '') == volume_id
116
+ end
117
+ end
118
+
55
119
  def running
56
120
  list_by_status('running')
57
121
  end
@@ -146,12 +210,20 @@ class Sumo
146
210
  ec2.terminate_instances(:instance_id => [ instance_id ])
147
211
  end
148
212
 
213
+ def console_output(instance_id)
214
+ ec2.get_console_output(:instance_id => instance_id)["output"]
215
+ end
216
+
149
217
  def config
150
218
  @config ||= default_config.merge read_config
151
219
  end
152
220
 
153
221
  def default_config
154
- { 'user' => 'root', 'ami' => 'ami-ed46a784' }
222
+ {
223
+ 'user' => 'root',
224
+ 'ami' => 'ami-ed46a784',
225
+ 'availability_zone' => 'us-east-1b'
226
+ }
155
227
  end
156
228
 
157
229
  def sumo_dir
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sumo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Wiggins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-05 00:00:00 -07:00
12
+ date: 2009-09-10 00:00:00 -07:00
13
13
  default_executable: sumo
14
14
  dependencies: []
15
15