rudy 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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