rudy 0.4.0 → 0.6.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.
Files changed (135) hide show
  1. data/CHANGES.txt +54 -30
  2. data/README.rdoc +100 -12
  3. data/Rakefile +103 -8
  4. data/Rudyfile +119 -0
  5. data/bin/ird +175 -0
  6. data/bin/rudy +259 -156
  7. data/bin/rudy-ec2 +228 -95
  8. data/bin/rudy-s3 +76 -0
  9. data/bin/rudy-sdb +67 -0
  10. data/lib/annoy.rb +270 -0
  11. data/lib/console.rb +30 -9
  12. data/lib/escape.rb +305 -0
  13. data/lib/rudy.rb +151 -182
  14. data/lib/rudy/aws.rb +56 -49
  15. data/lib/rudy/aws/ec2.rb +47 -292
  16. data/lib/rudy/aws/ec2/address.rb +157 -0
  17. data/lib/rudy/aws/ec2/group.rb +301 -0
  18. data/lib/rudy/aws/ec2/image.rb +168 -0
  19. data/lib/rudy/aws/ec2/instance.rb +434 -0
  20. data/lib/rudy/aws/ec2/keypair.rb +104 -0
  21. data/lib/rudy/aws/ec2/snapshot.rb +98 -0
  22. data/lib/rudy/aws/ec2/volume.rb +230 -0
  23. data/lib/rudy/aws/ec2/zone.rb +77 -0
  24. data/lib/rudy/aws/s3.rb +54 -0
  25. data/lib/rudy/aws/sdb.rb +298 -0
  26. data/lib/rudy/aws/sdb/error.rb +46 -0
  27. data/lib/rudy/{metadata/backup.rb → backup.rb} +26 -51
  28. data/lib/rudy/cli.rb +157 -0
  29. data/lib/rudy/cli/aws/ec2/addresses.rb +105 -0
  30. data/lib/rudy/cli/aws/ec2/candy.rb +208 -0
  31. data/lib/rudy/cli/aws/ec2/groups.rb +121 -0
  32. data/lib/rudy/cli/aws/ec2/images.rb +196 -0
  33. data/lib/rudy/cli/aws/ec2/instances.rb +194 -0
  34. data/lib/rudy/cli/aws/ec2/keypairs.rb +53 -0
  35. data/lib/rudy/cli/aws/ec2/snapshots.rb +49 -0
  36. data/lib/rudy/cli/aws/ec2/volumes.rb +104 -0
  37. data/lib/rudy/cli/aws/ec2/zones.rb +22 -0
  38. data/lib/rudy/cli/aws/s3/buckets.rb +50 -0
  39. data/lib/rudy/cli/aws/s3/store.rb +22 -0
  40. data/lib/rudy/cli/aws/sdb/domains.rb +41 -0
  41. data/lib/rudy/cli/candy.rb +8 -0
  42. data/lib/rudy/{command → cli}/config.rb +34 -24
  43. data/lib/rudy/cli/disks.rb +35 -0
  44. data/lib/rudy/cli/machines.rb +94 -0
  45. data/lib/rudy/cli/routines.rb +57 -0
  46. data/lib/rudy/config.rb +77 -72
  47. data/lib/rudy/config/objects.rb +29 -0
  48. data/lib/rudy/disks.rb +248 -0
  49. data/lib/rudy/global.rb +121 -0
  50. data/lib/rudy/huxtable.rb +340 -0
  51. data/lib/rudy/machines.rb +245 -0
  52. data/lib/rudy/metadata.rb +123 -13
  53. data/lib/rudy/routines.rb +47 -0
  54. data/lib/rudy/routines/helpers/diskhelper.rb +101 -0
  55. data/lib/rudy/routines/helpers/scripthelper.rb +91 -0
  56. data/lib/rudy/routines/release.rb +34 -0
  57. data/lib/rudy/routines/shutdown.rb +57 -0
  58. data/lib/rudy/routines/startup.rb +58 -0
  59. data/lib/rudy/scm/svn.rb +1 -1
  60. data/lib/rudy/utils.rb +322 -4
  61. data/lib/storable.rb +26 -17
  62. data/lib/sysinfo.rb +274 -0
  63. data/lib/tryouts.rb +6 -13
  64. data/rudy.gemspec +128 -42
  65. data/support/randomize-root-password +45 -0
  66. data/support/rudy-ec2-startup +9 -9
  67. data/support/update-ec2-ami-tools +20 -0
  68. data/test/05_config/00_setup_test.rb +20 -0
  69. data/test/05_config/30_machines_test.rb +69 -0
  70. data/test/20_sdb/00_setup_test.rb +16 -0
  71. data/test/20_sdb/10_domains_test.rb +115 -0
  72. data/test/25_ec2/00_setup_test.rb +29 -0
  73. data/test/25_ec2/10_keypairs_test.rb +41 -0
  74. data/test/25_ec2/20_groups_test.rb +131 -0
  75. data/test/25_ec2/30_addresses_test.rb +38 -0
  76. data/test/25_ec2/40_volumes_test.rb +49 -0
  77. data/test/25_ec2/50_snapshots_test.rb +74 -0
  78. data/test/26_ec2_instances/00_setup_test.rb +28 -0
  79. data/test/26_ec2_instances/10_instances_test.rb +83 -0
  80. data/test/26_ec2_instances/50_images_test.rb +13 -0
  81. data/test/30_sdb_metadata/00_setup_test.rb +21 -0
  82. data/test/30_sdb_metadata/10_disks_test.rb +109 -0
  83. data/test/30_sdb_metadata/20_backups_test.rb +102 -0
  84. data/test/coverage.txt +51 -0
  85. data/test/helper.rb +36 -0
  86. data/vendor/highline-1.5.1/CHANGELOG +222 -0
  87. data/vendor/highline-1.5.1/INSTALL +35 -0
  88. data/vendor/highline-1.5.1/LICENSE +7 -0
  89. data/vendor/highline-1.5.1/README +63 -0
  90. data/vendor/highline-1.5.1/Rakefile +82 -0
  91. data/vendor/highline-1.5.1/TODO +6 -0
  92. data/vendor/highline-1.5.1/examples/ansi_colors.rb +38 -0
  93. data/vendor/highline-1.5.1/examples/asking_for_arrays.rb +18 -0
  94. data/vendor/highline-1.5.1/examples/basic_usage.rb +75 -0
  95. data/vendor/highline-1.5.1/examples/color_scheme.rb +32 -0
  96. data/vendor/highline-1.5.1/examples/limit.rb +12 -0
  97. data/vendor/highline-1.5.1/examples/menus.rb +65 -0
  98. data/vendor/highline-1.5.1/examples/overwrite.rb +19 -0
  99. data/vendor/highline-1.5.1/examples/page_and_wrap.rb +322 -0
  100. data/vendor/highline-1.5.1/examples/password.rb +7 -0
  101. data/vendor/highline-1.5.1/examples/trapping_eof.rb +22 -0
  102. data/vendor/highline-1.5.1/examples/using_readline.rb +17 -0
  103. data/vendor/highline-1.5.1/lib/highline.rb +758 -0
  104. data/vendor/highline-1.5.1/lib/highline/color_scheme.rb +120 -0
  105. data/vendor/highline-1.5.1/lib/highline/compatibility.rb +17 -0
  106. data/vendor/highline-1.5.1/lib/highline/import.rb +43 -0
  107. data/vendor/highline-1.5.1/lib/highline/menu.rb +395 -0
  108. data/vendor/highline-1.5.1/lib/highline/question.rb +463 -0
  109. data/vendor/highline-1.5.1/lib/highline/system_extensions.rb +193 -0
  110. data/vendor/highline-1.5.1/setup.rb +1360 -0
  111. data/vendor/highline-1.5.1/test/tc_color_scheme.rb +56 -0
  112. data/vendor/highline-1.5.1/test/tc_highline.rb +823 -0
  113. data/vendor/highline-1.5.1/test/tc_import.rb +54 -0
  114. data/vendor/highline-1.5.1/test/tc_menu.rb +429 -0
  115. data/vendor/highline-1.5.1/test/ts_all.rb +15 -0
  116. metadata +141 -38
  117. data/lib/aws_sdb.rb +0 -3
  118. data/lib/aws_sdb/error.rb +0 -42
  119. data/lib/aws_sdb/service.rb +0 -215
  120. data/lib/rudy/aws/simpledb.rb +0 -53
  121. data/lib/rudy/command/addresses.rb +0 -46
  122. data/lib/rudy/command/backups.rb +0 -175
  123. data/lib/rudy/command/base.rb +0 -841
  124. data/lib/rudy/command/deploy.rb +0 -12
  125. data/lib/rudy/command/disks.rb +0 -213
  126. data/lib/rudy/command/environment.rb +0 -73
  127. data/lib/rudy/command/groups.rb +0 -61
  128. data/lib/rudy/command/images.rb +0 -91
  129. data/lib/rudy/command/instances.rb +0 -85
  130. data/lib/rudy/command/machines.rb +0 -161
  131. data/lib/rudy/command/metadata.rb +0 -41
  132. data/lib/rudy/command/release.rb +0 -174
  133. data/lib/rudy/command/volumes.rb +0 -66
  134. data/lib/rudy/metadata/disk.rb +0 -138
  135. data/tryouts/console_tryout.rb +0 -91
