judo 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.4
1
+ 0.5.0
data/bin/judo CHANGED
@@ -2,13 +2,11 @@
2
2
 
3
3
  require 'optparse'
4
4
  require File.dirname(__FILE__) + '/../lib/judo'
5
- require File.dirname(__FILE__) + '/../lib/judo/commandline_helpers'
5
+ require File.dirname(__FILE__) + '/../lib/judo/cli_helpers'
6
6
 
7
- include JudoCommandLineHelpers
7
+ include Judo::CLIHelpers
8
8
 
9
- defaults = Judo::Base.default_options(Dir.pwd)
10
-
11
- options = {}
9
+ options = Judo::Base.defaults
12
10
 
13
11
  ARGV.unshift "-h" if ARGV.size == 0
14
12
 
@@ -52,22 +50,15 @@ Usage: judo launch [options] SERVER ...
52
50
 
53
51
  banner
54
52
 
55
- # start stop create destroy launch restart info console
56
- # list volumes ips
57
-
58
- opts.on( '-c', '--config DIR', 'Specify the location of the config dir' ) do |dir|
59
- defaults[:judo_dir] = dir
60
- defaults.merge(Judo::Base.default_options(Dir.pwd, dir))
53
+ opts.on( '-a', '--accessid ID', 'Specify the AWS access ID' ) do |id|
54
+ options[:access_id] = id
55
+ end
56
+ opts.on( '-s', '--secret KEY', 'Specify the AWS access secret key' ) do |key|
57
+ options[:access_secret] = key
61
58
  end
62
59
  opts.on( '-f', '--force', 'Force a stop or restart (immediately force detach volumes)' ) do
63
60
  options[:force] = true
64
61
  end
65
- opts.on( '-d', '--domain DOMAIN', 'Specify a judo domain within an AWS account' ) do |domain|
66
- options[:domain] = domain
67
- end
68
- opts.on( '-r', '--repo DIR', 'Specify the location of the repo dir' ) do |dir|
69
- options[:repo] = dir
70
- end
71
62
  opts.on( '-t', '--type TYPE', 'Specify an instance type different from the config on server start' ) do |type|
72
63
  options[:instance_type] = type
73
64
  end
@@ -82,25 +73,6 @@ banner
82
73
  opts.on( '-i', '--ip IP', 'Specify an exsiting elastic_ip address on server creation' ) do |ip|
83
74
  options[:elastic_ip] = ip
84
75
  end
85
- opts.on( '-a', '--accessid ID', 'Specify the AWS access ID' ) do |id|
86
- options[:access_id] = id
87
- end
88
- opts.on( '-k', '--keypair KEY', 'Speicy the AWS keypair pem file to use or \'create\'' ) do |key|
89
- if key == 'create'
90
- options[:key_create] = true
91
- elsif File.basename(key) =~ /(.*)[.]pem$/
92
- options[:key_name] = $1
93
- options[:key_material] = File.new(key).read
94
- else
95
- abort "Key file must be KEY_NAME.pem"
96
- end
97
- end
98
- opts.on( '-s', '--secret KEY', 'Specify the AWS access secret key' ) do |key|
99
- options[:access_secret] = key
100
- end
101
- opts.on( '-b', '--bucket BUCKET', 'Specify the AWS S3 bucket to use' ) do |bucket|
102
- options[:bucket] = bucket
103
- end
104
76
  opts.on( '-v', '--version VERSION', 'Update the servers config version on create/start/launch' ) do |version|
105
77
  options[:version] = version
106
78
  end
@@ -113,31 +85,27 @@ end
113
85
  optparse.parse!
114
86
 
115
87
  action = ARGV.shift
116
- judo = Judo::Base.new(defaults.merge(options))
117
- judo.check_version if action != "setup"
88
+ judo = Judo::Base.new(options)
89
+ judo.ensure_setup unless action == "generate"
118
90
 
119
91
  begin
120
92
  case action
