solutious-rudy 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/CHANGES.txt +40 -16
  2. data/README.rdoc +6 -6
  3. data/bin/rudy +66 -10
  4. data/bin/rudy-ec2 +3 -1
  5. data/examples/authorize.rb +15 -0
  6. data/examples/gem-test.rb +11 -5
  7. data/examples/solaris.rb +35 -0
  8. data/examples/windows.rb +101 -0
  9. data/lib/rudy.rb +7 -1
  10. data/lib/rudy/aws.rb +2 -2
  11. data/lib/rudy/aws/ec2.rb +29 -22
  12. data/lib/rudy/aws/ec2/group.rb +1 -1
  13. data/lib/rudy/aws/ec2/image.rb +1 -29
  14. data/lib/rudy/aws/ec2/instance.rb +4 -32
  15. data/lib/rudy/aws/ec2/keypair.rb +1 -6
  16. data/lib/rudy/aws/ec2/snapshot.rb +2 -20
  17. data/lib/rudy/aws/ec2/volume.rb +11 -19
  18. data/lib/rudy/aws/ec2/zone.rb +1 -6
  19. data/lib/rudy/aws/sdb.rb +1 -1
  20. data/lib/rudy/cli/aws/ec2/addresses.rb +4 -10
  21. data/lib/rudy/cli/aws/ec2/groups.rb +0 -1
  22. data/lib/rudy/cli/aws/ec2/images.rb +1 -4
  23. data/lib/rudy/cli/aws/ec2/info.rb +63 -0
  24. data/lib/rudy/cli/aws/ec2/instances.rb +3 -5
  25. data/lib/rudy/cli/aws/ec2/keypairs.rb +3 -5
  26. data/lib/rudy/cli/aws/ec2/snapshots.rb +2 -6
  27. data/lib/rudy/cli/aws/ec2/zones.rb +2 -4
  28. data/lib/rudy/cli/backups.rb +20 -9
  29. data/lib/rudy/cli/base.rb +60 -3
  30. data/lib/rudy/cli/candy.rb +1 -1
  31. data/lib/rudy/cli/disks.rb +65 -7
  32. data/lib/rudy/cli/execbase.rb +0 -2
  33. data/lib/rudy/cli/images.rb +97 -0
  34. data/lib/rudy/cli/info.rb +48 -0
  35. data/lib/rudy/cli/keypairs.rb +43 -0
  36. data/lib/rudy/cli/machines.rb +48 -38
  37. data/lib/rudy/cli/networks.rb +68 -0
  38. data/lib/rudy/cli/routines.rb +3 -10
  39. data/lib/rudy/config/objects.rb +0 -1
  40. data/lib/rudy/disks.rb +4 -0
  41. data/lib/rudy/global.rb +1 -1
  42. data/lib/rudy/huxtable.rb +9 -3
  43. data/lib/rudy/machines.rb +1 -1
  44. data/lib/rudy/metadata.rb +4 -1
  45. data/lib/rudy/metadata/backup.rb +2 -2
  46. data/lib/rudy/metadata/disk.rb +7 -4
  47. data/lib/rudy/metadata/machine.rb +66 -2
  48. data/lib/rudy/routines.rb +2 -1
  49. data/lib/rudy/routines/base.rb +4 -157
  50. data/lib/rudy/routines/handlers/base.rb +6 -3
  51. data/lib/rudy/routines/handlers/disks.rb +127 -42
  52. data/lib/rudy/routines/handlers/group.rb +45 -10
  53. data/lib/rudy/routines/handlers/host.rb +16 -10
  54. data/lib/rudy/routines/handlers/keypair.rb +26 -10
  55. data/lib/rudy/routines/handlers/rye.rb +173 -0
  56. data/lib/rudy/routines/handlers/script.rb +2 -1
  57. data/lib/rudy/routines/passthrough.rb +2 -2
  58. data/lib/rudy/routines/reboot.rb +2 -2
  59. data/lib/rudy/routines/shutdown.rb +2 -2
  60. data/lib/rudy/routines/startup.rb +4 -2
  61. data/rudy.gemspec +15 -8
  62. data/tryouts/10_require_time/10_rudy_tryouts.rb +1 -1
  63. data/tryouts/12_config/20_defaults_tryouts.rb +1 -1
  64. data/tryouts/12_config/40_machines_tryouts.rb +1 -1
  65. data/tryouts/15_huxtable/20_user_tryouts.rb +1 -1
  66. data/tryouts/25_ec2/10_keypairs_tryouts.rb +1 -0
  67. data/tryouts/30_metadata/10_include_tryouts.rb +1 -1
  68. data/tryouts/30_metadata/13_object_tryouts.rb +4 -0
  69. data/tryouts/30_metadata/50_disk_tryouts.rb +4 -2
  70. data/tryouts/30_metadata/51_disk_digest_tryouts.rb +1 -1
  71. data/tryouts/30_metadata/53_disk_list_tryouts.rb +2 -1
  72. data/tryouts/30_metadata/56_disk_volume_tryouts.rb +1 -1
  73. data/tryouts/30_metadata/60_backup_tryouts.rb +4 -2
  74. data/tryouts/30_metadata/63_backup_list_tryouts.rb +1 -1
  75. data/tryouts/30_metadata/64_backup_disk_tryouts.rb +3 -1
  76. data/tryouts/30_metadata/66_backup_snapshot_tryouts.rb +1 -1
  77. data/tryouts/30_metadata/70_machine_tryouts.rb +5 -2
  78. data/tryouts/30_metadata/73_machine_list_tryouts.rb +1 -1
  79. data/tryouts/30_metadata/76_machine_instance_tryouts.rb +15 -3
  80. data/tryouts/30_metadata/77_machines_tryouts.rb +1 -1
  81. data/tryouts/40_routines/10_keypair_handler_tryouts.rb +6 -5
  82. data/tryouts/40_routines/11_group_handler_tryouts.rb +1 -1
  83. metadata +13 -6
  84. data/lib/rudy/cli/status.rb +0 -60
