judo 0.0.1 → 0.0.3
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.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
|