@@ -0,0 +1,35 @@
1
+
2
+
3
+ module Rudy
4
+ module CLI
5
+ class Disks < Rudy::CLI::CommandBase
6
+
7
+
8
+ def disks
9
+ rdisk = Rudy::Disks.new
10
+ rdisk.list do |d|
11
+ puts @@global.verbose > 0 ? d.inspect : d.dump(@@global.format)
12
+ end
13
+ end
14
+
15
+ def disks_wash
16
+ rdisk = Rudy::Disks.new
17
+ dirt = (rdisk.list || [])#.select { |d| d.available? }
18
+ if dirt.empty?
19
+ puts "Nothing to wash in #{rdisk.current_machine_group}"
20
+ return
21
+ end
22
+
23
+ puts "The following disk metadata will be deleted:"
24
+ puts dirt.collect {|d| d.name }
25
+ execute_check(:medium)
26
+
27
+ dirt.each do |d|
28
+ d.destroy(:force)
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,94 @@
1
+
2
+
3
+ module Rudy
4
+ module CLI
5
+ class Machines < Rudy::CLI::CommandBase
6
+
7
+
8
+ def machines
9
+ rmach = Rudy::Machines.new
10
+ mlist = rmach.list || []
11
+ if mlist.empty?
12
+ puts "No machines running in #{current_machine_group}"
13
+ puts "Try: #{$0} startup"
14
+ end
15
+ mlist.each do |m|
16
+ puts @@global.verbose > 0 ? m.inspect : m.dump(@@global.format)
17
+ end
18
+ end
19
+
20
+ def machines_wash
21
+ rmach = Rudy::Machines.new
22
+ dirt = (rmach.list || []).select { |m| !m.running? }
23
+ if dirt.empty?
24
+ puts "Nothing to wash in #{rmach.current_machine_group}"
25
+ return
26
+ end
27
+
28
+ puts "The following machine metadata will be deleted:"
29
+ puts dirt.collect {|m| m.name }
30
+ execute_check(:medium)
31
+
32
+ dirt.each do |m|
33
+ m.destroy
34
+ end
35
+
36
+ end
37
+
38
+
39
+ def ssh
40
+ # TODO: Give this methos a good look over
41
+ pkey = user_keypairpath(@@global.user)
42
+ unless pkey
43
+ puts "No private key configured for #{@@global.user} in #{current_machine_group}"
44
+ end
45
+
46
+ # Options to be sent to Net::SSH
47
+ ssh_opts = { :user => @@global.user || Rudy.sysinfo.user, :debug => nil }
48
+ if pkey
49
+ raise "Cannot find file #{pkey}" unless File.exists?(pkey)
50
+ raise InsecureKeyPermissions, @pkey unless File.stat(pkey).mode == 33152
51
+ ssh_opts[:keys] = pkey
52
+ end
53
+
54
+
55
+ # The user specified a command to run. We won't create an interactive
56
+ # session so we need to prepare the command and its arguments
57
+ if @argv.first
58
+ command, command_args = @argv.shift, @argv || []
59
+ puts "#{command} #{command_args.join(' ')}" if @@global.verbose > 1
60
+
61
+ # otherwise, we'll open an ssh session or print command
62
+ else
63
+ command, command_args = :interactive_ssh, @option.print.nil?
64
+ end
65
+
66
+
67
+ checked = false
68
+ rudy = Rudy::Machines.new
69
+ lt = rudy.list do |machine|
70
+ # Print header
71
+ if @@global.quiet
72
+ print "You are #{ssh_opts[:user].to_s.bright}. " if !checked # only the 1st
73
+ else
74
+ print "Connecting #{ssh_opts[:user].to_s.bright}@#{machine.dns_public} "
75
+ puts "#{machine.name} (#{machine.awsid})"
76
+ end
77
+
78
+ # Make sure we want to run this command on all instances
79
+ if !checked && command != :interactive_ssh
80
+ execute_check(:medium) if ssh_opts[:user] == "root"
81
+ checked = true
82
+ end
83
+
84
+ # Open the connection and run the command
85
+ rbox = Rye::Box.new(machine.dns_public, ssh_opts)
86
+ ret = rbox.send(command, command_args)
87
+ puts ret unless command == :interactive_ssh
88
+ end
89
+ end
90
+
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,57 @@
1
+
2
+
3
+ module Rudy; module CLI;
4
+ class Routines < Rudy::CLI::CommandBase
5
+
6
+ def startup
7
+ rr = Rudy::Routines::Startup.new
8
+ rr.execute
9
+
10
+ puts $/, "The following machines are now available:"
11
+ rmach = Rudy::Machines.new
12
+ rmach.list do |machine|
13
+ puts machine.to_s
14
+ end
15
+
16
+ if @@global.environment == @@config.default.environment &&
17
+ @@global.role == @@config.default.role
18
+ puts
19
+ puts "Try: #{$0} -u root ssh"
20
+ end
21
+
22
+ end
23
+
24
+ def release
25
+ rr = Rudy::Routines::Release.new
26
+ rmach = Rudy::Machines.new
27
+ startup unless rmach.running?
28
+ rr.execute
29
+ end
30
+
31
+ def shutdown
32
+ rr = Rudy::Routines::Shutdown.new
33
+ routine = fetch_routine_config(:shutdown)
34
+
35
+ puts "All machines in #{current_machine_group} will be shutdown and"
36
+ if routine && routine.disks
37
+ if routine.disks.destroy
38
+ puts "the following filesystems will be destroyed:".color(:red)
39
+ puts routine.disks.destroy.keys.join($/).bright
40
+ end
41
+ end
42
+
43
+ execute_check :medium
44
+
45
+ rr.execute
46
+
47
+ rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
48
+ lt = rinst.list_group(current_machine_group, :any) do |inst|
49
+ puts @@global.verbose > 0 ? inst.inspect : inst.dump(@@global.format)
50
+ end
51
+ puts "No instances running" if !lt || lt.empty?
52
+ end
53
+
54
+
55
+ end
56
+ end; end
57
+
@@ -1,92 +1,97 @@
1
1
 