@@ -77,16 +77,55 @@ module Rudy
77
77
 
78
78
  def postprocess
79
79
  @position &&= @position.to_s.rjust(2, '0')
80
+ @os &&= @os.to_sym
80
81
  end
81
82
 
82
83
  def to_s(*args)
83
- self.name
84
+ [self.name.bright, self.instid, self.dns_public].join '; '
84
85
  end
85
86
 
87
+ def rbox
88
+ r = Rudy::Routines::Handlers::RyeTools.create_box self
89
+ end
90
+
91
+ def disks
92
+ Rudy::Disks.list
93
+ end
94
+
95
+
86
96
  def get_instance
87
97
  Rudy::AWS::EC2::Instances.get @instid
88
98
  end
89
99
 
100
+ def get_console
101
+ raise "Instance not running" unless instance_running?
102
+ raw = Rudy::AWS::EC2::Instances.console @instid
103
+ console = Base64.decode64(raw)
104
+ # The linux console can include ANSI escape codes for color,
105
+ # clear screen etc... We strip them out to get rid of the
106
+ # clear specifically. Otherwise the display is messed!
107
+ console &&= console.noansi if console.respond_to? :noansi
108
+ console
109
+ end
110
+
111
+ def get_password
112
+ unless windows?
113
+ raise "Password support is Windows only (this is #{@os})"
114
+ end
115
+ console = get_console
116
+
117
+ raise "Console output not yet available. Please wait." if console.nil?
118
+
119
+ unless console.match(/<Password>(.+)<\/Password>/m)
120
+ # /m, match multiple lines
121
+ raise "Password not yet available. Is this a custom AMI?"
122
+ end
123
+
124
+ encrtypted_text = ($1 || '').strip
125
+ k = Rye::Key.from_file root_keypairpath
126
+ k.decrypt encrtypted_text
127
+ end
128
+
90
129
  def create
91
130
  raise "#{name} is already running" if instance_running?
92
131
 
@@ -103,6 +142,10 @@ module Rudy
103
142
 
104
143
  Rudy::Huxtable.ld "OPTS: #{opts.inspect}"
105
144
 
145
+ #@dns_public = @dns_private = nil
146
+ #inst = Rudy::AWS::EC2::Instances.list(:running).first
147
+ #@instid = inst.awsid
148
+
106
149
  Rudy::AWS::EC2::Instances.create(opts) do |inst|
107
150
  @instid = inst.awsid
108
151
  @created = @started = Time.now
@@ -125,6 +168,7 @@ module Rudy
125
168
  STDERR.puts ex.backtrace if Rudy.debug?
