File Coverage

blib/lib/Device/RAID/Poller.pm
Criterion Covered Total %
statement 17 84 20.2
branch 0 22 0.0
condition 0 6 0.0
subroutine 6 13 46.1
pod 7 7 100.0
total 30 132 22.7


line stmt bran cond sub pod time code
1             package Device::RAID::Poller;
2              
3 1     1   67646 use 5.006;
  1         4  
4 1     1   6 use strict;
  1         2  
  1         21  
5 1     1   5 use warnings;
  1         2  
  1         46  
6 1     1   8 use base 'Error::Helper';
  1         1  
  1         531  
7 1     1   1264 use Module::List qw(list_modules);
  1         24512  
  1         71  
8 1     1   706 use JSON;
  1         10244  
  1         6  
9              
10             =head1 NAME
11              
12             Device::RAID::Poller - Basic RAID status poller, returning RAID disk devices, types, and status.
13              
14             =head1 VERSION
15              
16             Version 0.1.2
17              
18             =cut
19              
20             our $VERSION = '0.1.2';
21              
22              
23             =head1 SYNOPSIS
24              
25             Quick summary of what the module does.
26              
27             Perhaps a little code snippet.
28              
29             use Device::RAID::Poller;
30              
31             my $drp = Device::RAID::Poller->new();
32             ...
33              
34             =head1 METHODS
35              
36             =head2 new
37              
38             This initiates the object.
39              
40              
41             =cut
42              
43             sub new {
44 0     0 1   my $self = {
45             perror=>undef,
46             error=>undef,
47             errorString=>"",
48             errorExtra=>{
49             flags=>{
50             1=>'invalidModule',
51             2=>'notLoaded',
52             }
53             },
54             modules=> {},
55             loaded=> {},
56             };
57 0           bless $self;
58              
59 0           return $self;
60             }
61              
62             =head2 modules_get
63              
64             Gets the currently specified modules to run.
65              
66             A return of undef means none are set and at run-time each module
67             will be loaded and tried.
68              
69             my @modules=$drp->modules_get;
70              
71             =cut
72              
73             sub modules_get {
74 0     0 1   my $self=$_[0];
75              
76 0 0         if( ! $self->errorblank ){
77 0           return undef;
78             }
79              
80 0           return keys %{ $self->{modules} };
  0            
81             }
82              
83             =head2 modules_set
84              
85             This sets modules to use if one does not wish to attempt to load
86             them all upon load.
87              
88             =cut
89              
90             sub modules_set {
91 0     0 1   my $self=$_[0];
92 0           my @modules;
93 0 0         if ( defined( $_[1] ) ){
94 0           @modules=@{ $_[1] }
  0            
95             }
96              
97 0 0         if( ! $self->errorblank ){
98 0           return undef;
99             }
100              
101 0           my $valid_backends=$self->list_backends;
102              
103 0 0         if (!defined( $modules[0] )){
104 0           $self->{modules}=\@modules;
105             }
106              
107 0           foreach my $module ( @modules ){
108 0 0         if ( ! exists( $valid_backends->{'Device::RAID::Poller::Backends::'.$module} ) ){
109 0           $self->{error}=1;
110 0           $self->{errorString}='"'.$module.'"';
111 0           $self->warn;
112 0           return undef;
113             }
114             }
115              
116 0           $self->{modules}=\@modules;
117              
118 0           return 1;
119             }
120              
121             =head2 list_backends
122              
123             This lists the available backends. This lists the full
124             backends name, meaning it will return 'Device::RAID::Poller::Backends::fbsdGmiiror';
125              
126             my $backends=$drp->list_backends;
127              
128             The returned value is a hashref where each key is a name
129             of a backend module.
130              
131             If you want this as a array, you can do the following.
132              
133             my @backends=keys %{ $drp->list_backends };
134              
135             =cut
136              
137             sub list_backends{
138 0     0 1   my $backends=list_modules("Device::RAID::Poller::Backends::", { list_modules => 1});
139              
140 0           return $backends;
141             }
142              
143             =head2 list_loaded
144              
145             This returns the list of backends that loaded
146             successfully.
147              
148             =cut
149              
150             sub list_loaded {
151 0     0 1   my $self=$_[0];
152              
153 0 0         if( ! $self->errorblank ){
154 0           return undef;
155             }
156              
157 0           return keys %{ $self->{loaded} };
  0            
158             }
159              
160             =head2 load
161              
162             This loads up the modules. Each one in the list is
163             checked and then if started successfully, it is saved
164             for reuse later.
165              
166             my $loaded=$drp->load;
167             if ( $loaded ){
168             print "One or more backends are now loaded.\n";
169             }else{
170             print "No usable backends found.\n";
171             }
172              
173             =cut
174              
175             sub load {
176 0     0 1   my $self=$_[0];
177              
178 0 0         if( ! $self->errorblank ){
179 0           return undef;
180             }
181              
182 0           my @backends=keys %{ $self->list_backends };
  0            
183              
184 0           my $loaded=0;
185              
186 0           foreach my $backend ( @backends ){
187 0           my $backend_test;
188             my $usable;
189 0           my $test_string='
190             use '.$backend.';
191             $backend_test='.$backend.'->new;
192             $usable=$backend_test->usable;
193             ';
194 0           eval( $test_string );
195 0 0         if ( $usable ){
196 0           $self->{loaded}{$backend}=$backend_test;
197 0           $loaded=1;
198             }
199             }
200              
201 0           return $loaded;
202             }
203              
204             =head2 run
205              
206             Runs the poller backend and report the results.
207              
208             If nothing is nothing is loaded, load will be called.
209              
210             m6 %status=$drp->run;
211              
212             =cut
213              
214             sub run {
215 0     0 1   my $self=$_[0];
216              
217 0 0         if( ! $self->errorblank ){
218 0           return undef;
219             }
220              
221             # Load should always be called before run.
222 0           my @loaded=$self->list_loaded;
223 0 0         if ( ! defined($loaded[0]) ){
224 0           $self->{error}=2;
225 0           $self->{errorString}='No backend modules loaded';
226 0           $self->warn;
227 0           return undef;
228             }
229              
230 0           my %return_hash;
231              
232             # Run each backend and check the return.
233 0           foreach my $backend ( @loaded ){
234 0           my %found;
235 0           eval{
236 0           %found=$self->{loaded}{$backend}->run;
237             };
238              
239             # If we got a good return, pull each device into the return hash.
240 0 0 0       if (
      0        
241             defined($found{status}) &&
242             defined($found{devices}) &&
243             $found{status}
244             ){
245 0           my @devs=keys( %{ $found{devices} } );
  0            
246 0           foreach my $dev ( @devs ){
247 0           $return_hash{$dev}=$found{devices}{$dev};
248             }
249             }
250             }
251              
252 0           return %return_hash;
253             }
254              
255             =head1 STATUS HASH
256              
257             The statu hash made of of hashes. Each subhash is the of the type
258             documented under the section RAID HASH.
259              
260             The keys of this hash are the device name as regarded by the module
261             in question. These may not represent a valid name under /dev, but may
262             just be a name generated to differentiate it from other devices. Both
263             the ZFS and MegaCLI backends are examples of this. In ZFS cases the
264             zpool is just a mountpoint some place. As to MegaCLI it is a name generated
265             from info gathered from the card.
266              
267             =head2 RAID HASH
268              
269             =head3 status
270              
271             This can be any of the following values.
272              
273             bad - missing disks
274             good - all disks are present
275             rebuilding - one or more drives is being rebuilt
276             unknown - Unable to determine the current status.
277              
278             =head2 name
279              
280             The name of the device.
281              
282             =head2 backend
283              
284             The backend that put polled this device. This is the name of the module
285             under "Device::RAID::Poller::Backends::". So "Device::RAID::Poller::Backends::ZFS"
286             would be "ZFS".
287              
288             =head3 good
289              
290             This is a list of good disks in the array..
291              
292             =head3 bad
293              
294             This is a list of bad disks in the array.
295              
296             =head3 spare
297              
298             This is a list of spare disks in the array.
299              
300             =head3 type
301              
302             This is type of RAID in question. This is a string that describes the RAID array.
303              
304             This may also be complex, such as for ZFS it is the output of 'zpool status' for the
305             pool in question.
306              
307             =head3 BBUstatus
308              
309             This can be any of the following values.
310              
311             notPresent - No BBU.
312             na - Not applicable. Device does not support it.
313             failed - BBU failed.
314             good - BBU is good.
315             charging - BBU is charging.
316             unknown - BBU status is not known.
317              
318             =head1 BACKENDS
319              
320             A backend is a module that exists directly under "Device::RAID::Poller::Backends::".
321              
322             Three methods must be present and as of currently are expected to run with no arguments.
323              
324             new
325             usable
326             run
327              
328             The new method creates the object.
329              
330             The usable method runs some basic checks to see if it is usable or not.
331              
332             The run method returns a hash with the assorted info. See the section BACKEND RETURN HASH for
333             more information.
334              
335             =head2 BACKEND RETURN HASH
336              
337             This is composed of keys below.
338              
339             devices - A array of hashes as documented in the section RAID HASH.
340             stutus - A 0/1 representing if it the the run method was successful.
341              
342             =head1 ERROR HANDLING/CODES
343              
344             =head2 1/invalidModule
345              
346             A non-existent module to use was specified.
347              
348             =head2 2/notLoaded
349              
350             Either load has not been called or no usable modules were found.
351              
352             =head1 AUTHOR
353              
354             Zane C. Bowers-Hadley, C<< >>
355              
356             =head1 BUGS
357              
358             Please report any bugs or feature requests to C, or through
359             the web interface at L. I will be
360             notified, and then you'll automatically be notified of progress on your bug as I make changes.
361              
362              
363              
364              
365             =head1 SUPPORT
366              
367             You can find documentation for this module with the perldoc command.
368              
369             perldoc Device::RAID::Poller
370              
371              
372             You can also look for information at:
373              
374             =over 4
375              
376             =item * RT: CPAN's request tracker (report bugs here)
377              
378             L
379              
380             =item * AnnoCPAN: Annotated CPAN documentation
381              
382             L
383              
384             =item * CPAN Ratings
385              
386             L
387              
388             =item * Search CPAN
389              
390             L
391              
392             =back
393              
394              
395             =head1 ACKNOWLEDGEMENTS
396              
397              
398             =head1 LICENSE AND COPYRIGHT
399              
400             This software is Copyright (c) 2019 by Zane C. Bowers-Hadley.
401              
402             This is free software, licensed under:
403              
404             The Artistic License 2.0 (GPL Compatible)
405              
406              
407             =cut
408              
409             1; # End of Device::RAID::Poller