2
-
3
2
  module Rudy
4
3
  require 'caesars'
5
-
6
- class AWSInfo < Caesars
7
- def valid?
8
- (!account.nil? && !accesskey.nil? && !secretkey.nil?) &&
9
- (!account.empty? && !accesskey.empty? && !secretkey.empty?)
10
- end
11
- end
12
-
13
- class Defaults < Caesars
14
- end
15
4
 
16
-
17
- class Routines < Caesars
5
+ class Config < Caesars::Config
6
+ require 'rudy/config/objects'
18
7
 
19
- def create(*args, &b)
20
- hash_handler(:create, *args, &b)
21
- end
22
- def destroy(*args, &b)
23
- hash_handler(:destroy, *args, &b)
24
- end
25
- def restore(*args, &b)
26
- hash_handler(:restore, *args, &b)
27
- end
28
- def mount(*args, &b)
29
- hash_handler(:mount, *args, &b)
30
- end
8
+ dsl Rudy::Config::Accounts::DSL
9
+ dsl Rudy::Config::Defaults::DSL
10
+ dsl Rudy::Config::Routines::DSL
11
+ dsl Rudy::Config::Machines::DSL
12
+ dsl Rudy::Config::Networks::DSL
31
13
 
32
- #
33
- # Force the specified keyword to always be treated as a hash.
34
- # Example:
35
- #
36
- # startup do
37
- # disks do
38
- # create "/path/2" # Available as hash: [action][disks][create][/path/2] == {}
39
- # create "/path/4" do # Available as hash: [action][disks][create][/path/4] == {size => 14}
40
- # size 14
41
- # end
42
- # end
43
- # end
44
- #
45
- def hash_handler(caesars_meth, *args, &b)
46
- # TODO: Move to caesars
47
- return @caesars_properties[caesars_meth] if @caesars_properties.has_key?(caesars_meth) && args.empty? && b.nil?
48
- return nil if args.empty? && b.nil?
49
- return method_missing(caesars_meth, *args, &b) if args.empty?
50
-
51
- caesars_name = args.shift
52
-
53
- prev = @caesars_pointer
54
- @caesars_pointer[caesars_meth] ||= Caesars::Hash.new
55
- hash = Caesars::Hash.new
56
- @caesars_pointer = hash
57
- b.call if b
58
- @caesars_pointer = prev
59
- @caesars_pointer[caesars_meth][caesars_name] = hash
60
- @caesars_pointer = prev
61
- end
62
- end
63
-
64
- class Machines < Caesars
65
- end
66
-
67
- class Config < Caesars::Config
68
- dsl Rudy::AWSInfo::DSL
69
- dsl Rudy::Defaults::DSL
70
- dsl Rudy::Routines::DSL
71
- dsl Rudy::Machines::DSL
14
+ # TODO: auto-generate in caesars
15
+ def accounts?; self.respond_to?(:accounts) && !self[:accounts].nil?; end
16
+ def defaults?; self.respond_to?(:defaults) && !self[:defaults].nil?; end
17
+ def machines?; self.respond_to?(:machines) && !self[:machines].nil?; end
18
+ def routines?; self.respond_to?(:routines) && !self[:routines].nil?; end
19
+ def networks?; self.respond_to?(:networks) && !self[:networks].nil?; end
72
20
 