121
- when "setup" then judo.setup
122
- when "ips" then do_ips(judo)
123
- when "volumes" then do_volumes(judo)
124
- when "list" then do_list(judo, ARGV)
125
- when "groups" then do_groups(judo)
126
- when "watch" then each_server(judo, ARGV) { |s| s.ssh_command("tail -n 1000 -f /var/log/kuzushi.log") }
127
- when "info" then each_server(judo, ARGV) { |s| do_info(judo, s) }
128
- when "console" then each_server(judo, ARGV) { |s| puts s.console_output }
129
- when "commit" then mk_groups(judo, ARGV) { |g| g.compile }
130
- when "ssh" then each_server(judo, ARGV) { |s| s.connect_ssh }
131
- when "start" then each_server(judo, ARGV) { |s| s.start(options) }
132
- when "restart" then each_server(judo, ARGV) { |s| s.restart(options) }
133
- when "stop" then each_server(judo, ARGV) { |s| s.stop(options) }
134
- when "create" then mk_servers(judo, options, ARGV, false)
135
- when "launch" then mk_servers(judo, options, ARGV, true)
136
- when "snapshots" then do_snapshots(judo, ARGV)
137
- when "config" then
138
- puts "Judo DB Version: #{judo.db_version}"
139
- puts "Judo Key Pair: #{judo.key_name}"
140
- puts "Judo Bucket: #{judo.bucket_name}"
93
+ when "generate" then do_generate(judo, ARGV)
94
+ when "commit" then do_commit(judo, ARGV)
95
+ when "ips" then do_ips(judo)
96
+ when "volumes" then do_volumes(judo)
97
+ when "list" then do_list(judo, ARGV)
98
+ when "groups" then do_groups(judo)
99
+ when "snapshots" then do_snapshots(judo, ARGV)
100
+ when "watch" then each_server(judo, ARGV) { |s| s.ssh_command("tail -n 1000 -f /var/log/kuzushi.log") }
101
+ when "info" then each_server(judo, ARGV) { |s| do_info(judo, s) }
102
+ when "console" then each_server(judo, ARGV) { |s| puts s.console_output }
103
+ when "ssh" then each_server(judo, ARGV) { |s| s.connect_ssh }
104
+ when "start" then each_server(judo, ARGV) { |s| s.start(options) }
105
+ when "restart" then each_server(judo, ARGV) { |s| s.restart(options) }
106
+ when "stop" then each_server(judo, ARGV) { |s| s.stop(options) }
107
+ when "create" then mk_servers(judo, options, ARGV, false)
108
+ when "launch" then mk_servers(judo, options, ARGV, true)
141
109
  when "rename" then
142
110
  raise JudoError, "usage: judo rename SERVER SERVER" unless ARGV.size == 2
143
111
  server = judo.find_server(ARGV[0]).rename(ARGV[1])
@@ -2,7 +2,7 @@
2
2
 
3
3
  kuzushi-setup ## this will wait for all the volumes to attach and take care of mounting and formatting them
4
4
 
5
- if [ "$JUDO_FIRST_BOOT" ] ; then
5
+ if [ "$JUDO_FIRST_BOOT" = "true" ] ; then
6
6
  ## do some setup on the first boot only
7
7
  fi
8
8
 
@@ -21,8 +21,6 @@
21
21
  ## id - this is random string that uniqily identifies the server for its lifetime
22
22
  ## name - the name of the server
23
23
  ## group_name - the name of group the server is in
24
- ## domain - this is the JUDO_DOMAIN currently running
25
- ## secret - this is a 128bit random string assigned to an instance at creation time - great for passwords
26
24
  ## metadata - a hash of metadata associated with the server with --data KEY=VALUE
27
25
  ## boot - a hash of boot options passed to the server with --boot KEY=VALUE
28
26
  ## first_boot? - is set to true or false depending on if this is the instance's first boot
@@ -33,8 +31,6 @@ set -x
33
31
 
34
32
  export JUDO_ID='<%= id %>'
35
33
  export JUDO_NAME='<%= name %>'
