File Coverage

blib/lib/MogileFS/Admin.pm
Criterion Covered Total %
statement 22 284 7.7
branch 4 140 2.8
condition 0 22 0.0
subroutine 6 51 11.7
pod 0 41 0.0
total 32 538 5.9


line stmt bran cond sub pod time code
1             package MogileFS::Admin;
2 2     2   2279 use strict;
  2         5  
  2         78  
3 2     2   11 use Carp;
  2         3  
  2         158  
4 2     2   12 use MogileFS::Backend;
  2         3  
  2         65  
5 2     2   12 use fields qw(backend readonly);
  2         4  
  2         16  
6              
7             sub new {
8 1     1 0 15 my MogileFS::Admin $self = shift;
9 1 50       13 $self = fields::new($self) unless ref $self;
10              
11 1         3863 my %args = @_;
12              
13 1 50       6 $self->{readonly} = $args{readonly} ? 1 : 0;
14 1         4 my %backend_args = ( hosts => $args{hosts} );
15 1 50       6 $backend_args{timeout} = $args{timeout} if $args{timeout};
16 1 50       15 $self->{backend} = MogileFS::Backend->new( %backend_args )
17             or _fail("couldn't instantiate MogileFS::Backend");
18              
19 1         6 return $self;
20             }
21              
22             sub readonly {
23 0     0 0 0 my MogileFS::Admin $self = shift;
24 0 0       0 return $self->{readonly} = $_[0] ? 1 : 0 if @_;
    0          
25 0         0 return $self->{readonly};
26             }
27              
28             sub replicate_now {
29 0     0 0 0 my MogileFS::Admin $self = shift;
30              
31 0 0       0 my $res = $self->{backend}->do_request("replicate_now", {})
32             or return undef;
33 0         0 return 1;
34             }
35              
36             sub get_hosts {
37 0     0 0 0 my MogileFS::Admin $self = shift;
38 0         0 my $hostid = shift;
39              
40 0 0       0 my $args = $hostid ? { hostid => $hostid } : {};
41 0 0       0 my $res = $self->{backend}->do_request("get_hosts", $args)
42             or return undef;
43              
44 0         0 my @ret = ();
45 0         0 foreach my $ct (1..$res->{hosts}) {
46 0         0 push @ret, { map { $_ => $res->{"host${ct}_$_"} }
  0         0  
47             qw(hostid status hostname hostip http_port http_get_port altip altmask) };
48             }
49              
50 0         0 return \@ret;
51             }
52              
53             sub get_devices {
54 0     0 0 0 my MogileFS::Admin $self = shift;
55 0         0 my $devid = shift;
56              
57 0 0       0 my $args = $devid ? { devid => $devid } : {};
58 0 0       0 my $res = $self->{backend}->do_request("get_devices", $args)
59             or return undef;
60              
61 0         0 my @ret = ();
62 0         0 foreach my $ct (1..$res->{devices}) {
63 0         0 push @ret, { (map { $_ => $res->{"dev${ct}_$_"} } qw(devid hostid status observed_state utilization)),
  0         0  
64 0         0 (map { $_ => $res->{"dev${ct}_$_"}+0 } qw(mb_total mb_used weight)) };
65             }
66              
67 0         0 return \@ret;
68              
69             }
70              
71             # get raw information about fids, for enumerating the dataset
72             # ( $from_fid, $count )
73             # returns:
74             # { fid => { hashref with keys: domain, class, devcount, length, key } }
75             sub list_fids {
76 0     0 0 0 my MogileFS::Admin $self = shift;
77 0         0 my ($fromfid, $count) = @_;
78              
79 0 0       0 my $res = $self->{backend}->do_request('list_fids', { from => $fromfid, to => $count })
80             or return undef;
81              
82 0         0 my $ret = {};
83 0         0 foreach my $i (1..$res->{fid_count}) {
84 0         0 $ret->{$res->{"fid_${i}_fid"}} = {
85             key => $res->{"fid_${i}_key"},
86             length => $res->{"fid_${i}_length"},
87             class => $res->{"fid_${i}_class"},
88             domain => $res->{"fid_${i}_domain"},
89             devcount => $res->{"fid_${i}_devcount"},
90             };
91             }
92 0         0 return $ret;
93             }
94              
95             sub clear_cache {
96 0     0 0 0 my MogileFS::Admin $self = shift;
97             # do the request, default to request all stats if they didn't specify any
98 0 0       0 push @_, 'all' unless @_;
99 0 0       0 my $res = $self->{backend}->do_request("clear_cache", { map { $_ => 1 } @_ })
  0         0  
100             or return undef;
101 0         0 return 1;
102             }
103              
104             # get a hashref of the domains we know about in the format of
105             # { domain_name => { class_name => mindevcount, class_name => mindevcount, ... }, ... }
106             sub get_domains {
107 1     1 0 9 my MogileFS::Admin $self = shift;
108              
109 1 0       8 my $res = $self->{backend}->do_request("get_domains", {})
110             or return undef;
111              
112 0           my $ret = {};
113 0           foreach my $i (1..$res->{domains}) {
114 0   0       $ret->{$res->{"domain$i"}} = {
      0        
115             map {
116 0           $res->{"domain${i}class${_}name"} =>
117             { mindevcount => $res->{"domain${i}class${_}mindevcount"},
118             replpolicy => $res->{"domain${i}class${_}replpolicy"} || '',
119             hashtype => $res->{"domain${i}class${_}hashtype"} || '',
120             }
121             } (1..$res->{"domain${i}classes"})
122             };
123             }
124              
125 0           return $ret;
126             }
127              
128             # create a new domain
129             sub create_domain {
130 0     0 0   my MogileFS::Admin $self = shift;
131 0 0         return undef if $self->{readonly};
132              
133 0           my $domain = shift;
134              
135 0           my $res = $self->{backend}->do_request("create_domain", { domain => $domain });
136 0 0         return undef unless $res->{domain} eq $domain;
137              
138 0           return 1;
139             }
140              
141             # delete a domain
142             sub delete_domain {
143 0     0 0   my MogileFS::Admin $self = shift;
144 0 0         return undef if $self->{readonly};
145              
146 0           my $domain = shift;
147              
148 0 0         $self->{backend}->do_request("delete_domain", { domain => $domain })
149             or return undef;
150              
151 0           return 1;
152             }
153              
154             # create a class within a domain
155             sub create_class {
156 0     0 0   my MogileFS::Admin $self = shift;
157              
158             # wrapper around _mod_class(create)
159 0           return $self->_mod_class(@_, 'create');
160             }
161              
162              
163             # update a class's mindevcount within a domain
164             sub update_class {
165 0     0 0   my MogileFS::Admin $self = shift;
166              
167             # wrapper around _mod_class(update)
168 0           return $self->_mod_class(@_, 'update');
169             }
170              
171             # delete a class
172             sub delete_class {
173 0     0 0   my MogileFS::Admin $self = shift;
174 0 0         return undef if $self->{readonly};
175              
176 0           my ($domain, $class) = @_;
177              
178 0 0         $self->{backend}->do_request("delete_class", {
179             domain => $domain,
180             class => $class,
181             }) or return undef;
182              
183 0           return 1;
184             }
185              
186              
187             # create a host
188             sub create_host {
189 0     0 0   my MogileFS::Admin $self = shift;
190 0           my $host = shift;
191 0 0         return undef unless $host;
192              
193 0           my $args = shift;
194 0 0         return undef unless ref $args eq 'HASH';
195 0 0 0       return undef unless $args->{ip} && $args->{port};
196              
197 0           return $self->_mod_host($host, $args, 'create');
198             }
199              
200             # edit a host
201             sub update_host {
202 0     0 0   my MogileFS::Admin $self = shift;
203 0           my $host = shift;
204 0 0         return undef unless $host;
205              
206 0           my $args = shift;
207 0 0         return undef unless ref $args eq 'HASH';
208              
209 0           return $self->_mod_host($host, $args, 'update');
210             }
211              
212             # delete a host
213             sub delete_host {
214 0     0 0   my MogileFS::Admin $self = shift;
215 0 0         return undef if $self->{readonly};
216              
217 0           my $host = shift;
218 0 0         return undef unless $host;
219              
220 0 0         $self->{backend}->do_request("delete_host", { host => $host })
221             or return undef;
222 0           return 1;
223             }
224              
225             # create a new device
226             sub create_device {
227 0     0 0   my MogileFS::Admin $self = shift;
228 0 0         return undef if $self->{readonly};
229              
230 0           my (%opts) = @_; #hostname or hostid, devid, state (optional)
231              
232 0 0         my $res = $self->{backend}->do_request("create_device", \%opts)
233             or return undef;
234              
235 0           return 1;
236             }
237              
238             # edit a device
239             sub update_device {
240 0     0 0   my MogileFS::Admin $self = shift;
241 0 0         return undef if $self->{readonly};
242 0           my $host = shift;
243 0           my $device = shift;
244 0 0         return undef unless $host;
245 0 0         return undef unless $device;
246              
247 0           my $args = shift;
248 0 0         return undef unless ref $args eq 'HASH';
249              
250             # TODO: provide a native update_device in the MogileFS::Admin command set.
251 0 0         if ($args->{status}){
252 0 0         $self->change_device_state($host, $device, $args->{status}) or return undef;
253             }
254 0 0         if ($args->{weight}){
255 0 0         $self->change_device_weight($host, $device, $args->{weight}) or return undef;
256             }
257              
258 0           return 1;
259             }
260              
261             # change the state of a device; pass in the hostname of the host the
262             # device is located on, the device id number, and the state you want
263             # the host to be set to. returns 1 on success, undef on error.
264             sub change_device_state {
265 0     0 0   my MogileFS::Admin $self = shift;
266 0 0         return undef if $self->{readonly};
267              
268 0           my ($host, $device, $state) = @_;
269              
270 0 0         my $res = $self->{backend}->do_request("set_state", {
271             host => $host,
272             device => $device,
273             state => $state,
274             }) or return undef;
275              
276 0           return 1;
277             }
278              
279             # change the weight of a device by passing in the hostname and
280             # the device id
281             sub change_device_weight {
282 0     0 0   my MogileFS::Admin $self = shift;
283 0 0         return undef if $self->{readonly};
284              
285 0           my ($host, $device, $weight) = @_;
286 0           $weight += 0;
287              
288 0 0         my $res = $self->{backend}->do_request("set_weight", {
289             host => $host,
290             device => $device,
291             weight => $weight,
292             }) or return undef;
293              
294 0           return 1;
295             }
296              
297             # returns a hash (list) of key => weight
298             sub _get_slave_keys {
299 0     0     my MogileFS::Admin $self = shift;
300 0           my $backend = $self->{backend};
301              
302 0           my $keys_res = $backend->do_request("server_setting", {
303             key => "slave_keys",
304             });
305              
306 0 0         return () unless $keys_res;
307              
308 0           my %slave_keys;
309              
310 0           foreach my $slave (split /,/, $keys_res->{value}) {
311 0           my ($key, $weight) = split /=/, $slave, 2;
312              
313             # Weight can be zero, so don't default to 1 if it's defined and longer than 0 characters.
314 0 0 0       unless (defined $weight && length $weight) {
315 0           $weight = 1;
316             }
317              
318 0           $slave_keys{$key} = $weight;
319             }
320              
321 0           return %slave_keys;
322             }
323              
324             # returns a hash (list) of key => options
325             sub _set_slave_keys {
326 0     0     my MogileFS::Admin $self = shift;
327 0           my $backend = $self->{backend};
328              
329 0           my %slave_keys = @_;
330              
331 0           my @keys;
332              
333 0           foreach my $key (keys %slave_keys) {
334 0           my $weight = $slave_keys{$key};
335 0 0 0       if (defined $weight && length $weight && $weight != 1) {
      0        
336 0           $key .= "=$weight";
337             }
338 0           push @keys, $key;
339             }
340              
341 0           my $keys_res = $backend->do_request("set_server_setting", {
342             key => "slave_keys",
343             value => join(',', @keys),
344             });
345              
346 0 0         return 0 unless $keys_res;
347 0           return 1;
348             }
349              
350             # returns a hashref of key => [dsn, username, password] specifying slave nodes which can be connected to.
351             sub slave_list {
352 0     0 0   my MogileFS::Admin $self = shift;
353              
354 0           my $backend = $self->{backend};
355              
356 0           my %slave_keys = $self->_get_slave_keys;
357 0           my %return;
358              
359 0           foreach my $key (keys %slave_keys) {
360 0           my $slave_res = $backend->do_request("server_setting", {
361             key => "slave_$key",
362             });
363 0 0         next unless $slave_res;
364 0           my ($dsn, $username, $password) = split /\|/, $slave_res->{value};
365 0           $return{$key} = [$dsn, $username, $password];
366             }
367              
368 0           return \%return;
369             }
370              
371             sub slave_add {
372 0     0 0   my MogileFS::Admin $self = shift;
373 0           my ($key, $dsn, $username, $password) = @_;
374              
375 0           my $backend = $self->{backend};
376              
377 0           my %slave_keys = $self->_get_slave_keys;
378              
379 0 0         if (exists $slave_keys{$key}) {
380 0           return 0;
381             }
382              
383 0 0         my $res = $backend->do_request("set_server_setting", {
384             key => "slave_$key",
385             value => join('|', $dsn, $username, $password),
386             }) or return undef;
387              
388 0           $slave_keys{$key} = undef;
389              
390 0           $self->_set_slave_keys(%slave_keys);
391              
392 0           return 1;
393             }
394              
395             sub slave_modify {
396 0     0 0   my MogileFS::Admin $self = shift;
397 0           my $key = shift;
398 0           my %opts = @_;
399              
400 0           my $backend = $self->{backend};
401              
402 0           my %slave_keys = $self->_get_slave_keys;
403              
404 0 0         unless (exists $slave_keys{$key}) {
405 0           return 0;
406             }
407              
408 0 0         my $get_res = $backend->do_request("server_setting", {
409             key => "slave_$key",
410             }) or return undef;
411              
412 0           my ($dsn, $username, $password) = split /\|/, $get_res->{value};
413              
414 0 0         $dsn = $opts{dsn} if exists $opts{dsn};
415 0 0         $username = $opts{username} if exists $opts{username};
416 0 0         $password = $opts{password} if exists $opts{password};
417              
418 0 0         my $set_res = $backend->do_request("set_server_setting", {
419             key => "slave_$key",
420             value => join('|', $dsn, $username, $password),
421             }) or return undef;
422              
423 0           return 1;
424             }
425              
426             sub slave_delete {
427 0     0 0   my MogileFS::Admin $self = shift;
428 0           my $key = shift;
429              
430 0           my $backend = $self->{backend};
431              
432 0           my %slave_keys = $self->_get_slave_keys;
433              
434 0 0         unless (exists $slave_keys{$key}) {
435 0           return 0;
436             }
437              
438 0 0         my $res = $backend->do_request("set_server_setting", {
439             key => "slave_$key",
440             value => undef,
441             }) or return undef;
442              
443 0           delete $slave_keys{$key};
444              
445 0           $self->_set_slave_keys(%slave_keys);
446              
447 0           return 1;
448             }
449              
450             sub fsck_start {
451 0     0 0   my MogileFS::Admin $self = shift;
452 0           return $self->{backend}->do_request("fsck_start", {});
453             }
454              
455             sub fsck_stop {
456 0     0 0   my MogileFS::Admin $self = shift;
457 0           return $self->{backend}->do_request("fsck_stop", {});
458             }
459              
460             sub fsck_reset {
461 0     0 0   my MogileFS::Admin $self = shift;
462 0           my %opts = @_;
463 0           my $polonly = delete $opts{policy_only};
464 0           my $startpos = delete $opts{startpos};
465 0 0         Carp::croak("Unknown options: ". join(", ", keys %opts)) if %opts;
466 0           return $self->{backend}->do_request("fsck_reset", {
467             policy_only => $polonly,
468             startpos => $startpos,
469             });
470             }
471              
472             sub fsck_clearlog {
473 0     0 0   my MogileFS::Admin $self = shift;
474 0           return $self->{backend}->do_request("fsck_clearlog", {});
475             }
476              
477             sub fsck_status {
478 0     0 0   my MogileFS::Admin $self = shift;
479 0           return $self->{backend}->do_request("fsck_status", {});
480             }
481              
482             sub fsck_log_rows {
483 0     0 0   my MogileFS::Admin $self = shift;
484 0           my %args = @_;
485 0           my $after = delete $args{after_logid};
486 0 0         die if %args;
487              
488 0           my $ret = $self->{backend}->do_request("fsck_getlog", {
489             after_logid => $after,
490             });
491 0           my @ret;
492 0           for (my $i = 1; $i <= $ret->{row_count}; $i++) {
493 0           my $rec = {};
494 0           foreach my $k (qw(logid utime fid evcode devid)) {
495 0           $rec->{$k} = $ret->{"row_${i}_$k"};
496             }
497 0           push @ret, $rec;
498             }
499 0           return @ret;
500             }
501              
502             sub set_server_setting {
503 0     0 0   my MogileFS::Admin $self = shift;
504 0           my ($key, $val) = @_;
505 0           my $res = $self->{backend}->do_request("set_server_setting", {
506             key => $key,
507             value => $val,
508             });
509 0 0         return 0 unless $res;
510 0           return 1;
511             }
512              
513             sub server_settings {
514 0     0 0   my MogileFS::Admin $self = shift;
515 0           my ($key, $val) = @_;
516 0           my $res = $self->{backend}->do_request("server_settings", {});
517 0 0         return 0 unless $res;
518 0           my $ret = {};
519 0           for (my $i = 1; $i <= $res->{key_count}; $i++) {
520 0           $ret->{$res->{"key_$i"}} = $res->{"value_$i"};
521             }
522 0           return $ret;
523             }
524              
525             sub rebalance_status {
526 0     0 0   my MogileFS::Admin $self = shift;
527 0           return $self->{backend}->do_request("rebalance_status", {});
528             }
529              
530             sub rebalance_start {
531 0     0 0   my MogileFS::Admin $self = shift;
532 0           return $self->{backend}->do_request("rebalance_start", {});
533             }
534              
535             sub rebalance_test {
536 0     0 0   my MogileFS::Admin $self = shift;
537 0           return $self->{backend}->do_request("rebalance_test", {});
538             }
539              
540             sub rebalance_stop {
541 0     0 0   my MogileFS::Admin $self = shift;
542 0           return $self->{backend}->do_request("rebalance_stop", {});
543             }
544              
545             sub rebalance_reset {
546 0     0 0   my MogileFS::Admin $self = shift;
547 0           return $self->{backend}->do_request("rebalance_reset", {});
548             }
549              
550             sub rebalance_set_policy {
551 0     0 0   my MogileFS::Admin $self = shift;
552              
553 0           my $policy = shift;
554 0           return $self->{backend}->do_request("rebalance_set_policy", {
555             policy => $policy,
556             });
557             }
558              
559             ################################################################################
560             # MogileFS::Admin class methods
561             #
562              
563             sub _fail {
564 0     0     croak "MogileFS::Admin: $_[0]";
565             }
566              
567             # FIXME: is this used?
568             sub _debug {
569 0 0   0     return 1 unless $MogileFS::DEBUG;
570 0           my $msg = shift;
571 0           my $ref = shift;
572 0           chomp $msg;
573 0           eval "use Data::Dumper;";
574 0           print STDERR "$msg\n" . Dumper($ref) . "\n";
575 0           return 1;
576             }
577              
578             # modify a class within a domain
579             sub _mod_class {
580 0     0     my MogileFS::Admin $self = shift;
581 0 0         return undef if $self->{readonly};
582              
583 0           my ($domain, $class, $args, $verb) = @_;
584 0   0       $verb ||= 'create';
585              
586 0           my $res = $self->{backend}->do_request("${verb}_class", {
587             domain => $domain,
588             class => $class,
589             %$args,
590             });
591 0 0         return undef unless $res->{class} eq $class;
592              
593 0           return 1;
594             }
595              
596             # modify a host
597             sub _mod_host {
598 0     0     my MogileFS::Admin $self = shift;
599 0 0         return undef if $self->{readonly};
600              
601 0           my ($host, $args, $verb) = @_;
602              
603 0   0       $args ||= {};
604 0           $args->{host} = $host;
605 0   0       $verb ||= 'create';
606              
607 0           my $res = $self->{backend}->do_request("${verb}_host", $args);
608 0 0         return undef unless $res->{host} eq $host;
609              
610 0           return 1;
611             }
612              
613             sub errstr {
614 0     0 0   my MogileFS::Admin $self = shift;
615 0 0         return undef unless $self->{backend};
616 0           return $self->{backend}->errstr;
617             }
618              
619             sub errcode {
620 0     0 0   my MogileFS::Admin $self = shift;
621 0 0         return undef unless $self->{backend};
622 0           return $self->{backend}->errcode;
623             }
624              
625             sub err {
626 0     0 0   my MogileFS::Admin $self = shift;
627 0 0         return undef unless $self->{backend};
628 0           return $self->{backend}->err;
629             }
630              
631             1;