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.
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