judo 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -80
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/judo +21 -23
- data/lib/all.rb +1 -3
- data/lib/config.rb +31 -162
- data/lib/group.rb +37 -30
- data/lib/server.rb +36 -12
- data/lib/setup.rb +115 -0
- metadata +50 -22
data/README.rdoc
CHANGED
@@ -1,82 +1,4 @@
|
|
1
|
-
=
|
2
|
-
|
3
|
-
Want to launch and manage persistent utility servers on EC2? ec2-run-instances got you down? Try this:
|
4
|
-
|
5
|
-
$ sumo create mybox
|
6
|
-
Created server mybox
|
7
|
-
$ sumo list
|
8
|
-
mybox i-8a3d05e2 m1.small ami-1515f67c
|
9
|
-
$ sumo launch mybox
|
10
|
-
---> Launch server mybox... done (1.9s)
|
11
|
-
---> Acquire hostname... ec2-75-101-254-61.compute-1.amazonaws.com (34.0s)
|
12
|
-
---> Wait for ssh... done (3.1s)
|
13
|
-
|
14
|
-
Logging you in via ssh. Type 'exit' or Ctrl-D to return to your local system.
|
15
|
-
------------------------------------------------------------------------------
|
16
|
-
...
|
17
|
-
root@domU-12-31-39-04-31-37:~#
|
18
|
-
|
19
|
-
== Setup
|
20
|
-
|
21
|
-
Dependencies:
|
22
|
-
|
23
|
-
$ sudo gem install thor aws right_aws
|
24
|
-
|
25
|
-
Then create ~/.sumo/config.yml containing:
|
26
|
-
|
27
|
-
---
|
28
|
-
access_id: <your amazon access key id>
|
29
|
-
access_secret: <your amazon secret access key>
|
30
|
-
|
31
|
-
You'll need Bacon and Mocha if you want to run the specs, and Jewler if you want to create gems.
|
32
|
-
|
33
|
-
== Usage
|
34
|
-
|
35
|
-
Create a named persistent server:
|
36
|
-
|
37
|
-
$ sumo create mybox
|
38
|
-
Created server mybox
|
39
|
-
|
40
|
-
See config vars on the server record:
|
41
|
-
|
42
|
-
$ sumo info mybox
|
43
|
-
mybox:
|
44
|
-
availability_zone:"us-east-1d"
|
45
|
-
ami32:"ami-1515f67c"
|
46
|
-
user:"ubuntu"
|
47
|
-
key_name:"sumo"
|
48
|
-
ami64:"ami-ab15f6c2"
|
49
|
-
user_data:""
|
50
|
-
security_group:"sumo"
|
51
|
-
instance_size:"m1.small"
|
52
|
-
|
53
|
-
Set config vars before launch:
|
54
|
-
|
55
|
-
$ sumo set mybox --instance-size c1.medium
|
56
|
-
|
57
|
-
Create a static IP address and/or volumes:
|
58
|
-
|
59
|
-
$ sumo attach_ip mybox
|
60
|
-
$ sumo attach_volume mbox 50 /dev/sdh1
|
61
|
-
|
62
|
-
Launch an instance of the server:
|
63
|
-
|
64
|
-
$ sumo launch mybox
|
65
|
-
---> Launch server mybox...
|
66
|
-
|
67
|
-
You may want to spin down the server if it's not in use:
|
68
|
-
|
69
|
-
$ sumo stop mybox
|
70
|
-
|
71
|
-
...and bring it up again later:
|
72
|
-
|
73
|
-
$ sumo start mybox
|
74
|
-
|
75
|
-
== Some details you might want to know
|
76
|
-
|
77
|
-
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.
|
78
|
-
|
79
|
-
It will also create an Amazon security group called sumo, so that it can lower the firewall for services you configure via cookbook roles.
|
1
|
+
= Judo
|
80
2
|
|
81
3
|
== Meta
|
82
4
|
|
@@ -86,5 +8,5 @@ Patches contributed by Blake Mizerany, Jesse Newland, Gert Goet, and Tim Lossen
|
|
86
8
|
|
87
9
|
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
|
88
10
|
|
89
|
-
http://github.com/
|
11
|
+
http://github.com/orionz/judo
|
90
12
|
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'jeweler'
|
|
2
2
|
|
3
3
|
Jeweler::Tasks.new do |s|
|
4
4
|
s.name = "judo"
|
5
|
-
s.description = "
|
5
|
+
s.description = "The gentile way to manage and control ec2 instances"
|
6
6
|
s.summary = s.description
|
7
7
|
s.author = "Orion Henry"
|
8
8
|
s.email = "orion@heroku.com"
|
@@ -14,6 +14,7 @@ Jeweler::Tasks.new do |s|
|
|
14
14
|
s.add_dependency "aws"
|
15
15
|
s.add_dependency "thor"
|
16
16
|
s.add_dependency "json"
|
17
|
+
s.add_dependency "fog"
|
17
18
|
end
|
18
19
|
|
19
20
|
Jeweler::RubyforgeTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/bin/judo
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/../lib/all'
|
4
4
|
|
5
|
-
#Sumo::Config.connect
|
6
|
-
|
7
5
|
require 'thor'
|
8
6
|
|
9
7
|
class CLI < Thor
|
@@ -30,7 +28,7 @@ class CLI < Thor
|
|
30
28
|
|
31
29
|
desc "create NAME", "create a persistent server"
|
32
30
|
def create(name, start = false)
|
33
|
-
group =
|
31
|
+
group = Judo::Group.current
|
34
32
|
if name =~ /^[+](\d*)/
|
35
33
|
n = $1.to_i
|
36
34
|
fail "woah nelly - that's too many - 5 or less pls" if n > 5
|
@@ -97,27 +95,28 @@ class CLI < Thor
|
|
97
95
|
# pp server.volumes.inspect
|
98
96
|
# puts server.state.inspect
|
99
97
|
## EC2 describe_volumes
|
100
|
-
# puts " #{dev.to_s}:#{
|
98
|
+
# puts " #{dev.to_s}:#{Judo::Config.ec2.describe_volumes([vol_id])}"
|
101
99
|
# end
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
103
|
desc "list [NAMES]", "list all servers"
|
106
104
|
def list(*names)
|
107
|
-
if group =
|
105
|
+
if group = Judo::Group.current
|
106
|
+
printf " SERVER IN GROUP #{group.name}\n"
|
108
107
|
servers(*names) do |s|
|
109
|
-
printf "%-18s %-11s %-11s %-13s %-10s %-10s %s\n", s.name, s.state["instance_id"], s.instance_size, s.ami, s.ec2_state, "#{s.volumes.keys.size} volumes", s.ip
|
108
|
+
printf "%-18s %-4s %-11s %-11s %-13s %-10s %-10s %s\n", s.name, s.version_desc, s.state["instance_id"], s.instance_size, s.ami, s.ec2_state, "#{s.volumes.keys.size} volumes", s.ip
|
110
109
|
end
|
111
110
|
else
|
112
111
|
printf " SERVER GROUPS\n"
|
113
|
-
|
112
|
+
Judo::Group.all.each do |g|
|
114
113
|
printf "%-18s %s servers\n", g.name, g.servers.size
|
115
114
|
end
|
116
115
|
# printf " UNGROUPED SERVERS\n"
|
117
116
|
# servers.each do |s|
|
118
117
|
# printf "%-18s %-11s %-11s %-13s %-10s %-10s %s\n", s.name, s.state["instance_id"], s.state["security_group"], s.ami, s.ec2_state, "#{s.volumes.keys.size} volumes", s.ip
|
119
118
|
# end
|
120
|
-
else
|
119
|
+
# else
|
121
120
|
end
|
122
121
|
end
|
123
122
|
|
@@ -132,9 +131,9 @@ class CLI < Thor
|
|
132
131
|
end
|
133
132
|
end
|
134
133
|
|
135
|
-
desc "init", "create a new
|
134
|
+
desc "init", "create a new judo repository in the current directory"
|
136
135
|
def init
|
137
|
-
|
136
|
+
Judo::Setup.new.init
|
138
137
|
end
|
139
138
|
|
140
139
|
desc "volumes", "list all volumes"
|
@@ -143,8 +142,8 @@ class CLI < Thor
|
|
143
142
|
printf format, "AWS_ID", "SIZE", "AWS_STATUS", "AWS_DEVICE", "ATTACHED TO", "CONFIGURED FOR"
|
144
143
|
printf "%s\n", ("-" * 80)
|
145
144
|
### EC2 describe_volumes
|
146
|
-
|
147
|
-
[ volume[:aws_id], volume[:aws_size], volume[:aws_status], volume[:aws_device] || "",
|
145
|
+
Judo::Config.ec2.describe_volumes.map do |volume|
|
146
|
+
[ volume[:aws_id], volume[:aws_size], volume[:aws_status], volume[:aws_device] || "", instance_id_to_judo(volume[:aws_instance_id]) || volume[:aws_instance_id] || "", volume_id_to_judo(volume[:aws_id]) ]
|
148
147
|
end.sort { |a,b| [ a[5].to_s, a[3].to_s ] <=> [ b[5].to_s, b[3].to_s ] }.each do |d|
|
149
148
|
printf format, *d
|
150
149
|
end
|
@@ -156,8 +155,8 @@ class CLI < Thor
|
|
156
155
|
printf format, "IP", "ATTACHED TO", "CONFIGURED FOR"
|
157
156
|
printf "%s\n", ("-"*57)
|
158
157
|
## EC2 describe_addresses
|
159
|
-
|
160
|
-
[ ip[:public_ip],
|
158
|
+
Judo::Config.ec2.describe_addresses.map do |ip|
|
159
|
+
[ ip[:public_ip], instance_id_to_judo(ip[:instance_id]) || ip[:instance_id], ip_to_judo(ip[:public_ip]) ]
|
161
160
|
end.sort { |a,b| a[2].to_s <=> b[2].to_s }.each do |d|
|
162
161
|
printf format, *d
|
163
162
|
end
|
@@ -165,13 +164,12 @@ class CLI < Thor
|
|
165
164
|
|
166
165
|
desc "commit", "push configs and files to couchdb"
|
167
166
|
def commit
|
168
|
-
|
169
|
-
Sumo::Server.commit
|
167
|
+
Judo::Group.current.compile
|
170
168
|
end
|
171
169
|
|
172
170
|
no_tasks do
|
173
171
|
def servers(*names, &block)
|
174
|
-
group =
|
172
|
+
group = Judo::Group.current
|
175
173
|
good_servers = group.servers.select { |s| names.empty? or names.include?(s.name) }
|
176
174
|
bad_names = (names - good_servers.map(&:name))
|
177
175
|
fail "bad server name: #{bad_names.join(', ')}" unless bad_names.empty?
|
@@ -195,16 +193,16 @@ class CLI < Thor
|
|
195
193
|
result
|
196
194
|
end
|
197
195
|
|
198
|
-
def
|
199
|
-
|
196
|
+
def volume_id_to_judo(volume)
|
197
|
+
Judo::Server.all.detect { |s| s.volumes.invert[volume] }
|
200
198
|
end
|
201
199
|
|
202
|
-
def
|
203
|
-
|
200
|
+
def ip_to_judo(ip)
|
201
|
+
Judo::Server.all.detect { |s| s.state["elastic_ip"] == ip }
|
204
202
|
end
|
205
203
|
|
206
|
-
def
|
207
|
-
|
204
|
+
def instance_id_to_judo(instance_id)
|
205
|
+
Judo::Server.all.detect { |s| s.state["instance_id"] and s.state["instance_id"] == instance_id }
|
208
206
|
end
|
209
207
|
end
|
210
208
|
end
|
data/lib/all.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'aws'
|
3
3
|
require 'right_aws'
|
4
|
-
require 'sdb/active_sdb' ##
|
5
4
|
require 'yaml'
|
6
5
|
require 'socket'
|
7
6
|
require 'json'
|
8
|
-
require 'couchrest' ##
|
9
7
|
require 'fileutils'
|
10
8
|
|
11
9
|
require 'fog'
|
@@ -14,4 +12,4 @@ require 'fog/aws/s3'
|
|
14
12
|
require File.dirname(__FILE__) + '/config'
|
15
13
|
require File.dirname(__FILE__) + '/group'
|
16
14
|
require File.dirname(__FILE__) + '/server'
|
17
|
-
require File.dirname(__FILE__) + '/
|
15
|
+
require File.dirname(__FILE__) + '/setup'
|
data/lib/config.rb
CHANGED
@@ -2,123 +2,49 @@ module Judo
|
|
2
2
|
module Config
|
3
3
|
extend self
|
4
4
|
|
5
|
-
|
6
|
-
def defaults
|
7
|
-
defaults_file = "#{judo_dir}/defaults.json"
|
8
|
-
unless File.exists? defaults_file
|
9
|
-
File.open(defaults_file, "w") { |f| f.write(default_config.to_json) }
|
10
|
-
end
|
11
|
-
JSON.parse File.read(defaults_file)
|
5
|
+
def method_missing?(method)
|
12
6
|
end
|
13
7
|
|
14
|
-
def
|
15
|
-
|
16
|
-
:key_name => "judo",
|
17
|
-
:instance_size => "m1.small",
|
18
|
-
:ami32 => "ami-bb709dd2", ## public ubuntu 9.10 ami - 32 bit
|
19
|
-
:ami64 => "ami-55739e3c", ## public ubuntu 9.10 ami - 64 bit
|
20
|
-
:user => "ubuntu",
|
21
|
-
:security_group => { "name" => "judo", "public_ports" => ["22"] },
|
22
|
-
:availability_zone => "us-east-1d" ## FIXME -- this should be state not config -- what if they differ - how to set?
|
23
|
-
}
|
8
|
+
def db_version
|
9
|
+
1
|
24
10
|
end
|
25
11
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
12
|
+
def get_db_version
|
13
|
+
version = @sdb.get_attributes("judo_config", "judo")[:attributes]["dbversion"]
|
14
|
+
version and version.first.to_i or db_version
|
15
|
+
end
|
30
16
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# load_config_stack(conf["import"], all << conf)
|
35
|
-
# end
|
17
|
+
def check_version
|
18
|
+
fail "judo db is newer than the current gem - upgrade judo and try again" if get_db_version > db_version
|
19
|
+
end
|
36
20
|
|
37
21
|
def repo_dir
|
38
22
|
judo_config["repo"] || File.dirname(judo_dir)
|
39
23
|
end
|
40
24
|
|
41
|
-
# def group_dirs
|
42
|
-
# Dir["#{repo_dir}/*/config.json"].map { |d| File.dirname(d) }
|
43
|
-
# end
|
44
|
-
|
45
|
-
# def group_dir(name)
|
46
|
-
# group_dirs.select { |d| File.basename(d) == name }
|
47
|
-
# end
|
48
|
-
|
49
|
-
# def groups
|
50
|
-
# group_dirs.map { |g| File.basename(g) }
|
51
|
-
# end
|
52
|
-
|
53
|
-
# def group
|
54
|
-
# File.basename(group_dirs.detect { |d| Dir.pwd == d or Dir.pwd =~ /^#{d}\// }) rescue nil
|
55
|
-
# end
|
56
|
-
|
57
|
-
# def read_config(name)
|
58
|
-
# begin
|
59
|
-
# JSON.parse(File.read("#{group_dir(name)}/config.json"))
|
60
|
-
# rescue Errno::ENOENT
|
61
|
-
# {}
|
62
|
-
# end
|
63
|
-
# end
|
64
|
-
|
65
25
|
def access_id
|
66
|
-
judo_config["access_id"]
|
26
|
+
judo_config["access_id"]
|
67
27
|
end
|
68
28
|
|
69
29
|
def access_secret
|
70
|
-
judo_config["access_secret"]
|
30
|
+
judo_config["access_secret"]
|
71
31
|
end
|
72
32
|
|
73
|
-
def
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
### REMOVE
|
78
|
-
def couchdb
|
79
|
-
@couchdb ||= CouchRest.database!(couch_url)
|
80
|
-
end
|
81
|
-
|
82
|
-
def couch_url
|
83
|
-
judo_config["couch_url"] || "http://127.0.0.1:5984/judo"
|
84
|
-
end
|
85
|
-
|
86
|
-
## FIXME
|
87
|
-
def keypair_file
|
88
|
-
judo_config["keypair_file"] || "#{judo_dir}/keypair.pem"
|
33
|
+
def get_ec2(aws_id, aws_key)
|
34
|
+
Aws::Ec2.new(aws_id, aws_key, :logger => Logger.new(nil))
|
89
35
|
end
|
90
36
|
|
91
|
-
|
92
|
-
|
93
|
-
# one_time_setup unless setup?
|
94
|
-
# end
|
95
|
-
|
96
|
-
## FIXME
|
97
|
-
def one_time_setup
|
98
|
-
puts "ONE TIME SETUP"
|
99
|
-
Sumo::Server.create_domain
|
37
|
+
def ec2
|
38
|
+
@ec2 ||= get_ec2(access_id, access_secret)
|
100
39
|
end
|
101
40
|
|
102
|
-
# def
|
103
|
-
#
|
41
|
+
# def create_security_group
|
42
|
+
# ## EC2 create_security_group
|
43
|
+
# ec2.create_security_group('judo', 'Judo')
|
44
|
+
# ## EC2 authorize_security_group
|
45
|
+
# ec2.authorize_security_group_IP_ingress("judo", 22, 22,'tcp','0.0.0.0/0')
|
46
|
+
# rescue Aws::AwsError
|
104
47
|
# end
|
105
|
-
|
106
|
-
## FIXME
|
107
|
-
def create_keypair
|
108
|
-
## EC2 create_key_pair
|
109
|
-
material = ec2.create_key_pair("judo")[:aws_material]
|
110
|
-
File.open(keypair_file, 'w') { |f| f.write material }
|
111
|
-
File.chmod 0600, keypair_file
|
112
|
-
end
|
113
|
-
|
114
|
-
## FIXME - this seems... lame
|
115
|
-
def create_security_group
|
116
|
-
## EC2 create_security_group
|
117
|
-
ec2.create_security_group('judo', 'Sumo')
|
118
|
-
## EC2 authorize_security_group
|
119
|
-
ec2.authorize_security_group_IP_ingress("judo", 22, 22,'tcp','0.0.0.0/0')
|
120
|
-
rescue Aws::AwsError
|
121
|
-
end
|
122
48
|
|
123
49
|
def judo_config
|
124
50
|
@config ||= read_judo_config
|
@@ -150,14 +76,19 @@ module Judo
|
|
150
76
|
{}
|
151
77
|
end
|
152
78
|
|
79
|
+
def get_sdb(aws_id, aws_key)
|
80
|
+
puts "GET SDB #{aws_id} #{aws_key}"
|
81
|
+
Aws::SdbInterface.new(aws_id, aws_key, :logger => Logger.new(nil))
|
82
|
+
end
|
83
|
+
|
153
84
|
def sdb
|
154
|
-
@sdb
|
85
|
+
@sdb ||= get_sdb(access_id, access_secret)
|
86
|
+
@version_ok ||= check_version
|
87
|
+
@sdb
|
155
88
|
end
|
156
89
|
|
157
90
|
def s3
|
158
|
-
|
159
|
-
# @s3 ||= Aws::S3.new(access_id, access_secret)
|
160
|
-
@s3 = Fog::AWS::S3.new( :aws_access_key_id => access_id, :aws_secret_access_key => access_secret)
|
91
|
+
@s3 ||= Fog::AWS::S3.new( :aws_access_key_id => access_id, :aws_secret_access_key => access_secret)
|
161
92
|
end
|
162
93
|
|
163
94
|
def s3_url(k)
|
@@ -167,67 +98,5 @@ module Judo
|
|
167
98
|
def s3_put(k, file)
|
168
99
|
s3.put_object(judo_config["s3_bucket"], k, file)
|
169
100
|
end
|
170
|
-
|
171
|
-
def collect(keys, prompt, &blk)
|
172
|
-
k = keys.detect do |k|
|
173
|
-
printf "Looking in your environment for #{k}..."
|
174
|
-
printf "found!" if ENV[k]
|
175
|
-
printf "\n"
|
176
|
-
ENV[k]
|
177
|
-
end
|
178
|
-
value = ENV[k]
|
179
|
-
retries = 3
|
180
|
-
begin
|
181
|
-
unless value
|
182
|
-
printf "#{prompt}: "
|
183
|
-
value = STDIN.readline
|
184
|
-
end
|
185
|
-
blk.call(value) if blk
|
186
|
-
value
|
187
|
-
rescue *[Interrupt, EOFError]
|
188
|
-
puts "\nGoodbye!"
|
189
|
-
exit(0)
|
190
|
-
rescue Object => e
|
191
|
-
fail "too many retries" if retries == 0
|
192
|
-
puts "There was an error: #{e.class}:#{e.message}"
|
193
|
-
puts "Try again or hit CTRL-C"
|
194
|
-
value = nil
|
195
|
-
retries -= 1
|
196
|
-
retry
|
197
|
-
end
|
198
|
-
|
199
|
-
end
|
200
|
-
|
201
|
-
def init
|
202
|
-
### sooooo ugly
|
203
|
-
require 'pp'
|
204
|
-
fail "you are already inside a judo repository" if find_judo_dir(Dir.pwd)
|
205
|
-
fail "./.git not found - judo configurations must be kept in a git repo. type 'git init' to setup the git repo." unless File.exists? "./.git"
|
206
|
-
aws_id = collect(['AWS_ACCESS_KEY_ID', 'AMAZON_ACCESS_KEY_ID'], "Please enter your AWS access key")
|
207
|
-
aws_secret = collect(['AWS_SECRET_ACCESS_KEY', 'AMAZON_SECRET_ACCESS_KEY'], "Please enter your AWS secret key") do |aws_secret|
|
208
|
-
puts "Trying to connect to SimpleDB with #{aws_id}:#{aws_secret}"
|
209
|
-
@sdb = Aws::SdbInterface.new(aws_id, aws_secret, :logger => Logger.new(nil))
|
210
|
-
@sdb.create_domain("judo_servers")
|
211
|
-
@sdb.create_domain("judo_config")
|
212
|
-
end
|
213
|
-
|
214
|
-
puts "setting up an s3 bucket"
|
215
|
-
s3_bucket = ENV['SUMO_S3_BUCKET'] || "judo_#{rand(2**128).to_s(16)}"
|
216
|
-
Fog::AWS::S3.new( :aws_access_key_id => aws_id, :aws_secret_access_key => aws_secret).put_bucket(s3_bucket)
|
217
|
-
|
218
|
-
puts "setting up an .judo/config.yml"
|
219
|
-
system "mkdir .judo"
|
220
|
-
File.open(".judo/config.yml","w") { |f| f.write({ "access_id" => aws_id, "access_secret" => aws_secret, "s3_bucket" => s3_bucket }.to_yaml) }
|
221
|
-
|
222
|
-
puts "Setting up default config and keypair"
|
223
|
-
system "mkdir default"
|
224
|
-
keypair = "judo_#{rand(2**64).to_s(16)}"
|
225
|
-
@ec2 = Aws::Ec2.new(access_id, access_secret, :logger => Logger.new(nil))
|
226
|
-
material = @ec2.create_key_pair(keypair)[:aws_material]
|
227
|
-
File.open("default/#{keypair}.pem", 'w') { |f| f.write material }
|
228
|
-
File.chmod 0600, "default/#{keypair}.pem"
|
229
|
-
File.open("default/config.json","w") { |f| f.write default_config.merge({ "keypair" => keypair }) }
|
230
|
-
puts "congratulations! - you're ready to go!"
|
231
|
-
end
|
232
101
|
end
|
233
102
|
end
|
data/lib/group.rb
CHANGED
@@ -2,12 +2,12 @@ module Judo
|
|
2
2
|
class Group
|
3
3
|
attr_accessor :name, :dir
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
def self.dirs
|
6
|
+
Dir["#{Judo::Config.repo_dir}/*/config.json"].map { |d| File.dirname(d) }
|
7
|
+
end
|
8
8
|
|
9
9
|
def self.all
|
10
|
-
@@all ||= (dirs.map { |d| new(d) }
|
10
|
+
@@all ||= (dirs.map { |d| new(d) })
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.find(name)
|
@@ -18,9 +18,9 @@ module Judo
|
|
18
18
|
find(name)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def self.current
|
22
|
+
all.detect { |d| Dir.pwd == d.dir or Dir.pwd =~ /^#{d.dir}\// }
|
23
|
+
end
|
24
24
|
|
25
25
|
def initialize(dir, name = File.basename(dir))
|
26
26
|
@name = name
|
@@ -28,13 +28,13 @@ module Judo
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def create_server(server_name)
|
31
|
-
|
32
|
-
#
|
33
|
-
#
|
31
|
+
abort("Server needs a name") if server_name.nil?
|
32
|
+
# abort("Already a server named #{server_name}") if Judo::Server.find_by_name(attrs[:name]) ## FIXME
|
33
|
+
# Judo::Config.read_config(attrs[:group]) ## make sure the config is valid ## FIXME
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
server = Judo::Server.new server_name, self
|
36
|
+
server.task("Creating server #{server_name}") do
|
37
|
+
server.update "name" => server_name, "group" => name, "virgin" => true, "secret" => rand(2 ** 128).to_s(36)
|
38
38
|
Judo::Config.sdb.put_attributes("judo_config", "groups", name => server_name)
|
39
39
|
end
|
40
40
|
server
|
@@ -45,15 +45,27 @@ module Judo
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def server_names
|
48
|
-
Judo::Config.sdb.get_attributes("judo_config", "groups"
|
48
|
+
Judo::Config.sdb.get_attributes("judo_config", "groups")[:attributes][@name] || []
|
49
49
|
end
|
50
50
|
|
51
51
|
def servers
|
52
52
|
server_names.map { |n| Judo::Server.new(n, self) }
|
53
53
|
end
|
54
54
|
|
55
|
+
def version
|
56
|
+
@version ||= (Judo::Config.sdb.get_attributes("judo_config", "group_versions")[:attributes][@name] || ["0"]).first.to_i
|
57
|
+
@version ||= (Judo::Config.sdb.get_attributes("judo_config", "group_versions")[:attributes][@name] || ["0"]).first.to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_version(new_version)
|
61
|
+
@version = new_version
|
62
|
+
Judo::Config.sdb.put_attributes("judo_config", "group_versions", { name => new_version }, :replace)
|
63
|
+
end
|
64
|
+
|
55
65
|
def compile
|
56
66
|
tmpdir = "/tmp/kuzushi/#{name}"
|
67
|
+
set_version(version + 1)
|
68
|
+
puts "Compiling version #{version}"
|
57
69
|
FileUtils.rm_rf(tmpdir)
|
58
70
|
FileUtils.mkdir_p(tmpdir)
|
59
71
|
Dir.chdir(tmpdir) do |d|
|
@@ -71,7 +83,7 @@ module Judo
|
|
71
83
|
end
|
72
84
|
|
73
85
|
def tar_file
|
74
|
-
"#{name}.tar.gz"
|
86
|
+
"#{name}.#{version}.tar.gz" ## FIXME needs to incorprate #{config version} "#{name}.#{version}.tar.gz"
|
75
87
|
end
|
76
88
|
|
77
89
|
def s3_url
|
@@ -88,7 +100,7 @@ module Judo
|
|
88
100
|
|
89
101
|
def extract_file(type, name, files)
|
90
102
|
path = "#{dir}/#{type}s/#{name}"
|
91
|
-
|
103
|
+
found = Dir[path]
|
92
104
|
if not found.empty?
|
93
105
|
found.each { |f| files["#{type}s/#{File.basename(f)}"] = f }
|
94
106
|
elsif parent
|
@@ -128,32 +140,27 @@ module Judo
|
|
128
140
|
end
|
129
141
|
|
130
142
|
def self.load_all(group, configs = [])
|
131
|
-
|
143
|
+
return configs.reverse.inject({}) { |sum,conf| sum.merge(conf) } unless group
|
132
144
|
raw_config = group.read_config
|
133
145
|
load_all(find(raw_config["import"]), configs << raw_config)
|
134
146
|
end
|
135
147
|
|
136
148
|
def config_file
|
137
|
-
|
138
|
-
"#{dir}/config.json"
|
149
|
+
"#{dir}/config.json"
|
139
150
|
end
|
140
151
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
152
|
+
def read_config
|
153
|
+
begin
|
154
|
+
JSON.parse(File.read(config_file))
|
155
|
+
rescue Errno::ENOENT
|
156
|
+
{}
|
157
|
+
end
|
158
|
+
end
|
148
159
|
|
149
160
|
def delete_server(server)
|
150
161
|
sdb.delete_attributes("judo_config", "groups", name => server.name)
|
151
162
|
end
|
152
163
|
|
153
|
-
def default?
|
154
|
-
false
|
155
|
-
end
|
156
|
-
|
157
164
|
def to_s
|
158
165
|
name
|
159
166
|
end
|
data/lib/server.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
### NEEDED for new gem launch
|
2
2
|
|
3
3
|
### 32 hrs to go - 12:00am Feb 26th - expected completion Mar 2
|
4
|
-
### [
|
5
|
-
### [
|
6
|
-
### [
|
7
|
-
### [
|
8
|
-
### [
|
4
|
+
### [X] judo init (2 hrs)
|
5
|
+
### [X] implement real default config - remove special case code (3 hrs)
|
6
|
+
### [X] refactor keypair.pem setup (3 hrs)
|
7
|
+
### [X] version in the db - require upgrade of gem if db version ahead (1 hr)
|
8
|
+
### [X] implement multiple security groups (1 hr)
|
9
|
+
### [-] complete slug compile - load into s3 (4 hrs)
|
10
|
+
### [X] compile and put in s3
|
11
|
+
### [X] attach and increment version number
|
12
|
+
### [X] list version number on "judo list"
|
13
|
+
### [ ] update kuzushi to pull down a compiled tar.gz
|
14
|
+
### [ ] error if version is blank
|
15
|
+
### [ ] two phase delete (1 hr)
|
16
|
+
### [-] refactor availability_zone (2 hrs)
|
17
|
+
### [ ] pick availability zone from config "X":"Y" or "X":["Y","Z"]
|
18
|
+
### [ ] assign to state on creation ( could delay till volume creation )
|
9
19
|
### [ ] implement auto security_group creation and setup (6 hrs)
|
10
|
-
### [ ] version in the db - require upgrade of gem if db version ahead (1 hr)
|
11
20
|
### [ ] write some examples - simple postgres/redis/couchdb server (5hrs)
|
12
|
-
### [ ] two phase delete (1 hr)
|
13
21
|
### [ ] write new README (4 hrs)
|
14
22
|
### [ ] realase new gem! (1 hr)
|
15
23
|
|
16
24
|
### [ ] user a logger service (1 hr)
|
17
|
-
### [ ] write
|
25
|
+
### [ ] write specs (5 hr)
|
18
26
|
|
19
27
|
### Do Later
|
20
28
|
### [ ] use amazon's new conditional write tools so we never have problems from concurrent updates
|
@@ -97,6 +105,18 @@ module Judo
|
|
97
105
|
get "elastic_ip"
|
98
106
|
end
|
99
107
|
|
108
|
+
def version_desc
|
109
|
+
if version.to_i == group.version.to_i
|
110
|
+
"v#{version}"
|
111
|
+
else
|
112
|
+
"v#{version}/#{group.version}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def version
|
117
|
+
get "version"
|
118
|
+
end
|
119
|
+
|
100
120
|
def virgin?
|
101
121
|
get("virgin").to_s == "true" ## I'm going to set it to true and it will come back from the db as "true" -> could be "false" or false or nil also
|
102
122
|
end
|
@@ -274,20 +294,24 @@ module Judo
|
|
274
294
|
end
|
275
295
|
|
276
296
|
def launch_ec2
|
277
|
-
validate
|
297
|
+
# validate
|
278
298
|
|
279
299
|
## EC2 launch_instances
|
280
300
|
result = Config.ec2.launch_instances(ami,
|
281
301
|
:instance_type => config["instance_size"],
|
282
302
|
:availability_zone => config["availability_zone"],
|
283
303
|
:key_name => config["key_name"],
|
284
|
-
:group_ids =>
|
304
|
+
:group_ids => security_groups,
|
285
305
|
:user_data => user_data).first
|
286
306
|
|
287
|
-
update "instance_id" => result[:aws_instance_id], "virgin" => false
|
307
|
+
update "instance_id" => result[:aws_instance_id], "virgin" => false, "version" => group.version
|
288
308
|
# remove "virgin"
|
289
309
|
end
|
290
310
|
|
311
|
+
def security_groups
|
312
|
+
[ config["security_group"] ].flatten
|
313
|
+
end
|
314
|
+
|
291
315
|
def console_output
|
292
316
|
### EC2 get_console_output
|
293
317
|
Config.ec2.get_console_output(instance_id)[:aws_output]
|
@@ -439,7 +463,7 @@ USER_DATA
|
|
439
463
|
end
|
440
464
|
|
441
465
|
def url
|
442
|
-
|
466
|
+
group.s3_url
|
443
467
|
end
|
444
468
|
|
445
469
|
def validate
|
data/lib/setup.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module Judo
|
2
|
+
class Setup
|
3
|
+
def default_config
|
4
|
+
<<DEFAULT
|
5
|
+
{
|
6
|
+
"key_name":"#{@keypair}",
|
7
|
+
"instance_size":"m1.small",
|
8
|
+
"ami32":"ami-bb709dd2", // public ubuntu 9.10 ami - 32 bit
|
9
|
+
"ami64":"ami-55739e3c", // public ubuntu 9.10 ami - 64 bit
|
10
|
+
"user":"ubuntu",
|
11
|
+
"security_group":"judo",
|
12
|
+
"availability_zone":"us-east-1d"
|
13
|
+
}
|
14
|
+
DEFAULT
|
15
|
+
end
|
16
|
+
|
17
|
+
def getenv(key)
|
18
|
+
printf "Looking in your environment for #{key}..."
|
19
|
+
printf "found!" if ENV[key]
|
20
|
+
printf "\n"
|
21
|
+
ENV[key]
|
22
|
+
end
|
23
|
+
|
24
|
+
def request(query, default = "")
|
25
|
+
printf "#{query} ['#{default}']: "
|
26
|
+
input = STDIN.readline.strip
|
27
|
+
input.empty? and default or input
|
28
|
+
end
|
29
|
+
|
30
|
+
def failure(msg)
|
31
|
+
puts msg
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_setup
|
36
|
+
failure "you are already inside a judo repository" if Judo::Config.find_judo_dir(Dir.pwd)
|
37
|
+
failure "./.git not found - judo configurations must be kept in a git repo. type 'git init' to setup the git repo." unless File.exists? "./.git"
|
38
|
+
end
|
39
|
+
|
40
|
+
def init
|
41
|
+
check_setup
|
42
|
+
@aws_access_id ||= getenv('AWS_ACCESS_KEY_ID')
|
43
|
+
@aws_access_id ||= getenv('AWS_ACCESS_KEY_ID')
|
44
|
+
@aws_secret_key ||= getenv('AWS_SECRET_ACCESS_KEY')
|
45
|
+
@aws_secret_key ||= getenv('AMAZON_SECRET_ACCESS_KEY')
|
46
|
+
@s3_bucket ||= getenv('JUDO_S3_BUCKET')
|
47
|
+
@s3_bucket ||= "judo_#{rand(2**64).to_s(36)}"
|
48
|
+
begin
|
49
|
+
@aws_access_id = request("Please enter your AWS access key", @aws_access_id)
|
50
|
+
@aws_secret_key = request("Please enter your AWS secret key" , @aws_secret_key)
|
51
|
+
@s3_bucket = request("Please enter an S3 bucket to use", @s3_bucket)
|
52
|
+
|
53
|
+
setup_default_server_group
|
54
|
+
setup_default_security_group
|
55
|
+
setup_bucket
|
56
|
+
setup_db
|
57
|
+
setup_judo_config
|
58
|
+
|
59
|
+
rescue *[Interrupt, EOFError]
|
60
|
+
puts "\nGoodbye!"
|
61
|
+
exit(0)
|
62
|
+
rescue Object => e
|
63
|
+
puts "There was an error: #{e.class}:#{e.message}"
|
64
|
+
puts "Try again or hit CTRL-C"
|
65
|
+
retry
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def setup_db
|
70
|
+
puts "Trying to connect to SimpleDB with #{@aws_access_id}"
|
71
|
+
sdb.create_domain("judo_servers")
|
72
|
+
sdb.create_domain("judo_config")
|
73
|
+
olddb = sdb.get_attributes("judo_config", "judo")[:attributes]["dbversion"]
|
74
|
+
failure "There is an existing judo database of a newer version - upgrade judo and try again" if olddb and olddb.first.to_i > Judo::Config.db_version
|
75
|
+
sdb.put_attributes("judo_config", "judo", { "dbversion" => Judo::Config.db_version }, :replace)
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup_default_security_group
|
79
|
+
ec2.create_security_group('judo', 'Judo')
|
80
|
+
ec2.authorize_security_group_IP_ingress("judo", 22, 22,'tcp','0.0.0.0/0')
|
81
|
+
end
|
82
|
+
|
83
|
+
def setup_bucket
|
84
|
+
puts "setting up an s3 bucket"
|
85
|
+
Fog::AWS::S3.new(:aws_access_key_id => @aws_access_id, :aws_secret_access_key => @aws_secret_key).put_bucket(@s3_bucket)
|
86
|
+
end
|
87
|
+
|
88
|
+
def setup_default_server_group
|
89
|
+
puts "Setting up default group and keypair"
|
90
|
+
system "mkdir -p default/keypairs"
|
91
|
+
|
92
|
+
@keypair = "judo#{ec2.describe_key_pairs.map { |k| k[:aws_key_name] }.map { |k| k =~ /^judo(\d*)/; $1.to_i }.sort.last.to_i + 1}"
|
93
|
+
material = ec2.create_key_pair(@keypair)[:aws_material]
|
94
|
+
|
95
|
+
File.open("default/keypairs/#{@keypair}.pem", 'w') { |f| f.write material }
|
96
|
+
File.chmod 0600, "default/keypairs/#{@keypair}.pem"
|
97
|
+
File.open("default/config.json","w") { |f| f.write default_config }
|
98
|
+
end
|
99
|
+
|
100
|
+
def setup_judo_config
|
101
|
+
puts "setting up an .judo/config.yml"
|
102
|
+
system "mkdir .judo"
|
103
|
+
File.open(".judo/config.yml","w") { |f| f.write({ "access_id" => @aws_access_id, "access_secret" => @aws_secret_key, "s3_bucket" => @s3_bucket }.to_yaml) }
|
104
|
+
end
|
105
|
+
|
106
|
+
def ec2
|
107
|
+
@ec2 ||= Judo::Config.get_ec2(@aws_access_id, @aws_secret_key)
|
108
|
+
end
|
109
|
+
|
110
|
+
def sdb
|
111
|
+
@sdb ||= Judo::Config.get_sdb(@aws_access_id, @aws_secret_key)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: judo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Orion Henry
|
@@ -9,50 +14,70 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-03 00:00:00 -08:00
|
13
18
|
default_executable: judo
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: uuidtools
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
25
32
|
- !ruby/object:Gem::Dependency
|
26
33
|
name: aws
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
33
41
|
version: "0"
|
34
|
-
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id002
|
35
44
|
- !ruby/object:Gem::Dependency
|
36
45
|
name: thor
|
37
|
-
|
38
|
-
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
48
|
requirements:
|
41
49
|
- - ">="
|
42
50
|
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
43
53
|
version: "0"
|
44
|
-
|
54
|
+
type: :runtime
|
55
|
+
version_requirements: *id003
|
45
56
|
- !ruby/object:Gem::Dependency
|
46
57
|
name: json
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
47
66
|
type: :runtime
|
48
|
-
|
49
|
-
|
67
|
+
version_requirements: *id004
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: fog
|
70
|
+
prerelease: false
|
71
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
50
72
|
requirements:
|
51
73
|
- - ">="
|
52
74
|
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
53
77
|
version: "0"
|
54
|
-
|
55
|
-
|
78
|
+
type: :runtime
|
79
|
+
version_requirements: *id005
|
80
|
+
description: The gentile way to manage and control ec2 instances
|
56
81
|
email: orion@heroku.com
|
57
82
|
executables:
|
58
83
|
- judo
|
@@ -69,6 +94,7 @@ files:
|
|
69
94
|
- lib/config.rb
|
70
95
|
- lib/group.rb
|
71
96
|
- lib/server.rb
|
97
|
+
- lib/setup.rb
|
72
98
|
- spec/base.rb
|
73
99
|
- spec/server_spec.rb
|
74
100
|
has_rdoc: true
|
@@ -84,21 +110,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
110
|
requirements:
|
85
111
|
- - ">="
|
86
112
|
- !ruby/object:Gem::Version
|
113
|
+
segments:
|
114
|
+
- 0
|
87
115
|
version: "0"
|
88
|
-
version:
|
89
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
117
|
requirements:
|
91
118
|
- - ">="
|
92
119
|
- !ruby/object:Gem::Version
|
120
|
+
segments:
|
121
|
+
- 0
|
93
122
|
version: "0"
|
94
|
-
version:
|
95
123
|
requirements: []
|
96
124
|
|
97
125
|
rubyforge_project: judo
|
98
|
-
rubygems_version: 1.3.
|
126
|
+
rubygems_version: 1.3.6
|
99
127
|
signing_key:
|
100
128
|
specification_version: 3
|
101
|
-
summary:
|
129
|
+
summary: The gentile way to manage and control ec2 instances
|
102
130
|
test_files:
|
103
131
|
- spec/base.rb
|
104
132
|
- spec/server_spec.rb
|