rudy 0.8.5 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +110 -18
- data/README.rdoc +40 -44
- data/Rudyfile +35 -50
- data/bin/rudy +88 -57
- data/bin/rudy-ec2 +2 -16
- data/bin/rudy-s3 +0 -10
- data/bin/rudy-sdb +11 -12
- data/lib/rudy.rb +59 -91
- data/lib/rudy/aws.rb +4 -45
- data/lib/rudy/aws/ec2.rb +57 -20
- data/lib/rudy/aws/ec2/address.rb +10 -11
- data/lib/rudy/aws/ec2/group.rb +10 -9
- data/lib/rudy/aws/ec2/image.rb +8 -8
- data/lib/rudy/aws/ec2/instance.rb +18 -19
- data/lib/rudy/aws/ec2/keypair.rb +14 -19
- data/lib/rudy/aws/ec2/snapshot.rb +16 -9
- data/lib/rudy/aws/ec2/volume.rb +39 -26
- data/lib/rudy/aws/ec2/zone.rb +5 -4
- data/lib/rudy/aws/s3.rb +2 -1
- data/lib/rudy/aws/sdb.rb +35 -86
- data/lib/rudy/backups.rb +24 -0
- data/lib/rudy/cli.rb +5 -131
- data/lib/rudy/cli/aws/ec2/addresses.rb +19 -27
- data/lib/rudy/cli/aws/ec2/candy.rb +45 -20
- data/lib/rudy/cli/aws/ec2/groups.rb +9 -13
- data/lib/rudy/cli/aws/ec2/images.rb +5 -133
- data/lib/rudy/cli/aws/ec2/instances.rb +25 -25
- data/lib/rudy/cli/aws/ec2/keypairs.rb +7 -11
- data/lib/rudy/cli/aws/ec2/snapshots.rb +5 -9
- data/lib/rudy/cli/aws/ec2/volumes.rb +22 -23
- data/lib/rudy/cli/aws/ec2/zones.rb +2 -3
- data/lib/rudy/cli/aws/sdb/domains.rb +5 -6
- data/lib/rudy/cli/aws/sdb/objects.rb +33 -0
- data/lib/rudy/cli/aws/sdb/select.rb +23 -0
- data/lib/rudy/cli/backups.rb +38 -0
- data/lib/rudy/cli/base.rb +104 -0
- data/lib/rudy/cli/candy.rb +1 -2
- data/lib/rudy/cli/config.rb +20 -7
- data/lib/rudy/cli/disks.rb +7 -9
- data/lib/rudy/cli/execbase.rb +56 -0
- data/lib/rudy/cli/machines.rb +242 -45
- data/lib/rudy/cli/metadata.rb +24 -10
- data/lib/rudy/cli/networks.rb +34 -0
- data/lib/rudy/cli/routines.rb +32 -6
- data/lib/rudy/cli/status.rb +60 -0
- data/lib/rudy/config.rb +55 -32
- data/lib/rudy/config/objects.rb +44 -30
- data/lib/rudy/disks.rb +25 -0
- data/lib/rudy/exceptions.rb +99 -0
- data/lib/rudy/global.rb +67 -28
- data/lib/rudy/guidelines.rb +3 -2
- data/lib/rudy/huxtable.rb +67 -58
- data/lib/rudy/machines.rb +41 -263
- data/lib/rudy/metadata.rb +212 -38
- data/lib/rudy/metadata/backup.rb +123 -78
- data/lib/rudy/metadata/disk.rb +153 -170
- data/lib/rudy/metadata/machine.rb +179 -0
- data/lib/rudy/mixins.rb +2 -1
- data/lib/rudy/mixins/hash.rb +3 -1
- data/lib/rudy/mixins/symbol.rb +8 -0
- data/lib/rudy/routines.rb +127 -344
- data/lib/rudy/routines/base.rb +229 -0
- data/lib/rudy/routines/handlers/base.rb +48 -0
- data/lib/rudy/routines/handlers/depends.rb +49 -0
- data/lib/rudy/routines/handlers/disks.rb +249 -0
- data/lib/rudy/routines/handlers/group.rb +44 -0
- data/lib/rudy/routines/handlers/host.rb +70 -0
- data/lib/rudy/routines/handlers/keypair.rb +70 -0
- data/lib/rudy/routines/handlers/machines.rb +15 -0
- data/lib/rudy/routines/handlers/script.rb +85 -0
- data/lib/rudy/routines/handlers/user.rb +45 -0
- data/lib/rudy/routines/passthrough.rb +19 -23
- data/lib/rudy/routines/reboot.rb +98 -50
- data/lib/rudy/routines/shutdown.rb +65 -14
- data/lib/rudy/routines/startup.rb +112 -17
- data/lib/rudy/utils.rb +35 -68
- data/rudy.gemspec +82 -25
- data/tryouts/01_mixins/01_hash_tryouts.rb +20 -0
- data/tryouts/10_require_time/10_rudy_tryouts.rb +33 -0
- data/tryouts/10_require_time/15_global_tryouts.rb +58 -0
- data/tryouts/12_config/10_load_config_tryouts.rb +43 -0
- data/tryouts/12_config/20_defaults_tryouts.rb +16 -0
- data/tryouts/12_config/30_accounts_tryouts.rb +17 -0
- data/tryouts/12_config/40_machines_tryouts.rb +53 -0
- data/tryouts/12_config/50_commands_tryouts.rb +17 -0
- data/tryouts/12_config/60_routines_tryouts.rb +16 -0
- data/tryouts/15_huxtable/10_huxtable_tryouts.rb +47 -0
- data/tryouts/15_huxtable/20_user_tryouts.rb +47 -0
- data/tryouts/20_simpledb/10_domains_tryouts.rb +36 -0
- data/tryouts/20_simpledb/20_objects_tryouts.rb +56 -0
- data/tryouts/25_ec2/10_keypairs_tryouts.rb +54 -0
- data/tryouts/25_ec2/20_groups_tryouts.rb +56 -0
- data/tryouts/25_ec2/21_groups_authorize_address_tryouts.rb +53 -0
- data/tryouts/25_ec2/22_groups_authorize_account_tryouts.rb +54 -0
- data/tryouts/25_ec2/30_addresses_tryouts.rb +42 -0
- data/tryouts/25_ec2/40_volumes_tryouts.rb +53 -0
- data/tryouts/25_ec2/50_snapshots_tryouts.rb +75 -0
- data/tryouts/26_ec2_instances/10_instance_tryouts.rb +107 -0
- data/tryouts/26_ec2_instances/50_images_tryouts.rb +7 -0
- data/tryouts/30_metadata/10_include_tryouts.rb +45 -0
- data/tryouts/30_metadata/13_object_tryouts.rb +19 -0
- data/tryouts/30_metadata/50_disk_tryouts.rb +115 -0
- data/tryouts/30_metadata/51_disk_digest_tryouts.rb +24 -0
- data/tryouts/30_metadata/53_disk_list_tryouts.rb +35 -0
- data/tryouts/30_metadata/56_disk_volume_tryouts.rb +68 -0
- data/tryouts/30_metadata/60_backup_tryouts.rb +101 -0
- data/tryouts/30_metadata/63_backup_list_tryouts.rb +38 -0
- data/tryouts/30_metadata/64_backup_disk_tryouts.rb +65 -0
- data/tryouts/30_metadata/66_backup_snapshot_tryouts.rb +76 -0
- data/tryouts/30_metadata/70_machine_tryouts.rb +85 -0
- data/tryouts/30_metadata/73_machine_list_tryouts.rb +58 -0
- data/tryouts/30_metadata/76_machine_instance_tryouts.rb +64 -0
- data/tryouts/30_metadata/77_machines_tryouts.rb +45 -0
- data/tryouts/40_routines/10_keypair_handler_tryouts.rb +52 -0
- data/tryouts/40_routines/11_group_handler_tryouts.rb +36 -0
- data/tryouts/80_cli/10_rudyec2_tryouts.rb +8 -0
- data/tryouts/80_cli/60_rudy_tryouts.rb +41 -0
- data/tryouts/exploration/console.rb +91 -0
- data/tryouts/exploration/machine.rb +23 -0
- data/tryouts/failer +6 -0
- metadata +116 -32
- data/bin/ird +0 -153
- data/lib/rudy/metadata/backups.rb +0 -67
- data/lib/rudy/metadata/debug.rb +0 -38
- data/lib/rudy/metadata/disks.rb +0 -67
- data/lib/rudy/metadata/objectbase.rb +0 -108
- data/lib/rudy/routines/helper.rb +0 -76
- data/lib/rudy/routines/helpers/dependshelper.rb +0 -34
- data/lib/rudy/routines/helpers/diskhelper.rb +0 -403
- data/lib/rudy/routines/helpers/scripthelper.rb +0 -197
- data/lib/rudy/routines/helpers/userhelper.rb +0 -37
- 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
|