solutious-rudy 0.9.1 → 0.9.2

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