73
21
  def postprocess
74
- # TODO: give caesar attributes setter methods
75
- self.awsinfo.cert &&= File.expand_path(self.awsinfo.cert)
76
- self.awsinfo.privatekey &&= File.expand_path(self.awsinfo.privatekey)
22
+ #raise "There is no AWS info configured" if self.accounts.nil?
77
23
 
24
+ # These don't work anymore. Caesars bug?
25
+ #if accounts? && !self.accounts.aws.nil?
26
+ # self.accounts.aws.cert &&= File.expand_path(self.accounts.aws.cert)
27
+ # self.accounts.aws.privatekey &&= File.expand_path(self.accounts.aws.privatekey)
28
+ #end
78
29
  end
79
30
 
80
- def look_and_load
31
+ def look_and_load(adhoc_path=nil)
81
32
  cwd = Dir.pwd
82
- # Rudy looks for configs in all these locations
83
- @paths += Dir.glob(File.join('/etc', 'rudy', '*.rb')) || []
33
+ cwd_path = File.join(cwd, '.rudy', 'config')
34
+
35
+ # Attempt to load the core configuration file first.
36
+ # The "core" config file can have any or all configuration
37
+ # but it should generally only contain the access identifiers
38
+ # and defaults. That's why we only load one of them.
39
+ core_config_paths = [adhoc_path, cwd_path, Rudy::CONFIG_FILE]
40
+ core_config_paths.each do |path|
41
+ next unless path && File.exists?(path)
42
+ @paths << path
43
+ break
44
+ end
45
+
46
+ # Rudy then looks for the rest of the config in these locations
47
+ @paths += Dir.glob(File.join(cwd, 'Rudyfile')) || []
84
48
  @paths += Dir.glob(File.join(cwd, 'config', 'rudy', '*.rb')) || []
