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   72409 use 5.006;
  1         4  
4 1     1   6 use strict;
  1         2  
  1         22  
5 1     1   5 use warnings;
  1         1  
  1         30  
6 1     1   13 use base 'Error::Helper';
  1         4  
  1         544  
7 1     1   1331 use Module::List qw(list_modules);
  1         31208  
  1         81  
8 1     1   771 use JSON;
  1         11155  
  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.2.0
17              
18             =cut
19              
20             our $VERSION = '0.2.0';
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             initializing - Array is being created.
276             rebuilding - one or more drives is being rebuilt
277             unknown - Unable to determine the current status.
278              
279             =head3 name
280              
281             The name of the device.
282              
283             =head3 backend
284              
285             The backend that put polled this device. This is the name of the module
286             under "Device::RAID::Poller::Backends::". So "Device::RAID::Poller::Backends::ZFS"
287             would be "ZFS".
288              
289             =head3 good
290              
291             This is a list of good disks in the array..
292              
293             =head3 bad
294              
295             This is a list of bad disks in the array.
296              
297             =head3 spare
298              
299             This is a list of spare disks in the array.
300              
301             =head3 type
302              
303             This is type of RAID in question. This is a string that describes the RAID array.
304              
305             This may also be complex, such as for ZFS it is the output of 'zpool status' for the
306             pool in question.
307              
308             =head3 BBUstatus
309              
310             This can be any of the following values.
311              
312             notPresent - No BBU.
313             na - Not applicable. Device does not support it.
314             failed - BBU failed.
315             good - BBU is good.
316             charging - BBU is charging.
317             unknown - BBU status is not known.
318             testing - BBU is currently in testing mode
319              
320             =head1 BACKENDS
321              
322             A backend is a module that exists directly under "Device::RAID::Poller::Backends::".
323              
324             Three methods must be present and as of currently are expected to run with no arguments.
325              
326             new
327             usable
328             run
329              
330             The new method creates the object.
331              
332             The usable method runs some basic checks to see if it is usable or not.
333              
334             The run method returns a hash with the assorted info. See the section BACKEND RETURN HASH for
335             more information.
336              
337             =head2 BACKEND RETURN HASH
338              
339             This is composed of keys below.
340              
341             devices - A array of hashes as documented in the section RAID HASH.
342             stutus - A 0/1 representing if it the the run method was successful.
343              
344             =head1 ERROR HANDLING/CODES
345              
346             =head2 1/invalidModule
347              
348             A non-existent module to use was specified.
349              
350             =head2 2/notLoaded
351              
352             Either load has not been called or no usable modules were found.
353              
354             =head1 AUTHOR
355              
356             Zane C. Bowers-Hadley, C<< >>
357              
358             =head1 BUGS
359              
360             Please report any bugs or feature requests to C, or through
361             the web interface at L. I will be
362             notified, and then you'll automatically be notified of progress on your bug as I make changes.
363              
364              
365              
366              
367             =head1 SUPPORT
368              
369             You can find documentation for this module with the perldoc command.
370              
371             perldoc Device::RAID::Poller
372              
373              
374             You can also look for information at:
375              
376             =over 4
377              
378             =item * RT: CPAN's request tracker (report bugs here)
379              
380             L
381              
382             =item * AnnoCPAN: Annotated CPAN documentation
383              
384             L
385              
386             =item * CPAN Ratings
387              
388             L
389              
390             =item * Search CPAN
391              
392             L
393              
394             =item * Repository
395              
396             L
397              
398             =back
399              
400              
401             =head1 ACKNOWLEDGEMENTS
402              
403              
404             =head1 LICENSE AND COPYRIGHT
405              
406             This software is Copyright (c) 2019 by Zane C. Bowers-Hadley.
407              
408             This is free software, licensed under:
409              
410             The Artistic License 2.0 (GPL Compatible)
411              
412              
413             =cut
414              
415             1; # End of Device::RAID::Poller