judo 0.4.4 → 0.5.0

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