36
- export JUDO_DOMAIN='<%= domain %>'
37
- export JUDO_SECRET='<%= secret %>'
38
34
  export JUDO_FIRST_BOOT='<%= first_boot? %>'
39
35
 
40
36
  hostname <%= name %>
@@ -16,4 +16,4 @@ require File.dirname(__FILE__) + '/judo/base'
16
16
  require File.dirname(__FILE__) + '/judo/group'
17
17
  require File.dirname(__FILE__) + '/judo/server'
18
18
  require File.dirname(__FILE__) + '/judo/snapshot'
19
-
19
+ require File.dirname(__FILE__) + '/judo/patch'
@@ -1,17 +1,41 @@
1
1
  module Judo
2
2
  class Base
3
- attr_accessor :judo_dir, :repo, :group, :domain
3
+ attr_accessor :group
4
4
 
5
- def initialize(options = Judo::Base.default_options)
6
- @judo_dir = File.expand_path(options[:judo_dir]) if options[:judo_dir]
7
- @repo = File.expand_path(options[:repo]) if options[:repo]
8
- @bucket_name = options[:bucket]
5
+ def self.defaults
6
+ {
7
+ :access_id => ENV['AWS_ACCESS_KEY_ID'],
8
+ :access_secret => ENV['AWS_SECRET_ACCESS_KEY']
9
+ }
10
+ end
11
+
12
+ def initialize(options)
9
13
  @access_id = options[:access_id]
10
14
  @access_secret = options[:access_secret]
11
- @domain = options[:domain]
12
- @key_name = options[:key_name]
13
- @key_material = options[:key_material]
14
- @key_create = options[:key_create]
15
+ end
16
+
17
+ def access_id
18
+ @access_id || (raise JudoError, "no AWS Access ID specified")
19
+ end
20
+
21
+ def access_secret
22
+ @access_secret || (raise JudoError, "no AWS Secret Key specified")
23
+ end
24
+
25
+ def bucket_name
26
+ "judo_#{access_id}"
27
+ end
28
+
29
+ def server_domain
30
+ "judo_servers"
31
+ end
32
+
33
+ def snapshot_domain
34
+ "judo_snapshots"
35
+ end
36
+
37
+ def base_domain
38
+ "judo_base"
15
39
  end
16
40
 
17
41
  def find_groups(names)
@@ -20,7 +44,7 @@ module Judo
20
44
  groups.detect { |g| g.displayname == name } || (raise JudoError, "No such group #{name}")
21
45
  end
22
46
  end
23
-
47
+
24
48
  def find_server(name)
25
49
  find_servers([name]).first
26
50
  end
@@ -41,7 +65,7 @@ module Judo
41
65
  def find_servers_by_name_or_groups(*names)
42
66
  just_servers = names.flatten.reject { |s| s =~ /^:/ }
43
67
  just_groups = names.flatten.select { |s| s =~ /^:/ }
44
-
68
+
45
69
  [find_groups(just_groups).map { |g| g.servers } + find_servers(just_servers)].flatten
46
70
  end
47
71
 
@@ -70,59 +94,6 @@ module Judo
70
94
  end
71
95
  end
72
96
 
