rudy 0.8.5 → 0.9.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 (132) hide show
  1. data/CHANGES.txt +110 -18
  2. data/README.rdoc +40 -44
  3. data/Rudyfile +35 -50
  4. data/bin/rudy +88 -57
  5. data/bin/rudy-ec2 +2 -16
  6. data/bin/rudy-s3 +0 -10
  7. data/bin/rudy-sdb +11 -12
  8. data/lib/rudy.rb +59 -91
  9. data/lib/rudy/aws.rb +4 -45
  10. data/lib/rudy/aws/ec2.rb +57 -20
  11. data/lib/rudy/aws/ec2/address.rb +10 -11
  12. data/lib/rudy/aws/ec2/group.rb +10 -9
  13. data/lib/rudy/aws/ec2/image.rb +8 -8
  14. data/lib/rudy/aws/ec2/instance.rb +18 -19
  15. data/lib/rudy/aws/ec2/keypair.rb +14 -19
  16. data/lib/rudy/aws/ec2/snapshot.rb +16 -9
  17. data/lib/rudy/aws/ec2/volume.rb +39 -26
  18. data/lib/rudy/aws/ec2/zone.rb +5 -4
  19. data/lib/rudy/aws/s3.rb +2 -1
  20. data/lib/rudy/aws/sdb.rb +35 -86
  21. data/lib/rudy/backups.rb +24 -0
  22. data/lib/rudy/cli.rb +5 -131
  23. data/lib/rudy/cli/aws/ec2/addresses.rb +19 -27
  24. data/lib/rudy/cli/aws/ec2/candy.rb +45 -20
  25. data/lib/rudy/cli/aws/ec2/groups.rb +9 -13
  26. data/lib/rudy/cli/aws/ec2/images.rb +5 -133
  27. data/lib/rudy/cli/aws/ec2/instances.rb +25 -25
  28. data/lib/rudy/cli/aws/ec2/keypairs.rb +7 -11
  29. data/lib/rudy/cli/aws/ec2/snapshots.rb +5 -9
  30. data/lib/rudy/cli/aws/ec2/volumes.rb +22 -23
  31. data/lib/rudy/cli/aws/ec2/zones.rb +2 -3
  32. data/lib/rudy/cli/aws/sdb/domains.rb +5 -6
  33. data/lib/rudy/cli/aws/sdb/objects.rb +33 -0
  34. data/lib/rudy/cli/aws/sdb/select.rb +23 -0
  35. data/lib/rudy/cli/backups.rb +38 -0
  36. data/lib/rudy/cli/base.rb +104 -0
  37. data/lib/rudy/cli/candy.rb +1 -2
  38. data/lib/rudy/cli/config.rb +20 -7
  39. data/lib/rudy/cli/disks.rb +7 -9
  40. data/lib/rudy/cli/execbase.rb +56 -0
  41. data/lib/rudy/cli/machines.rb +242 -45
  42. data/lib/rudy/cli/metadata.rb +24 -10
  43. data/lib/rudy/cli/networks.rb +34 -0
  44. data/lib/rudy/cli/routines.rb +32 -6
  45. data/lib/rudy/cli/status.rb +60 -0
  46. data/lib/rudy/config.rb +55 -32
  47. data/lib/rudy/config/objects.rb +44 -30
  48. data/lib/rudy/disks.rb +25 -0
  49. data/lib/rudy/exceptions.rb +99 -0
  50. data/lib/rudy/global.rb +67 -28
  51. data/lib/rudy/guidelines.rb +3 -2
  52. data/lib/rudy/huxtable.rb +67 -58
  53. data/lib/rudy/machines.rb +41 -263
  54. data/lib/rudy/metadata.rb +212 -38
  55. data/lib/rudy/metadata/backup.rb +123 -78
  56. data/lib/rudy/metadata/disk.rb +153 -170
  57. data/lib/rudy/metadata/machine.rb +179 -0
  58. data/lib/rudy/mixins.rb +2 -1
  59. data/lib/rudy/mixins/hash.rb +3 -1
  60. data/lib/rudy/mixins/symbol.rb +8 -0
  61. data/lib/rudy/routines.rb +127 -344
  62. data/lib/rudy/routines/base.rb +229 -0
  63. data/lib/rudy/routines/handlers/base.rb +48 -0
  64. data/lib/rudy/routines/handlers/depends.rb +49 -0
  65. data/lib/rudy/routines/handlers/disks.rb +249 -0
  66. data/lib/rudy/routines/handlers/group.rb +44 -0
  67. data/lib/rudy/routines/handlers/host.rb +70 -0
  68. data/lib/rudy/routines/handlers/keypair.rb +70 -0
  69. data/lib/rudy/routines/handlers/machines.rb +15 -0
  70. data/lib/rudy/routines/handlers/script.rb +85 -0
  71. data/lib/rudy/routines/handlers/user.rb +45 -0
  72. data/lib/rudy/routines/passthrough.rb +19 -23
  73. data/lib/rudy/routines/reboot.rb +98 -50
  74. data/lib/rudy/routines/shutdown.rb +65 -14
  75. data/lib/rudy/routines/startup.rb +112 -17
  76. data/lib/rudy/utils.rb +35 -68
  77. data/rudy.gemspec +82 -25
  78. data/tryouts/01_mixins/01_hash_tryouts.rb +20 -0
  79. data/tryouts/10_require_time/10_rudy_tryouts.rb +33 -0
  80. data/tryouts/10_require_time/15_global_tryouts.rb +58 -0
  81. data/tryouts/12_config/10_load_config_tryouts.rb +43 -0
  82. data/tryouts/12_config/20_defaults_tryouts.rb +16 -0
  83. data/tryouts/12_config/30_accounts_tryouts.rb +17 -0
  84. data/tryouts/12_config/40_machines_tryouts.rb +53 -0
  85. data/tryouts/12_config/50_commands_tryouts.rb +17 -0
  86. data/tryouts/12_config/60_routines_tryouts.rb +16 -0
  87. data/tryouts/15_huxtable/10_huxtable_tryouts.rb +47 -0
  88. data/tryouts/15_huxtable/20_user_tryouts.rb +47 -0
  89. data/tryouts/20_simpledb/10_domains_tryouts.rb +36 -0
  90. data/tryouts/20_simpledb/20_objects_tryouts.rb +56 -0
  91. data/tryouts/25_ec2/10_keypairs_tryouts.rb +54 -0
  92. data/tryouts/25_ec2/20_groups_tryouts.rb +56 -0
  93. data/tryouts/25_ec2/21_groups_authorize_address_tryouts.rb +53 -0
  94. data/tryouts/25_ec2/22_groups_authorize_account_tryouts.rb +54 -0
  95. data/tryouts/25_ec2/30_addresses_tryouts.rb +42 -0
  96. data/tryouts/25_ec2/40_volumes_tryouts.rb +53 -0
  97. data/tryouts/25_ec2/50_snapshots_tryouts.rb +75 -0
  98. data/tryouts/26_ec2_instances/10_instance_tryouts.rb +107 -0
  99. data/tryouts/26_ec2_instances/50_images_tryouts.rb +7 -0
  100. data/tryouts/30_metadata/10_include_tryouts.rb +45 -0
  101. data/tryouts/30_metadata/13_object_tryouts.rb +19 -0
  102. data/tryouts/30_metadata/50_disk_tryouts.rb +115 -0
  103. data/tryouts/30_metadata/51_disk_digest_tryouts.rb +24 -0
  104. data/tryouts/30_metadata/53_disk_list_tryouts.rb +35 -0
  105. data/tryouts/30_metadata/56_disk_volume_tryouts.rb +68 -0
  106. data/tryouts/30_metadata/60_backup_tryouts.rb +101 -0
  107. data/tryouts/30_metadata/63_backup_list_tryouts.rb +38 -0
  108. data/tryouts/30_metadata/64_backup_disk_tryouts.rb +65 -0
  109. data/tryouts/30_metadata/66_backup_snapshot_tryouts.rb +76 -0
  110. data/tryouts/30_metadata/70_machine_tryouts.rb +85 -0
  111. data/tryouts/30_metadata/73_machine_list_tryouts.rb +58 -0
  112. data/tryouts/30_metadata/76_machine_instance_tryouts.rb +64 -0
  113. data/tryouts/30_metadata/77_machines_tryouts.rb +45 -0
  114. data/tryouts/40_routines/10_keypair_handler_tryouts.rb +52 -0
  115. data/tryouts/40_routines/11_group_handler_tryouts.rb +36 -0
  116. data/tryouts/80_cli/10_rudyec2_tryouts.rb +8 -0
  117. data/tryouts/80_cli/60_rudy_tryouts.rb +41 -0
  118. data/tryouts/exploration/console.rb +91 -0
  119. data/tryouts/exploration/machine.rb +23 -0
  120. data/tryouts/failer +6 -0
  121. metadata +116 -32
  122. data/bin/ird +0 -153
  123. data/lib/rudy/metadata/backups.rb +0 -67
  124. data/lib/rudy/metadata/debug.rb +0 -38
  125. data/lib/rudy/metadata/disks.rb +0 -67
  126. data/lib/rudy/metadata/objectbase.rb +0 -108
  127. data/lib/rudy/routines/helper.rb +0 -76
  128. data/lib/rudy/routines/helpers/dependshelper.rb +0 -34
  129. data/lib/rudy/routines/helpers/diskhelper.rb +0 -403
  130. data/lib/rudy/routines/helpers/scripthelper.rb +0 -197
  131. data/lib/rudy/routines/helpers/userhelper.rb +0 -37
  132. data/support/rudy-ec2-startup +0 -200