126
169
  end
127
170
  end
171
+
128
172
  self.save
129
173
  self
130
174
  end
@@ -138,9 +182,15 @@ module Rudy
138
182
  Rudy::AWS::EC2::Instances.restart(@instid) if instance_running?
139
183
  end
140
184
 
185
+ def attached_volumes
186
+ volumes = []
187
+ return volumes if @instid.nil?
188
+ Rudy::AWS::EC2::Volumes.list_by_instance( @instid) || []
189
+ end
190
+
141
191
  def refresh!(metadata=true)
142
192
  ## Updating the metadata isn't necessary
143
- ##super if metadata # update metadata
193
+ super() if metadata # update metadata
144
194
  @instance = get_instance
145
195
  if @instance.is_a?(Rudy::AWS::EC2::Instance)
146
196
  @dns_public, @dns_private = @instance.dns_public, @instance.dns_private
@@ -161,6 +211,20 @@ module Rudy
161
211
  d
162
212
  end
163
213
 
214
+ def default_fstype
215
+ windows? ? Rudy::DEFAULT_WINDOWS_FS : Rudy::DEFAULT_LINUX_FS
216
+ end
217
+
218
+ def default_device
219
+ windows? ? Rudy::DEFAULT_WINDOWS_DEVICE : Rudy::DEFAULT_LINUX_DEVICE
220
+ end
221
+
222
+
223
+ def os?(v); @os.to_s == v.to_s; end
224
+ def windows?; os? 'windows'; end
225
+ def linux?; os? 'linux'; end
226
+ def solaris?; os? 'solaris'; end
227
+
164
228
  def dns_public?; !@dns_public.nil? && !@dns_public.empty?; end
165
229
  def dns_private?; !@dns_private.nil? && !@dns_private.empty?; end
166
230
 
data/lib/rudy/routines.rb CHANGED
@@ -95,9 +95,10 @@ module Rudy
95
95
  end
96
96
 
97
97
  def self.rescue(ret=nil, &bloc_party)
98
+
98
99
  begin
99
100
  ret = bloc_party.call
100
- rescue NameError, ArgumentError, RuntimeError => ex
101
+ rescue NameError, ArgumentError, RuntimeError, Errno::ECONNREFUSED => ex
101
102
  STDERR.puts " #{ex.class}: #{ex.message}".color(:red)
102
103
  STDERR.puts ex.backtrace if Rudy.debug?
103
104
  unless Rudy::Huxtable.global.parallel
@@ -49,7 +49,10 @@ module Rudy; module Routines;
49
49
  end
50
50
 
51
51
  # Share one Rye::Box instance for localhost across all routines
52
- @@lbox = create_rye_box @@global.localhost unless defined?(@@lbox)
52
+ unless defined?(@@lbox)
53
+ host, opts = @@global.localhost, { :user => Rudy.sysinfo.user }
54
+ @@lbox = Rudy::Routines::Handlers::RyeTools.create_box host, opts
55
+ end
53
56
 
54
57
  disable_run if @@global.testrun
55
58
 
@@ -68,162 +71,6 @@ module Rudy; module Routines;
68
71
  def raise_early_exceptions; raise "Please override"; end
69
72
  def execute; raise "Please override"; end
70
73
 
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
74
  end
228
75
 
229
76
  end; end;
@@ -12,11 +12,14 @@ module Rudy; module Routines; module Handlers;
12
12
  print_response(ret)
13
13
  rescue IOError => ex
14
14
  STDERR.puts " Connection Error (#{ex.message})".color(:red)
15
- choice = Annoy.get_user_input('(S)kip (A)bort: ', nil, 3600) || ''
15
+ choice = Annoy.get_user_input('(S)kip (R)etry (F)orce (A)bort: ', nil, 3600) || ''
16
16
  if choice.match(/\AS/i)
17
17
  return
18
- #elsif choice.match(/\AR/i)
19
- # retry
18
+ elsif choice.match(/\AR/i)
19
+ retry
20
+ elsif choice.match(/\AF/i)
21
+ @@global.force = true
22
+ retry
20
23
  else
21
24
  exit 12
22
25
  end
@@ -5,10 +5,16 @@ module Rudy::Routines::Handlers;
5
5
  extend self