85
49
  @paths += Dir.glob(File.join(cwd, '.rudy', '*.rb')) || []
50
+ @paths += Dir.glob(File.join('/etc', 'rudy', '*.rb')) || []
51
+ @paths &&= @paths.uniq
52
+
86
53
  refresh
87
54
  end
55
+
88
56
 
89
-
57
+ def self.init_config_dir
58
+
59
+ unless File.exists?(Rudy::CONFIG_DIR)
60
+ puts "Creating #{Rudy::CONFIG_DIR}"
61
+ Dir.mkdir(Rudy::CONFIG_DIR, 0700)
62
+ end
63
+
64
+ unless File.exists?(Rudy::CONFIG_FILE)
65
+ puts "Creating #{Rudy::CONFIG_FILE}"
66
+ rudy_config = Rudy::Utils.without_indent %Q{
67
+ # Amazon Web Services
68
+ # Account access indentifiers.
69
+ accounts do
70
+ aws do
71
+ name "Rudy Default"
72
+ accountnum ""
73
+ accesskey ""
74
+ secretkey ""
75
+ privatekey "~/path/2/pk-xxxx.pem"
76
+ cert "~/path/2/cert-xxxx.pem"
77
+ end
78
+ end
79
+
80
+ # Global Defaults
81
+ # Define the values to use unless otherwise specified on the command-line.
82
+ defaults do
83
+ region :"us-east-1"
84
+ zone :"us-east-1b"
85
+ environment :stage
86
+ role :app
87
+ position "01"
88
+ user ENV['USER'].to_sym
89
+ end
90
+ }
91
+ Rudy::Utils.write_to_file(Rudy::CONFIG_FILE, rudy_config, 'w', 0600)
92
+ end
93
+ end
94
+
90
95
  end