@@ -0,0 +1,229 @@
1
+
2
+ module Rudy; module Routines;
3
+ class Base
4
+ include Rudy::Huxtable
5
+
6
+ @@run = true
7
+
8
+ def self.run?; @@run; end
9
+ def self.disable_run; @@run = false; end
10
+ def self.enable_run; @@run = true; end
11
+
12
+ def run?; @@run; end
13
+ def disable_run; @@run = false; end
14
+ def enable_run; @@run = true; end
15
+
16
+ # An Array Rudy::Machines objects that will be processed
17
+ attr_reader :machines
18
+
19
+ # * +name+ The name of the command specified on the command line
20
+ # * +option+ A Hash or OpenStruct of named command line options.
21
+ # If it's a Hash it will be converted to an OpenStruct.
22
+ # * +argv+ An Array of arguments
23
+ #
24
+ # +option+ and +argv+ are made available to the routine block.
25
+ #
26
+ # routines do
27
+ # magic do |options,argv|
28
+ # ...
29
+ # end
30
+ # end
31
+ #
32
+ def initialize(name=nil, option={}, argv=[], *args)
33
+ name ||= (self.class.to_s.split(/::/)).last.downcase
34
+ option = OpenStruct.new(option) if option.is_a? Hash
35
+ @name, @option, @argv = name.to_sym, option, argv
36
+ a, s, r = @@global.accesskey, @@global.secretkey, @@global.region
37
+ @@sdb ||= Rudy::AWS::SDB.new(a, s, r)
38
+
39
+ # Grab the routines configuration for this routine name
40
+ # e.g. startup, sysupdate, installdeps
41
+ @routine = fetch_routine_config @name rescue {}
42
+
43
+ ld "Routine: #{@routine.inspect}"
44
+
45
+ if @routine
46
+ # Removes the dependencies from the routines hash.
47
+ # We run these separately from the other actions.
48
+ @before, @after = @routine.delete(:before), @routine.delete(:after)
49
+ end
50
+
51
+ # Share one Rye::Box instance for localhost across all routines
52
+ @@lbox = create_rye_box @@global.localhost unless defined?(@@lbox)
53
+
54
+ disable_run if @@global.testrun
55
+
56
+ # We create these frozen globals for the benefit of
57
+ # the local and remote routine blocks.
58
+ $global = @@global.dup.freeze unless $global
59
+ $option = option.dup.freeze unless $option
60
+
61
+ ## TODO: get the machine config for just the current machine group. This
62
+ ## probably requires Caesars to be aware of which nodes are structural.
63
+ ##$config = fetch_machine_config unless $config
64
+
65
+ init(*args) if respond_to? :init
66
+ end
67
+
68
+ def raise_early_exceptions; raise "Please override"; end
69
+ def execute; raise "Please override"; end
70
+
71
+ # Create an instance of Rye::Box for +hostname+. +opts+ is
72
+ # an optional Hash of options. See Rye::Box.initialize
73
+ #
74
+ # This method should be used throughout the Rudy::Routines
75
+ # namespace rather than creating instances manually b/c it
76
+ # applies some fancy pants defaults like command hooks.
77
+ def create_rye_box(hostname, opts={})
78
+ ld [:hostname, hostname, opts, caller[0]]
79
+ opts = {
80
+ :info => (@@global.verbose >= 3), # rudy -vvv
81
+ :debug => false,
82
+ :user => Rudy.sysinfo.user
83
+ }.merge opts
84
+
85
+ box = Rye::Box.new hostname, opts
86
+
87
+
88
+ # We define hooks so we can still print each command and its output
89
+ # when running the command blocks. NOTE: We only print this in
90
+ # verbosity mode.
91
+ if @@global.verbose > 0 && !@@global.parallel
92
+ # This block gets called for every command method call.
93
+ box.pre_command_hook do |cmd, user, host, nickname|
94
+ print_command user, nickname, cmd
95
+ end
96
+ end
97
+
98
+ if @@global.verbose > 1
99
+ # And this one gets called after each command method call.
100
+ box.post_command_hook do |ret|
101
+ print_response ret
102
+ end
103
+ end
104
+
105
+ box.exception_hook(Rye::CommandError, &rbox_exception_handler)
106
+ box.exception_hook(Exception, &rbox_exception_handler)
107
+
108
+ ## It'd better for unknown commands to be handled elsewhere
109
+ ## because it doesn't make sense to retry a method that doesn't exist
110
+ ##box.exception_hook(Rye::CommandNotFound, &rbox_exception_handler)
111
+
112
+ box
113
+ end
114
+
115
+
116
+
117
+ # Create an instance of Rye::Set from a list of +hostnames+.
118
+ # +hostnames+ can contain hostnames or Rudy::Machine objects.
119
+ # +opts+ is an optional Hash of options. See Rye::Box.initialize
120
+ #
121
+ # NOTE: Windows machines are skipped and not added to the set.
122
+ def create_rye_set(hostnames, opts={})
123
+ hostnames ||= []
124
+
125
+ opts = {
126
+ :user => (current_machine_user).to_s,
127
+ :parallel => @@global.parallel
128
+ }.merge(opts)
129
+ set = Rye::Set.new current_machine_group, opts
130
+
131
+ opts.delete(:parallel) # Not used by Rye::Box.new
132
+
133
+ hostnames.each do |m|
134
+ # This is a short-circuit for Windows instances. We don't support
135
+ # disks for windows yet and there's no SSH so routines are out of
136
+ # the picture too.
137
+ next if (m.os || '').to_s == 'win32'
138
+
139
+ if m.is_a?(Rudy::Machine)
140
+ m.refresh! if m.dns_public.nil? || m.dns_public.empty?
141
+ if m.dns_public.nil? || m.dns_public.empty?
142
+ ld "Cannot find public DNS for #{m.name} (continuing...)"
143
+ ##next
144
+ end
145
+ ld [:dns_public, m.dns_public, m.instid]
146
+ rbox = create_rye_box(m.dns_public, opts)
147
+ rbox.stash = m # Store the machine instance in the stash
148
+ rbox.nickname = m.name
149
+ else
150
+ # Otherwise we assume it's a hostname
151
+ rbox = create_rye_box(m)
152
+ end
153
+ rbox.add_key user_keypairpath(opts[:user])
154
+ set.add_box rbox
155
+ end
156
+
157
+ ld "Machines Set: %s" % [set.empty? ? '[empty]' : set.inspect]
158
+
159
+ set
160
+ end
161
+
162
+
163
+
164
+
165
+ # Returns a formatted string for printing command info
166
+ def print_command(user, host, cmd)
167
+ #return if @@global.parallel
168
+ cmd ||= ""
169
+ cmd, user = cmd.to_s, user.to_s
170
+ prompt = user == "root" ? "#" : "$"
171
+ li ("%s@%s%s %s" % [user, host, prompt, cmd.bright])
172
+ end
173
+
174
+ def print_response(rap)
175
+ # Non zero exit codes raise exceptions so
176
+ # the erorrs have already been handled.
177
+ return if rap.exit_code != 0
178
+
179
+ if @@global.parallel
180
+ cmd, user = cmd.to_s, user.to_s
181
+ prompt = user == "root" ? "#" : "$"
182
+ li "%s@%s%s %s%s%s" % [rap.box.user, rap.box.nickname, prompt, rap.cmd.bright, $/, rap.stdout.inspect]
183
+ unless rap.stderr.empty?
184
+ le "#{rap.box.nickname}: " << rap.stderr.join("#{rap.box.nickname}: ")
185
+ end
186
+ else
187
+ li ' ' << rap.stdout.join("#{$/} ") if !rap.stdout.empty?
188
+ colour = rap.exit_code != 0 ? :red : :normal
189
+ unless rap.stderr.empty?
190
+ le (" STDERR " << '-'*38).color(colour).bright
191
+ le " " << rap.stderr.join("#{$/} ").color(colour)
192
+ end
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ def rbox_exception_handler
199
+ Proc.new do |ex, cmd, user, host, nickname|
200
+ print_exception(user, host, cmd, nickname, ex)
201
+ unless @@global.parallel
202
+ choice = Annoy.get_user_input('(S)kip (R)etry (F)orce (A)bort: ', nil, 3600) || ''
203
+ if choice.match(/\AS/i)
204
+ :skip
205
+ elsif choice.match(/\AR/i)
206
+ :retry # Tells Rye::Box#run_command to retry
207
+ elsif choice.match(/\AF/i)
208
+ @@global.force = true
209
+ :retry
210
+ else
211
+ exit 12
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ def print_exception(user, host, cmd, nickname, ex)
218
+ prefix = @@global.parallel ? "#{nickname}: #{cmd}: " : ""
219
+ if ex.is_a?(Rye::CommandError)
220
+ le prefix << ex.message.color(:red)
221
+ else
222
+ le prefix << "#{ex.class}: #{ex.message}".color(:red)
223
+ end
224
+ le *ex.backtrace if @@global.verbose > 2
225
+ end
226
+
227
+ end
228
+
229
+ end; end;
@@ -0,0 +1,48 @@
1
+
2
+
3
+ module Rudy; module Routines; module Handlers;
4
+ module Base
5
+ include Rudy::Huxtable
6
+
7
+ def trap_rbox_errors(ret=nil, &command)
8
+ begin
9
+ ret = command.call if command
10
+ return unless ret.is_a?(Rye::Rap)
11
+ puts ' ' << ret.stdout.join("#{$/} ") if !ret.stdout.empty?
12
+ print_response(ret)
13
+ rescue IOError => ex
14
+ STDERR.puts " Connection Error (#{ex.message})".color(:red)
15
+ choice = Annoy.get_user_input('(S)kip (A)bort: ', nil, 3600) || ''
16
+ if choice.match(/\AS/i)
17
+ return
18
+ #elsif choice.match(/\AR/i)
19
+ # retry
20
+ else
21
+ exit 12
22
+ end
23
+ end
24
+
25
+ ret
26
+ end
27
+
28
+ def keep_going?
29
+ Annoy.pose_question(" Keep going?\a ", /yes|y|ya|sure|you bet!/i, STDERR)
30
+ end
31
+
32
+
33
+ private
34
+ def print_response(rap)
35
+ colour = rap.exit_code != 0 ? :red : :normal
36
+ [:stderr].each do |sumpin|
37
+ next if rap.send(sumpin).empty?
38
+ STDERR.puts
39
+ STDERR.puts((" #{sumpin.to_s.upcase} " << '-'*38).color(colour).bright)
40
+ STDERR.puts " " << rap.send(sumpin).join("#{$/} ").color(colour)
41
+ end
42
+ STDERR.puts " Exit code: #{rap.exit_code}".color(colour) if rap.exit_code != 0
43
+ end
44
+
45
+ end
46
+
47
+ end; end; end
48
+
@@ -0,0 +1,49 @@
1
+
2
+ module Rudy; module Routines; module Handlers;
3
+ module Depends
4
+ include Rudy::Routines::Handlers::Base
5
+ extend self
6
+
7
+ ## NOTE: Dependencies don't use Rudy::Routines.add_handler but we
8
+ ## define them ehere anyway so raise_early_exceptions passes.
9
+ Rudy::Routines.add_handler :before, self
10
+ Rudy::Routines.add_handler :after, self
11
+
12
+ def raise_early_exceptions(type, depends, rset, lbox, argv=nil)
13
+ unless depends.kind_of? Array
14
+ raise Rudy::Error, "#{type} must be a kind of Array (#{depends.class})"
15
+ end
16
+ raise Rudy::Routines::EmptyDepends, type if depends.nil? || depends.empty?
17
+ depends.flatten.compact.each do |name|
18
+ raise Rudy::Routines::NoRoutine, name unless valid_routine?(name)
19
+ end
20
+ end
21
+
22
+ # A simple wrapper for executing a routine.
23
+ #
24
+ # * +routine_name+ should be a Symbol representing a routine
25
+ # available to the current machine group.
26
+ #
27
+ # This method finds the handler for the given routine,
28
+ # creates an instance, calls raise_early_exceptions,
29
+ # and finally executes the routine.
30
+ def execute(routine_name)
31
+ routine_obj = Rudy::Routines.get_routine routine_name
32
+ ld "Executing dependency: #{routine_name} (#{routine_obj})"
33
+ routine = routine_obj.new routine_name
34
+ routine.raise_early_exceptions
35
+ routine.execute
36
+ end
37
+
38
+ # Calls execute for each routine name in +depends+ (an Array).
39
+ # Does nothing if given an empty Array or nil.
40
+ def execute_all(depends)
41
+ return if depends.nil? || depends.empty?
42
+ depends = depends.flatten.compact
43
+ ld "Found depenencies: #{depends.join(', ')}"
44
+ depends.each { |routine| execute(routine) }
45
+ end
46
+
47
+ end
48
+
49
+ end; end; end
@@ -0,0 +1,249 @@
1
+
2
+ module Rudy::Routines::Handlers;
3
+ module Disks
4
+ include Rudy::Routines::Handlers::Base
5
+ extend self
6
+
7
+ ACTIONS = [:create, :destroy, :archive, :mount, :restore,
8
+ :attach, :detach, :mount, :umount].freeze
9
+
10
+ Rudy::Routines.add_handler :disks, self
11
+
12
+ def raise_early_exceptions(type, batch, rset, lbox, argv=nil)
13
+
14
+ end
15
+
16
+ def any?(routine)
17
+ (routine.kind_of?(Hash) && routine.disks &&
18
+ routine.disks.kind_of?(Hash) && !routine.disks.empty?) ? true : false
19
+ end
20
+
21
+ # Create mount?, create?, umount? etc... methods
22
+ ACTIONS.each do |action|
23
+ define_method "#{action}?" do |routine|
24
+ return false unless any? routine
25
+ routine.disks.member? action
26
+ end
27
+ end
28
+
29
+ def paths(routine)
30
+ return nil unless disks?(routine)
31
+ routine.disks.values.collect { |d| d.keys }.flatten
32
+ end
33
+
34
+
35
+ def execute(type, routine, rset, lbox, argv=nil)
36
+ original_user = rset.user
37
+ rset.add_key user_keypairpath('root')
38
+ rset.switch_user 'root'
39
+
40
+ # We need to add mkfs since it's not enabled by default.
41
+ # We prepend the command with rudy_ so we can delete it.
42
+ Rye::Cmd.add_command(:rudy_mkfs, 'mkfs')
43
+
44
+ routine.each_pair do |action, disks|
45
+ unless respond_to?(action.to_sym)
46
+ Rudy::Huxtable.le %Q(DiskHelper: unknown action "#{action}")
47
+ next
48
+ end
49
+ # A quick hack to take advantage of the threading in Rye::Set.
50
+ # The action method does not run in the context of a Rye::Box
51
+ # object so we need to send rset as an argument.
52
+ rset.batch do
53
+ disks.each_pair do |path, props|
54
+ # self contains the current instance of Rye::Box.
55
+ disk = Rudy::Disk.new(self.stash.position, path, props)
56
+ Rudy::Routines::Handlers::Disks.send(action, self, disk)
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ Rye::Cmd.remove_command(:rudy_mkfs)
63
+
64
+ rset.switch_user original_user
65
+ end
66
+
67
+
68
+ def create(rbox, disk)
69
+ if disk.exists?
70
+ puts "Disk found: #{disk.name}"
71
+ disk.refresh!
72
+ end
73
+
74
+ unless @@global.force
75
+ raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
76
+ end
77
+
78
+ unless disk.volume_exists?
79
+ msg = "Creating volume... "
80
+ disk.create
81
+ Rudy::Utils.waiter(2, 60, STDOUT, msg) {
82
+ disk.volume_available?
83
+ }
84
+ end
85
+
86
+ attach rbox, disk unless disk.volume_attached?
87
+ format rbox, disk if disk.raw?
88
+ mount rbox, disk unless disk.mounted?
89
+
90
+ disk.save :replace
91
+ end
92
+
93
+
94
+
95
+ def detach(rbox, disk)
96
+
97
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
98
+ disk.refresh!
99
+
100
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
101
+
102
+ umount rbox, disk if disk.mounted?
103
+ raise Rudy::Disks::InUse, disk.name if disk.mounted?
104
+
105
+ msg = "Detaching #{disk.volid}..."
106
+ disk.volume_detach
107
+ Rudy::Utils.waiter(2, 60, STDOUT, msg) {
108
+ disk.volume_available?
109
+ }
110
+
111
+ end
112
+
113
+ def attach(rbox, disk)
114
+
115
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
116
+ disk.refresh!
117
+
118
+ raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
119
+
120
+ msg = "Attaching #{disk.volid} to #{rbox.stash.instid}... "
121
+ disk.volume_attach(rbox.stash.instid)
122
+ Rudy::Utils.waiter(2, 10, STDOUT, msg) {
123
+ disk.volume_attached?
124
+ }
125
+
126
+ end
127
+
128
+ def mount(rbox, disk)
129
+
130
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
131
+ disk.refresh!
132
+ attach rbox, disk unless disk.volume_attached?
133
+
134
+ unless @@global.force
135
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
136
+ raise Rudy::Disks::NotFormatted, disk.name if disk.raw?
137
+ raise Rudy::Disks::AlreadyMounted, disk.name if disk.mounted?
138
+ end
139
+
140
+ rbox.mkdir(:p, disk.path)
141
+
142
+ puts "Mounting at #{disk.path}... "
143
+
144
+ rbox.mount(:t, disk.fstype, disk.device, disk.path)
145
+ disk.mounted = true
146
+ disk.save :replace
147
+ sleep 1
148
+ end
149
+
150
+
151
+ def umount(rbox, disk)
152
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
153
+ disk.refresh!
154
+
155
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
156
+ if @@global.force
157
+ raise Rudy::Disks::NotMounted, disk.name if !disk.mounted?
158
+ end
159
+
160
+ puts "Unmounting #{disk.path}... "
161
+ rbox.umount(disk.path)
162
+ disk.mounted = false
163
+ disk.save :replace
164
+ sleep 2
165
+ end
166
+ alias_method :unmount, :umount
167
+
168
+ def format(rbox, disk)
169
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
170
+ disk.refresh!
171
+
172
+ attach rbox, disk unless disk.volume_attached?
173
+
174
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
175
+
176
+ unless @@global.force
177
+ raise Rudy::Disks::AlreadyFormatted, disk.name if !disk.raw?
178
+ end
179
+
180
+ disk.fstype = 'ext3' if disk.fstype.nil? || disk.fstype.empty?
181
+
182
+ puts "Creating #{disk.fstype} filesystem for #{disk.device}... "
183
+ rbox.rudy_mkfs(:t, disk.fstype, :F, disk.device)
184
+ disk.raw = false
185
+ disk.save :replace
186
+ end
187
+
188
+ def destroy(rbox, disk)
189
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
190
+ disk.refresh!
191
+
192
+ umount rbox, disk if disk.mounted?
193
+ detach rbox, disk if disk.volume_attached?
194
+
195
+ unless @@global.force
196
+ raise Rudy::Disks::InUse, disk.name if disk.volume_attached?
197
+ end
198
+
199
+ puts "Destroying #{disk.name}"
200
+ disk.destroy
201
+ end
202
+
203
+ def archive(rbox, disk)
204
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
205
+ disk.refresh!
206
+
207
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
208
+
209
+ back = disk.archive
210
+ puts "Created backup: #{back.name}"
211
+ end
212
+
213
+ def restore(rbox, disk)
214
+
215
+ if disk.exists?
216
+ puts "Disk found: #{disk.name}"
217
+ disk.refresh!
218
+ end
219
+
220
+ unless @@global.force
221
+ raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
222
+ end
223
+
224
+ latest_backup = disk.backups.last
225
+ latest_backup.fstype = 'ext3' if latest_backup.fstype.nil? || latest_backup.fstype.empty?
226
+ disk.size, disk.fstype = latest_backup.size, latest_backup.fstype
227
+
228
+ puts "Backup found: #{latest_backup.name}"
229
+
230
+ unless disk.volume_exists?
231
+ msg = "Creating volume... "
232
+ disk.create latest_backup.size, latest_backup.zone, latest_backup.snapid
233
+ Rudy::Utils.waiter(2, 60, STDOUT, msg) {
234
+ disk.volume_available?
235
+ }
236
+ disk.raw = false
237
+ disk.save :replace
238
+ end
239
+
240
+ attach rbox, disk unless disk.volume_attached?
241
+ mount rbox, disk unless disk.mounted?
242
+
243
+ disk.save :replace
244
+
245
+ end
246
+
247
+
248
+ end
249
+ end