6
6
 
7
7
  ACTIONS = [:create, :destroy, :archive, :mount, :restore,
8
- :attach, :detach, :mount, :umount].freeze
8
+ :attach, :detach, :mount, :umount, :fstype].freeze
9
9
 
10
10
  Rudy::Routines.add_handler :disks, self
11
11
 
12
+ Rye::Cmd.add_command(:rudy_rm, 'rm')
13
+ Rye::Cmd.add_command(:rudy_mkfs, 'mkfs')
14
+ Rye::Cmd.add_command(:rudy_blkid, 'blkid')
15
+ Rye::Cmd.add_command(:rudy_format, 'C:/windows/system32/format.com')
16
+ Rye::Cmd.add_command(:rudy_diskpart, 'diskpart')
17
+
12
18
  def raise_early_exceptions(type, batch, rset, lbox, argv=nil)
13
19
 
14
20
  end
@@ -34,43 +40,54 @@ module Rudy::Routines::Handlers;
34
40
 
35
41
  def execute(type, routine, rset, lbox, argv=nil)
36
42
  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
+ rset.add_key user_keypairpath(current_machine_user)
44
+ rset.switch_user current_machine_user
43
45
 
44
46
  routine.each_pair do |action, disks|
45
47
  unless respond_to?(action.to_sym)
46
- Rudy::Huxtable.le %Q(DiskHelper: unknown action "#{action}")
48
+ Rudy::Huxtable.le %Q(DiskHandler: unknown action "#{action}")
47
49
  next
48
50
  end
49
51
  # A quick hack to take advantage of the threading in Rye::Set.
50
52
  # The action method does not run in the context of a Rye::Box
51
53
  # object so we need to send rset as an argument.
52
54
  rset.batch do
55
+ # Windows EC2 instances have 2 disks by default (C: and D:)
56
+ volumes = self.stash.attached_volumes
53
57
  disks.each_pair do |path, props|
54
58
  # self contains the current instance of Rye::Box.
55
59
  disk = Rudy::Disk.new(self.stash.position, path, props)
56
- Rudy::Routines::Handlers::Disks.send(action, self, disk)
60
+ disk.refresh! if disk.exists? # We need the volume ID if available
61
+ # don't include the current disk in the count.
62
+ volumes.reject! { |v| v.awsid == disk.volid } if disk.volid && disk.volume_attached?
63
+ disk_index = volumes.size + 2
64
+ Rudy::Routines::Handlers::Disks.send(action, self, disk, disk_index)
57
65
  end
58
66
  end
59
67
 
60
68
  end
61
69
 
62
- Rye::Cmd.remove_command(:rudy_mkfs)
63
-
64
70
  rset.switch_user original_user
65
71
  end
66
72
 
73
+ def fstype(rbox, disk, index)
74
+
75
+ raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
76
+ disk.refresh!
77
+
78
+ #p rbox.rudy_blkid :s, 'TYPE', :o, 'value', disk.device
79
+
80
+ end
81
+
67
82
 
68
- def create(rbox, disk)
83
+ def create(rbox, disk, index)
69
84
  if disk.exists?
70
85
  puts "Disk found: #{disk.name}"
71
86
  disk.refresh!
72
87
  end
73
88
 
89
+ disk.index = index # Needed for windows
90
+
74
91
  unless @@global.force
75
92
  raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
76
93
  end
@@ -83,25 +100,27 @@ module Rudy::Routines::Handlers;
83
100
  }
84
101
  end
85
102
 
86
- attach rbox, disk unless disk.volume_attached?
87
- format rbox, disk if disk.raw?
88
- mount rbox, disk unless disk.mounted?
103
+ attach rbox, disk, index unless disk.volume_attached?
104
+ format rbox, disk, index if disk.raw?
105
+ mount rbox, disk, index unless disk.mounted?
89
106
 
90
107
  disk.save :replace
91
108
  end
92
109
 
93
110
 
94
111
 
95
- def detach(rbox, disk)
112
+ def detach(rbox, disk, index)
96
113
 
97
114
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
98
115
  disk.refresh!
99
116
 
100
- raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
117
+ unless @@global.force
118
+ raise Rudy::Disks::NotAttached, disk.name unless disk.volume_attached?
119
+ end
101
120
 