73
- def sdb_domain(name)
74
- if @domain
75
- "#{@domain}_#{name}"
76
- else
77
- name
78
- end
79
- end
80
-
81
- def server_domain
82
- sdb_domain("judo_servers")
83
- end
84
-
85
- def snapshot_domain
86
- sdb_domain("judo_snapshots")
87
- end
88
-
89
- def base_domain
90
- sdb_domain("judo_config")
91
- end
92
-
93
- def self.default_options(pwd = Dir.pwd, dir = find_judo_dir(pwd))
94
- config = YAML.load File.read("#{dir}/config.yml")
95
- repo_dir = config["repo"] || File.dirname(dir)
96
- group_config = Dir["#{repo_dir}/*/config.json"].detect { |d| File.dirname(d) == pwd }
97
- {
98
- :judo_dir => dir,
99
- :repo => repo_dir,
100
- :domain => (config["domain"] || ENV['JUDO_DOMAIN']),
101
- :bucket => (config["s3_bucket"] || ENV['JUDO_BUCKET']),
102
- :access_id => (config["access_id"] || ENV['AWS_ACCESS_KEY_ID']),
103
- :access_secret => (config["access_secret"] || ENV['AWS_SECRET_ACCESS_KEY'])
104
- }.delete_if { |key,value| value.nil? }
105
- rescue Object => e
106
- {
107
- :access_id => ENV['AWS_ACCESS_KEY_ID'],
108
- :access_secret => ENV['AWS_SECRET_ACCESS_KEY'],
109
- :bucket => ENV['JUDO_BUCKET'],
110
- :domain => ENV['JUDO_DOMAIN'],
111
- }.delete_if { |key,value| value.nil? }
112
- end
113
-
114
- def self.find_judo_dir(check)
115
- if check == "/"
116
- if File.exists?("#{ENV['HOME']}/.judo")
117
- "#{ENV['HOME']}/.judo"
118
- else
119
- nil
120
- end
121
- else
122
- File.exists?(check + "/.judo") ? check + "/.judo" : find_judo_dir(File.dirname(check))
123
- end
124
- end
125
-
126
97
  def sdb
127
98
  @sdb ||= Aws::SdbInterface.new(access_id, access_secret, :logger => Logger.new(nil))
128
99
  end
@@ -167,17 +138,9 @@ module Judo
167
138
  rand(2**32).to_s(36)
168
139
  end
169
140
 
170
- def default_group_dir
171
- File.expand_path(File.dirname(__FILE__) + "/../../default")
172
- end
173
-
174
- def default_file(name)
175
- "#{default_group_dir}/#{name}"
176
- end
177
-
178
141
  def mk_server_name(group)
