judo 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (10) hide show
  1. data/README.rdoc +2 -80
  2. data/Rakefile +2 -1
  3. data/VERSION +1 -1
  4. data/bin/judo +21 -23
  5. data/lib/all.rb +1 -3
  6. data/lib/config.rb +31 -162
  7. data/lib/group.rb +37 -30
  8. data/lib/server.rb +36 -12
  9. data/lib/setup.rb +115 -0
  10. metadata +50 -22
data/README.rdoc CHANGED
@@ -1,82 +1,4 @@
1
- = Tired of wrestling with server provisioning? Sumo!
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/adamwiggins/sumo
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 = "A no-hassle way to launch one-off EC2 instances from the command line"
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
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 = Sumo::Group.current
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}:#{Sumo::Config.ec2.describe_volumes([vol_id])}"
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 = Sumo::Group.current
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
- Sumo::Group.all.each do |g|
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 sumo repository in the current directory"
134
+ desc "init", "create a new judo repository in the current directory"
136
135
  def init
137
- Sumo::Config.init
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
- Sumo::Config.ec2.describe_volumes.map do |volume|
147
- [ volume[:aws_id], volume[:aws_size], volume[:aws_status], volume[:aws_device] || "", instance_id_to_sumo(volume[:aws_instance_id]) || volume[:aws_instance_id] || "", volume_id_to_sumo(volume[:aws_id]) ]
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
- Sumo::Config.ec2.describe_addresses.map do |ip|
160
- [ ip[:public_ip], instance_id_to_sumo(ip[:instance_id]) || ip[:instance_id], ip_to_sumo(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
- # group = Sumo::Config.group
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 = Sumo::Group.current
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 volume_id_to_sumo(volume)
199
- Sumo::Server.all.detect { |s| s.volumes.invert[volume] }
196
+ def volume_id_to_judo(volume)
197
+ Judo::Server.all.detect { |s| s.volumes.invert[volume] }
200
198
  end
201
199
 
202
- def ip_to_sumo(ip)
203
- Sumo::Server.all.detect { |s| s.state["elastic_ip"] == ip }
200
+ def ip_to_judo(ip)
201
+ Judo::Server.all.detect { |s| s.state["elastic_ip"] == ip }
204
202
  end
205
203
 
206
- def instance_id_to_sumo(instance_id)
207
- Sumo::Server.all.detect { |s| s.state["instance_id"] and s.state["instance_id"] == instance_id }
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__) + '/couchrest_hacks'
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
- ## FIXME - maybe write these to defaults.json and dont have them hidden here in the code...
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 default_config
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
- # def merged_config(name)
27
- # stack = load_config_stack(name)
28
- # stack.reverse.inject({}) { |sum,conf| sum.merge(conf) }
29
- # end
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
- # def load_config_stack(name, all = [])
32
- # return (all << defaults) if name.nil?
33
- # conf = read_config(name)
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"] || ENV["AWS_ACCESS_KEY_ID"] || (raise "please define access_id in #{judo_config_file} or in the env as AWS_ACCESS_KEY_ID")
26
+ judo_config["access_id"]
67
27
  end
68
28
 
69
29
  def access_secret
70
- judo_config["access_secret"] || ENV["AWS_SECRET_ACCESS_KEY"] || (raise "please define access_secet in #{judo_config_file} or in the env as AWS_SECRET_ACCESS_KEY")
30
+ judo_config["access_secret"]
71
31
  end
72
32
 
73
- def ec2
74
- @ec2 ||= Aws::Ec2.new(access_id, access_secret, :logger => Logger.new(nil))
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
- # def connect
92
- # @@con = Aws::ActiveSdb.establish_connection(Config.access_id, Config.access_secret, :logger => Logger.new(nil))
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 setup?
103
- # Sumo::Server.connection.list_domains[:domains].include? Sumo::Server.domain
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 = Aws::SdbInterface.new(access_id, access_secret, :logger => Logger.new(nil))
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
- # @s3 ||= RightAws::S3.new(access_id, access_secret, :logger => Logger.new(nil))
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
- def self.dirs
6
- Dir["#{Judo::Config.repo_dir}/*/config.json"].map { |d| File.dirname(d) }
7
- end
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) } << Group.new(Judo::Config.judo_dir, "default"))
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
- def self.current
22
- all.detect { |d| Dir.pwd == d.dir or Dir.pwd =~ /^#{d.dir}\// } || find("default")
23
- end
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
- 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
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
- 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)
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", @name)[:attributes][@name] || []
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
- found = Dir[path]
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
- return configs.reverse.inject(Judo::Config.defaults) { |sum,conf| sum.merge(conf) } unless group
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
- return "#{dir}/defaults.json" if name == "default"
138
- "#{dir}/config.json"
149
+ "#{dir}/config.json"
139
150
  end
140
151
 
141
- def read_config
142
- begin
143
- JSON.parse(File.read(config_file))
144
- rescue Errno::ENOENT
145
- {}
146
- end
147
- end
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
- ### [ ] judo init (2 hrs)
5
- ### [ ] implement real default config - remove special case code (3 hrs)
6
- ### [ ] complete slug compile - load into s3 (4 hrs)
7
- ### [ ] refactor availability_zone (2 hrs)
8
- ### [ ] refactor keypair.pem setup (3 hrs)
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 4 simple specs (1 hr)
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 => [config["security_group"]],
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
- "#{Judo::Config.couch_url}/#{group}"
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
- version: 0.0.1
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-02 00:00:00 -08:00
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
- type: :runtime
18
- version_requirement:
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
- version:
30
+ type: :runtime
31
+ version_requirements: *id001
25
32
  - !ruby/object:Gem::Dependency
26
33
  name: aws
27
- type: :runtime
28
- version_requirement:
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
- version:
42
+ type: :runtime
43
+ version_requirements: *id002
35
44
  - !ruby/object:Gem::Dependency
36
45
  name: thor
37
- type: :runtime
38
- version_requirement:
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
- version:
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
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
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
- version:
55
- description: A no-hassle way to launch one-off EC2 instances from the command line
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.5
126
+ rubygems_version: 1.3.6
99
127
  signing_key:
100
128
  specification_version: 3
101
- summary: A no-hassle way to launch one-off EC2 instances from the command line
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