91
96
  end
92
97
 
@@ -0,0 +1,29 @@
1
+
2
+
3
+ class Rudy::Config
4
+ class Machines < Caesars
5
+ end
6
+
7
+
8
+ class Accounts < Caesars
9
+ def valid?
10
+ (!aws.nil? && !aws.accesskey.nil? && !aws.secretkey.nil?) &&
11
+ (!aws.account.empty? && !aws.accesskey.empty? && !aws.secretkey.empty?)
12
+ end
13
+ end
14
+
15
+ class Defaults < Caesars
16
+ end
17
+
18
+ class Networks < Caesars
19
+ end
20
+
21
+ class Routines < Caesars
22
+
23
+ forced_hash :create
24
+ forced_hash :destroy
25
+ forced_hash :restore
26
+ forced_hash :mount
27
+
28
+ end
29
+ end
@@ -0,0 +1,248 @@
1
+
2
+
3
+ module Rudy
4
+ class Disk < Storable
5
+ include Rudy::MetaData::ObjectBase
6
+
7
+ field :rtype
8
+ field :awsid
9
+ field :status
10
+ field :instid
11
+
12
+ field :region
13
+ field :zone
14
+ field :environment
15
+ field :role
16
+ field :position
17
+ field :path
18
+
19
+ field :device
20
+ field :size
21
+ #field :backups => Array
22
+
23
+ field :mounted
24
+
25
+ def init(path=nil, size=nil, device=nil, position=nil)
26
+ @path, @size, @device = path, size, device
27
+ @rtype = 'disk'
28
+ @region = @@global.region
29
+ @zone = @@global.zone
30
+ @environment = @@global.environment
31
+ @role = @@global.role
32
+ @position = position || @@global.position
33
+ @mounted = false
34
+ postprocess
35
+ end
36
+
37
+ def postprocess
38
+ @size &&= @size.to_i
39
+ @mounted = true if @mounted == "true"
40
+ end
41
+
42
+ def liner_note
43
+ info = @awsid && !@awsid.empty? ? @awsid : 'no volume'
44
+ "%s %s" % [self.name.bright, info]
45
+ end
46
+
47
+ def to_s(with_titles=true)
48
+ update
49
+ mtd = @mounted ? "mounted" : @status
50
+ "%s; %3sGB; %s; %s" % [liner_note, @size, @device, mtd]
51
+ end
52
+
53
+ def inspect
54
+ lines = []
55
+ lines << liner_note
56
+ field_names.each do |key|
57
+ next unless self.respond_to?(key)
58
+ val = self.send(key)
59
+ lines << sprintf(" %22s: %s", key, (val.is_a?(Array) ? val.join(', ') : val))
60
+ end
61
+ lines.join($/)
62
+ end
63
+
64
+ def name
65
+ sep=File::SEPARATOR
66
+ dirs = @path.split sep if @path && !@path.empty?
67
+ dirs.shift while dirs && (dirs[0].nil? || dirs[0].empty?)
68
+ super("disk", @zone, @environment, @role, @position, *dirs)
69
+ end
70
+
71
+
72
+
73
+ def create(snapshot=nil)
74
+ raise "#{name} is already running" if exists?
75
+ vol = @rvol.create(@size, @zone, snapshot)
76
+ @awsid = vol.awsid
77
+ self.save
78
+ self
79
+ end
80
+
81
+ def attach(instid)
82
+ raise "No volume id" unless exists?
83
+ vol = @rvol.attach(@awsid, instid, @device)
84
+ end
85
+
86
+ def detach
87
+ raise "No volume id" unless exists?
88
+ vol = @rvol.detach(@awsid)
89
+ end
90
+
91
+ def destroy(force=false)
92
+ if @awsid && !deleting?
93
+ if !force
94
+ raise Rudy::AWS::EC2::VolumeNotAvailable, @awsid if attached?
95
+ else
96
+ detach if exists? && attached?
97
+ sleep 0.1
98
+ end
99
+ raise Rudy::AWS::EC2::VolumeNotAvailable, @awsid if in_use?
100
+ @rvol.destroy(@awsid) if exists? && available?
101
+ end
102
+ super() # quotes, otherwise Ruby will send this method's args
103
+ end
104
+
105
+ def update
106
+ return false unless @awsid
107
+ @volume = @rvol.get(@awsid)
108
+ if @volume.is_a?(Rudy::AWS::EC2::Volume)
109
+ @status = @volume.status
110
+ @instid = @volume.instid
111
+ save
112
+ end
113
+ end
114
+
115
+ def to_query(more=[], less=[])
116
+ super([:path, *more], less) # Add path to the default fields
117
+ end
118
+
119
+ def to_select(more=[], less=[])
120
+ super([:path, *more], less)
121
+ end
122
+
123
+ # Does this disk have enough info to be saved or used?
124
+ # The test is based on the same criteria for building
125
+ # SimpleDB queries.
126
+ def valid?
127
+ criteria = build_criteria([:path]).flatten
128
+ criteria.size == criteria.compact.size
129
+ end
130
+
131
+ def mounted?
132
+ @mounted && @mounted == true
133
+ end
134
+
135
+
136
+ %w[exists? deleting? available? attached? in_use?].each do |state|
137
+ define_method(state) do
138
+ return false if @awsid.nil? || @awsid.empty?
139
+ @rvol.send(state, @awsid) rescue false # deleting?, available?, etc...
140
+ end
141
+ end
142
+ end
143
+
144
+ class Disks
145
+ include Rudy::MetaData
146
+
147
+
148
+ def create(&each_mach)
149
+
150
+ end
151
+
152
+
153
+ def destroy(&each_mach)
154
+ #raise MachineGroupNotRunning, current_machine_group unless running?
155
+ #raise MachineGroupNotDefined, current_machine_group unless known_machine_group?
156
+ list do |disk|
157
+ puts "Destroying #{disk.name}"
158
+ disk.destroy
159
+ end
160
+ end
161
+
162
+ def list(more=[], less=[], &each_disk)
163
+ disks = list_as_hash(&each_disk)
164
+ disks &&= disks.values
165
+ disks
166
+ end
167
+
168
+ def list_as_hash(more=[], less=[], &each_disk)
169
+ query = to_select([:rtype, 'disk'], less)
170
+ list = @sdb.select(query) || {}
171
+ disks = {}
172
+ list.each_pair do |n,d|
173
+ disks[n] = Rudy::Disk.from_hash(d)
174
+ end
175
+ disks.each_pair { |n,disk| each_disk.call(disk) } if each_disk
176
+ disks = nil if disks.empty?
177
+ disks
178
+ end
179
+
180
+ def get(rname=nil)
181
+ dhash = @sdb.get(Rudy::DOMAIN, rname)
182
+ return nil if dhash.nil? || dhash.empty?
183
+ d = Rudy::Disk.from_hash(dhash)
184
+ d.update if d
185
+ d
186
+ end
187
+
188
+
189
+ def running?
190
+ !list.nil?
191
+ # TODO: add logic that checks whether the instances are running.
192
+ end
193
+
194
+
195
+
196
+
197
+ end
198
+ end
199
+
200
+
201
+
202
+
203
+ __END__
204
+
205
+ def format(instance)
206
+ raise "No instance supplied" unless instance
207
+ raise "Disk not valid" unless self.valid?
208
+
209
+ begin
210
+ puts "Creating the filesystem (mkfs.ext3 -F #{disk.device})".bright
211
+ ssh_command instance.dns_public, current_user_keypairpath, @@global.user, "mkfs.ext3 -F #{disk.device}"
212
+ sleep 1
213
+ rescue => ex
214
+ @logger.puts ex.backtrace if debug?
215
+ raise "Error formatting #{disk.path}: #{ex.message}"
216
+ end
217
+ true
218
+ end
219
+ def mount(instance)
220
+ raise "No instance supplied" unless instance
221
+ disk = find_disk(opts[:disk] || opts[:path])
222
+ raise "Disk #{opts[:disk] || opts[:path]} cannot be found" unless disk
223
+ switch_user(:root)
224
+ begin
225
+ puts "Mounting #{disk.device} to #{disk.path}".bright
226
+ ssh_command instance.dns_public, current_user_keypairpath, @@global.user, "mkdir -p #{disk.path} && mount -t ext3 #{disk.device} #{disk.path}"
227
+ rescue => ex
228
+ @logger.puts ex.backtrace if debug?
229
+ raise "Error mounting #{disk.path}: #{ex.message}"
230
+ end
231
+ true
232
+ end
233
+
234
+ def unmount(instance)
235
+ raise "No instance supplied" unless instance
236
+ disk = find_disk(opts[:disk] || opts[:path])
237
+ raise "Disk #{opts[:disk] || opts[:path]} cannot be found" unless disk
238
+ switch_user(:root)
239
+ begin
240
+ puts "Unmounting #{disk.path}...".bright
241
+ ssh_command instance.dns_public, current_user_keypairpath, global.user, "umount #{disk.path}"
242
+ sleep 1
243
+ rescue => ex
244
+ @logger.puts ex.backtrace if debug?
245
+ raise "Error unmounting #{disk.path}: #{ex.message}"
246
+ end
247
+ true
248
+ end