179
- index = servers.map { |s| (s.name =~ /^#{s.group.name}.(\d*)$/); $1.to_i }.sort.last.to_i + 1
180
- "#{group}#{index}"
142
+ index = servers.map { |s| (s.name =~ /^#{s.group.name}.(\d*)$/); $1.to_i }.sort.last.to_i + 1
143
+ "#{group}#{index}"
181
144
  end
182
145
 
183
146
  def create_server(name, group, options)
@@ -224,7 +187,7 @@ module Judo
224
187
  end
225
188
 
226
189
  def ec2_snapshots
227
- @ec2_snapshots ||= ec2.describe_snapshots
190
+ @ec2_snapshots ||= ec2.describe_snapshots([], :owner => "self")
228
191
  end
229
192
 
230
193
  def ec2_instances
@@ -235,29 +198,10 @@ module Judo
235
198
  @ec2 ||= Aws::Ec2.new(access_id, access_secret, :logger => Logger.new(nil))
236
199
  end
237
200
 
238
- def groups_config
239
- @groups_config ||= sdb.get_attributes(base_domain, "groups")[:attributes]
240
- end
241
-
242
201
  def group_versions
243
202
  @group_version ||= sdb.get_attributes(base_domain, "group_versions")[:attributes]
244
203
  end
245
204
 
246
- def set_keypair(key_name, material)
247
- @key_name = key_name
248
- @key_material = material
249
- s3_put("#{key_name}.pem", material)
250
- update "key_name" => key_name
251
- end
252
-
253
- def key_name
254
- @key_name ||= get("key_name")
255
- end
256
-
257
- def key_material
258
- @key_material ||= s3_get("#{key_name}.pem")
259
- end
260
-
261
205
  def ip_to_judo(ip)
262
206
  servers.detect { |s| s.elastic_ip == ip }
263
207
  end
@@ -275,78 +219,15 @@ module Judo
275
219
  end
276
220
 
277
221
  def s3_url(k)
278
- Aws::S3Generator::Key.new(bucket, s3_key(k)).get
222
+ Aws::S3Generator::Key.new(bucket, k).get
279
223
  end
280
224
 
281
225
  def s3_get(k)
282
- bucket.get( s3_key(k))
226
+ bucket.get(k)
283
227
  end
284
228
 
285
229
  def s3_put(k, file)
286
- bucket.put( s3_key(k), file)
287
- end
288
-
289
- def s3_key(k)
290
- if @domain
291
- "#{@domain}/#{k}"
292
- else
293
- k
294
- end
295
- end
296
-
297
- def repo
298
- raise JudoError, "no repo dir specified" unless @repo
299
- raise JudoError, "repo dir not found" unless File.exists?(@repo)
300
- @repo
301
- end
302
-
303
- def access_id
304
- @access_id || (raise JudoError, "no AWS Access ID specified")
305
- end
306
-
307
- def access_secret
308
- @access_secret || (raise JudoError, "no AWS Secret Key specified")
309
- end
310
-
311
- ## this is a little funny - does not work like the others - can specify bucket on cmdline or env - but if not takes from judo state
312
- def bucket_name
313
- (@bucket_name ||= get("bucket")) || (raise JudoError, "no S3 bucket name specified")
314
- end
315
-
316
- def set_bucket_name(new_name)
317
- @bucket_name = new_name
318
- update "bucket" => @bucket_name
319
- end
320
-
321
- def db_version
322
- 2
323
- end
324
-
325
- def upgrade_db
326
- case get_db_version
327
- when 0
328
- task("Upgrading Judo: Creating Snapshots SDB Domain") do
329
- sdb.create_domain(server_domain)
330
- sdb.create_domain(base_domain)
331
- sdb.create_domain(snapshot_domain)
332
- set_db_version(2)
333
- end
334
- when 1
335
- task("Upgrading Judo: Creating Snapshots SDB Domain") do
336
- sdb.create_domain(snapshot_domain)
337
- set_db_version(2)
338
- end
339
- else
340
- raise JudoError, "judo db is newer than the current gem - upgrade judo and try again"
341
- end
342
- end
343
-
344
- def set_db_version(new_version)
345
- update "dbversion" => new_version
346
- end
347
-
348
- def get_db_version
349
- get("dbversion").to_i
230
+ bucket.put(k, file)
350
231
  end
351
232
 
352
233
  def get(key)
@@ -363,113 +244,83 @@ module Judo
363
244
  @state ||= sdb.get_attributes(base_domain, "judo")[:attributes]
364
245
  end
365
246
 
366
- def check_version
367
- upgrade_db if get_db_version != db_version
368
- rescue Aws::AwsError => e
369
- setup_sdb
370
- upgrade_db
247
+ def ensure_setup
248
+ ensure_init
249
+ ensure_db_version
371
250
  end
372
251
 
373
- def setup(options = {})
374
- @repo ||= "." ## use cwd as default repo dir
375
-
376
- setup_sdb
377
- setup_keypair
378
- setup_bucket
379
- setup_security_group
380
- setup_judo_config
381
- setup_repo
252
+ def ensure_init
253
+ if !has_init?
254
+ init_sdb
255
+ init_security_group
256
+ init_keypair
257
+ end
382
258
  end
383
259
 
384
- def setup_sdb
385
- task("Trying to connect to SimpleDB") do
386
- sdb.create_domain(base_domain)
387
- end
260
+ def has_init?
261
+ sdb.list_domains[:domains].include?(base_domain)
388
262
  end
389
263
 
390
- def setup_security_group
391
- begin
392
- ec2.create_security_group('judo', 'Judo')
393
- ec2.authorize_security_group_IP_ingress("judo", 22, 22,'tcp','0.0.0.0/0')
394
- rescue Aws::AwsError => e
395
- raise unless e.message =~ /InvalidGroup.Duplicate/
264
+ def init_sdb
265
+ task("Initializing Judo SDB") do
266
+ sdb.create_domain(base_domain)
396
267
  end
397
268
  end
398
269
 
399
- def setup_judo_config
400
- if judo_dir and File.exists?("#{judo_dir}/config.yml")
401
- puts "config already exists [#{judo_dir}/config.yml]"
402
- return
403
- end
404
- raise JudoError, "You must specify a repo dir" unless repo
405
- task("writing .judo/config.yml") do
406
- Dir.chdir(repo) do
407
- if File.exists?(".judo/config.yml")
408
- puts ".judo folder already exists"
409
- else
410
- system "mkdir .judo"
411
- File.open(".judo/config.yml","w") do |f|
412
- f.write({ "access_id" => access_id, "access_secret" => access_secret, "s3_bucket" => bucket_name }.to_yaml)
413
- end
414
- end
270
+ def init_security_group
271
+ task("Initializing Judo Security Group") do
272
+ begin
273
+ ec2.create_security_group('judo', 'Judo')
274
+ ec2.authorize_security_group_IP_ingress("judo", 22, 22,'tcp','0.0.0.0/0')
275
+ rescue Aws::AwsError => e
276
+ raise unless e.message =~ /InvalidGroup.Duplicate/
415
277
  end
416
278
  end
417
279
  end
418
280
 
419
- def setup_repo
420
- if File.exists?("#{repo}/default")
421
- puts "default group already exists [#{repo}/default]"
422
- return
423
- end
424
- task("Setting up default group") do
425
- FileUtils.cp_r(default_group_dir, repo)
426
- get_group("default").compile
281
+ def init_keypair
282
+ task("Initializing Judo Keypair") do
283
+ ec2.delete_key_pair("judo")
284
+ material = ec2.create_key_pair("judo")[:aws_material]
285
+ s3_put("judo.pem", material)
427
286
  end
428
287
  end
429
288
 
430
289
  def keypair_file(&blk)
431
- Tempfile.open("judo_pem") do |file|
432
- file.write key_material
290
+ Tempfile.open("judo.pem") do |file|
291
+ file.write(s3_get("judo.pem"))
433
292
  file.flush
434
293
  blk.call(file.path)
435
294
  end
436
295
  end
437
296
 
438
- def setup_bucket
439
- if name = get("bucket_name")
440
- puts "Bucket #{name} already set"
441
- else
442
- puts "Setting bucket name #{bucket_name}"
443
- set_bucket_name(bucket_name)
444
- end
297
+ def set_db_version(new_version)
298
+ update "dbversion" => new_version
445
299
  end
446
300
 
447
- def setup_keypair
448
- if @key_name and @key_material
449
- task("Setting keypair #{@key_name}") do
450
- set_keypair(@key_name, @key_material)
301
+ def get_db_version
302
+ get("dbversion").to_i
303
+ end
304
+
305
+ def ensure_db_version
306
+ case get_db_version
307
+ when 0
308
+ task("Upgrading Judo SDB from version 0 to 2") do
309
+ sdb.create_domain(server_domain)
310
+ sdb.create_domain(snapshot_domain)
311
+ set_db_version(2)
451
312
  end
452
- elsif @key_create or not key_name
453
- task("Generating an ssl keypair") do
454
- name = "judo#{ec2.describe_key_pairs.map { |k| k[:aws_key_name] }.map { |k| k =~ /^judo(\d*)/; $1.to_i }.sort.last.to_i + 1}"
455
- material = ec2.create_key_pair(name)[:aws_material]
456
- set_keypair(name, material)
313
+ when 1
314
+ task("Upgrading Judo SDB from version 1 to 2") do
315
+ sdb.create_domain(snapshot_domain)
316
+ set_db_version(2)
457
317
  end
318
+ when 2
319
+ # current version
458
320
  else
459
- puts "Keypair #{key_name} already set"
321
+ raise JudoError, "Judo SDB has higher version (#{get_db_version}) " +
322
+ "than current gem (2) - please upgrade Judo"
460
323
  end
461
324
  end
462
-
463
- def default_config
464
- <<DEFAULT
465
- {
466
- "ami32":"ami-2d4aa444", // public ubuntu 10.04 ami - 32 bit
467
- "ami64":"ami-fd4aa494", // public ubuntu 10.04 ami - 64 bit
468
- "user":"ubuntu",
469
- "security_group":"judo",
470
- "availability_zone":"us-east-1d"
471
- }
472
- DEFAULT
473
- end
474
325
  end
475
326
  end