102
- umount rbox, disk if disk.mounted?
121
+ umount rbox, disk, index if disk.mounted?
103
122
  raise Rudy::Disks::InUse, disk.name if disk.mounted?
104
-
123
+
105
124
  msg = "Detaching #{disk.volid}..."
106
125
  disk.volume_detach
107
126
  Rudy::Utils.waiter(2, 60, STDOUT, msg) {
@@ -110,25 +129,48 @@ module Rudy::Routines::Handlers;
110
129
 
111
130
  end
112
131
 
113
- def attach(rbox, disk)
132
+ def attach(rbox, disk, index)
133
+
134
+ unless disk.volume_exists?
135
+ msg = "Creating volume... "
136
+ disk.create
137
+ Rudy::Utils.waiter(2, 60, STDOUT, msg) {
138
+ disk.volume_available?
139
+ }
140
+ end
114
141
 
115
142
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
116
143
  disk.refresh!
117
144
 
118
- raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
145
+ unless @@global.force
146
+ raise Rudy::Disks::AlreadyAttached, disk.name if disk.volume_attached?
147
+ end
148
+
149
+ devices = rbox.stash.attached_volumes.collect { |v| v.device }
150
+ if devices.member? disk.device
151
+ li "Device ID #{disk.device} is taken. Using #{devices.sort.last.succ}"
152
+ disk.device = devices.sort.last.succ
153
+ disk.save :replace
154
+ end
119
155
 
120
156
  msg = "Attaching #{disk.volid} to #{rbox.stash.instid}... "
121
157
  disk.volume_attach(rbox.stash.instid)
122
- Rudy::Utils.waiter(2, 10, STDOUT, msg) {
158
+ Rudy::Utils.waiter(3, 30, STDOUT, msg) {
123
159
  disk.volume_attached?
124
160
  }
125
161
 
126
162
  end
127
163
 
128
- def mount(rbox, disk)
164
+ def mount(rbox, disk, index)
129
165
 
130
166
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
131
167
  disk.refresh!
168
+
169
+ if rbox.stash.windows?
170
+ Rudy::Huxtable.li "Skipping for Windows"
171
+ return
172
+ end
173
+
132
174
  attach rbox, disk unless disk.volume_attached?
133
175
 
134
176
  unless @@global.force
@@ -137,35 +179,42 @@ module Rudy::Routines::Handlers;
137
179
  raise Rudy::Disks::AlreadyMounted, disk.name if disk.mounted?
138
180
  end
139
181
 
140
- rbox.mkdir(:p, disk.path)
141
-
142
182
  puts "Mounting at #{disk.path}... "
143
-
183
+
184
+
185
+ rbox.mkdir(:p, disk.path)
144
186
  rbox.mount(:t, disk.fstype, disk.device, disk.path)
145
187
  disk.mounted = true
146
188
  disk.save :replace
147
189
  sleep 1
190
+
148
191
  end
149
192
 
150
193
 
151
- def umount(rbox, disk)
194
+ def umount(rbox, disk, index)
195
+
152
196
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
153
197
  disk.refresh!
154
198
 
155
- raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
156
- if @@global.force
199
+ unless @@global.force
200
+ raise Rudy::Disks::NotAttached, disk.name if !disk.volume_attached?
157
201
  raise Rudy::Disks::NotMounted, disk.name if !disk.mounted?
158
202
  end
159
203
 
160
204
  puts "Unmounting #{disk.path}... "
161
- rbox.umount(disk.path)
205
+
206
+ unless rbox.nil? || rbox.stash.windows?
207
+ rbox.umount(disk.path)
208
+ end
209
+
162
210
  disk.mounted = false
163
211
  disk.save :replace
164
212
  sleep 2
213
+
165
214
  end
166
215
  alias_method :unmount, :umount
167
216
 
168
- def format(rbox, disk)
217
+ def format(rbox, disk, index)
169
218
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
170
219
  disk.refresh!
171
220
 
@@ -177,20 +226,32 @@ module Rudy::Routines::Handlers;
177
226
  raise Rudy::Disks::AlreadyFormatted, disk.name if !disk.raw?
178
227
  end
179
228
 
180
- disk.fstype = 'ext3' if disk.fstype.nil? || disk.fstype.empty?
229
+ if disk.fstype.nil? || disk.fstype.empty?
230
+ disk.fstype = rbox.stash.default_fstype
231
+ end
232
+
233
+ print "Creating #{disk.fstype} filesystem for #{disk.path}... "
234
+ if rbox.stash.windows?
235
+ puts "(index: #{index})"
236
+ windows_diskpart_partition rbox, disk, index
237
+ disk.mounted = true
238
+ else
239
+ puts $/
240
+ rbox.rudy_mkfs(:t, disk.fstype, :F, disk.device)
241
+ end
181
242
 
182
- puts "Creating #{disk.fstype} filesystem for #{disk.device}... "
183
- rbox.rudy_mkfs(:t, disk.fstype, :F, disk.device)
184
243
  disk.raw = false
185
244
  disk.save :replace
245
+ sleep 1
246
+ disk
186
247
  end
187
248
 
188
- def destroy(rbox, disk)
249
+ def destroy(rbox, disk, index)
189
250
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
190
251
  disk.refresh!
191
252
 
192
- umount rbox, disk if disk.mounted?
193
- detach rbox, disk if disk.volume_attached?
253
+ umount rbox,disk,index if disk.mounted? && !rbox.nil? && !rbox.stash.windows?
254
+ detach rbox,disk,index if disk.volume_attached?
194
255
 
195
256
  unless @@global.force
196
257
  raise Rudy::Disks::InUse, disk.name if disk.volume_attached?
@@ -200,7 +261,7 @@ module Rudy::Routines::Handlers;
200
261
  disk.destroy
201
262
  end
202
263
 
203
- def archive(rbox, disk)
264
+ def archive(rbox, disk, index)
204
265
  raise Rudy::Metadata::UnknownObject, disk.name unless disk.exists?
205
266
  disk.refresh!
206
267
 
@@ -210,7 +271,7 @@ module Rudy::Routines::Handlers;
210
271
  puts "Created backup: #{back.name}"
211
272
  end
212
273
 
213
- def restore(rbox, disk)
274
+ def restore(rbox, disk, index)
214
275
 
215
276
  if disk.exists?
216
277
  puts "Disk found: #{disk.name}"
@@ -222,7 +283,11 @@ module Rudy::Routines::Handlers;
222
283
  end
223
284
 
224
285
  latest_backup = disk.backups.last
225
- latest_backup.fstype = 'ext3' if latest_backup.fstype.nil? || latest_backup.fstype.empty?
286
+
287
+ if latest_backup.fstype.nil? || latest_backup.fstype.empty?
288
+ latest_backup.fstype = rbox.stash.default_fstype
289
+ end
290
+
226
291
  disk.size, disk.fstype = latest_backup.size, latest_backup.fstype
227
292
 
228
293
  puts "Backup found: #{latest_backup.name}"
@@ -237,13 +302,33 @@ module Rudy::Routines::Handlers;
237
302
  disk.save :replace
238
303
  end
239
304
 
240
- attach rbox, disk unless disk.volume_attached?
241
- mount rbox, disk unless disk.mounted?
305
+ attach rbox, disk, index unless disk.volume_attached?
306
+ mount rbox, disk, index unless disk.mounted?
242
307
 
243
308
  disk.save :replace
244
309
 
245
310
  end
246
311
 
312
+ private
313
+
314
+ # See:
315
+ # * http://social.technet.microsoft.com/Forums/en-US/winserversetup/thread/2cfbaae1-6e33-4197-bb71-63434a34eb3c
316
+ # * http://technet.microsoft.com/en-us/library/cc766465(WS.10).aspx
317
+ def windows_diskpart_partition(rbox, disk, disk_num)
318
+ rbox.quietly { rudy_rm :f, 'diskpart-script' }
319
+ rbox.file_append 'diskpart-script', %Q{
320
+ select disk #{disk_num}
321
+ clean
322
+ create partition primary
323
+ select partition 1
324
+ active
325
+ assign letter=#{disk.path.tr(':/', '')}
326
+ exit}
327
+ rbox.rudy_diskpart '/s', 'diskpart-script'
328
+ rbox.quietly { rudy_rm :f, 'diskpart-script' }
329
+ rbox.rudy_format disk.path, '/V:RUDY', "/FS:#{disk.fstype}", '/Q', '/Y'
330
+ end
331
+
247
332
 
248
333
  end
249
334
  end