File Coverage

blib/lib/Device/RAID/Poller/Backends/Avago_tw_cli.pm
Criterion Covered Total %
statement 8 90 8.8
branch 0 46 0.0
condition 0 36 0.0
subroutine 3 6 50.0
pod 3 3 100.0
total 14 181 7.7


line stmt bran cond sub pod time code
1             package Device::RAID::Poller::Backends::Avago_tw_cli;
2              
3 1     1   68301 use 5.006;
  1         15  
4 1     1   7 use strict;
  1         2  
  1         33  
5 1     1   7 use warnings;
  1         1  
  1         1258  
6              
7             =head1 NAME
8              
9             Device::RAID::Poller::Backends::Avago_tw_cli - Handles polling using the Avago tw_cli utility.
10              
11             =head1 VERSION
12              
13             Version 0.0.1
14              
15             =cut
16              
17             our $VERSION = '0.0.1';
18              
19             =head1 SYNOPSIS
20              
21             use Device::RAID::Poller::Backends::Avago_tw_cli;
22            
23             my $backend = Device::RAID::Poller::Backends::Avago_tw_cli->new;
24            
25             my $usable=$backend->usable;
26             my %return_hash;
27             if ( $usable ){
28             %return_hash=$backend->run;
29             my %status=$backend->run;
30             use Data::Dumper;
31             print Dumper( \%status );
32             }
33              
34             =head1 METHODS
35              
36             =head2 new
37              
38             Initiates the backend object.
39              
40             my $backend = Device::RAID::Poller::Backends::Avago_tw_cli->new;
41              
42             =cut
43              
44             sub new {
45 0     0 1   my $self = {
46             usable => 0,
47             adapters => 0,
48             };
49 0           bless $self;
50              
51 0           return $self;
52             }
53              
54             =head2 run
55              
56             Runs the poller backend and report the results.
57              
58             If nothing is nothing is loaded, load will be called.
59              
60             my %status=$backend->run;
61             use Data::Dumper;
62             print Dumper( \%status );
63              
64             =cut
65              
66             sub run {
67 0     0 1   my $self = $_[0];
68              
69 0           my %return_hash = (
70             'status' => 0,
71             'devices' => {},
72             );
73              
74             # if not usable, no point in continuing
75 0 0         if ( !$self->{usable} ) {
76 0           return %return_hash;
77             }
78              
79             # need to parse this to get the available ontrollers
80             #
81             ## tw_cli show
82             #Ctl Model (V)Ports Drives Units NotOpt RRate VRate BBU
83             #------------------------------------------------------------------------
84             #c2 9690SA-8I 6 6 2 0 1 1 Charging
85 0           my $raw = `tw_cli show`;
86 0 0         if ( $? != 0 ) {
87 0           return %return_hash;
88             }
89 0           my @raw_split = split( /\n/, $raw );
90              
91             # controller stuff starts on line tree, array are zero indexed
92 0           my $line_int = 2;
93              
94             # holds a list of the found controllers
95 0           my %controllers;
96 0           while ( defined( $raw_split[$line_int] ) ) {
97 0           my ( $controller, $model, $vports, $drives, $units, $notopt, $rrate, $vrate, $bbu )
98             = split( /[\t\ ]+/, $raw_split[$line_int], 9 );
99              
100             # make sure we have the info we care about
101 0 0 0       if ( defined($controller)
102             && defined($bbu) )
103             {
104             # normalize the found BBU data
105 0 0 0       if ( $bbu =~ /Charging/ ) {
    0 0        
    0          
    0          
    0          
106 0           $bbu = 'charging';
107             }
108             elsif ( $bbu =~ /^-/ ) {
109 0           $bbu = 'notPresent';
110             }
111             elsif ( $bbu =~ /[Oo][Kk]/ ) {
112 0           $bbu = 'good';
113             }
114             elsif ( $bbu =~ /Testing/ ) {
115 0           $bbu = 'testing';
116             }elsif (
117             ($bbu=~/Fault/) ||
118             ($bbu=~/WeakBat/) ||
119             ($bbu=~/Error/)
120             ) {
121 0           $bbu='failed';
122             }
123             else {
124 0           $bbu = 'unknown';
125             }
126              
127 0           $controllers{$controller} = $bbu;
128             }
129              
130 0           $line_int++;
131             }
132              
133             # parse thise to figure out drive status
134             #
135             ## tw_cli /c2 show
136             #Unit UnitType Status %RCmpl %V/I/M Stripe Size(GB) Cache AVrfy
137             #------------------------------------------------------------------------------
138             #u0 RAID-1 OK - - - 298.013 Ri ON
139             #u1 RAID-5 OK - - 64K 2793.94 Ri ON
140             #
141             #VPort Status Unit Size Type Phy Encl-Slot Model
142             #------------------------------------------------------------------------------
143             #p0 OK u0 298.09 GB SATA 0 - ST3320613AS
144             #p1 OK u0 298.09 GB SATA 1 - ST3320613AS
145             #p2 OK u1 931.51 GB SATA 2 - Hitachi HDS721010CL
146             #p3 OK u1 931.51 GB SATA 3 - Hitachi HDS721010CL
147             #p4 OK u1 931.51 GB SATA 4 - Hitachi HDS721010CL
148             #p5 OK u1 931.51 GB SATA 5 - Hitachi HDS721010CL
149 0           foreach my $controller ( @{ keys(%controllers) } ) {
  0            
150 0           $raw = `tw_cli /$controller show`;
151 0           my $process = 1;
152 0 0         if ( $? != 0 ) {
153 0           $process = 0;
154             }
155 0           @raw_split = split( /\n/, $raw );
156              
157 0           my @arrays;
158              
159             # raid stuff starts on line three
160 0           $line_int = 2;
161 0           while ( defined( $raw_split[$line_int] ) ) {
162 0           my @line_split = split( /[\t\ ]+/, $raw_split[$line_int] );
163              
164 0 0 0       if ( defined( $line_split[0] )
165             && ( $line_split[0] =~ /^u[0123456789]+/ ) )
166             {
167              
168             # normalize array status
169 0           my $status=$line_split[1];
170 0 0 0       if ($status =~ /OK/) {
    0 0        
    0 0        
    0          
171 0           $status='good';
172             }elsif ( $status=~/^INIT/ ) {
173 0           $status='initializing';
174             }elsif (
175             ( $status =~ /^REBUILDING/ ) ||
176             ( $status =~ /^RECOVERY/ ) ||
177             ( $status =~ /^MIGRATING/ )
178             ){
179 0           $status='rebuilding';
180             }elsif (
181             ( $status=~/DEGRADED/ ) ||
182             ( $status=~/INOPERABLE/ )
183             ) {
184 0           $status='failed';
185             }else {
186 0           $status='unknown';
187             }
188              
189             # add a found array
190             $return_hash{devices}{'Avago_tw_cli '.$line_split[0]}={
191 0           BBUstatus=>$controllers{$controller},
192             good=>[],
193             bad=>[],
194             spare=>[],
195             $status=>$status,
196             backend=>'Avago_tw_cli',
197             type=>$line_split[1],
198             };
199              
200             }
201              
202             # handle it if we find a drive line
203 0 0 0       if ( defined( $line_split[0] )
      0        
      0        
      0        
204             && ( $line_split[0] =~ /^p[0123456789]+/ ) &&
205             defined( $line_split[1] ) &&
206             defined( $line_split[2] ) &&
207             ( $line_split[2] =~ /^u[0123456789]+/ )
208             )
209             {
210 0 0         if ($line_split[1] =~ /OK/) {
211 0           push(@{ $return_hash{devices}{'Avago_tw_cli '.$line_split[2]}{good} }, $line_split[0]);
  0            
212             }else {
213 0           push(@{ $return_hash{devices}{'Avago_tw_cli '.$line_split[2]}{bad} }, $line_split[0]);
  0            
214             }
215             }
216              
217 0           $line_int++;
218             }
219              
220             }
221              
222 0           $return_hash{status} = 1;
223 0           return %return_hash;
224             }
225              
226             =head2 usable
227              
228             Returns a perl boolean for if it is usable or not.
229              
230             my $usable=$backend->usable;
231             if ( ! $usable ){
232             print "This backend is not usable.\n";
233             }
234              
235             =cut
236              
237             sub usable {
238 0     0 1   my $self = $_[0];
239              
240 0 0 0       if ( ( $^O !~ 'linux' )
241             && ( $^O !~ 'freebsd' ) )
242             {
243 0           $self->{usable} = 0;
244 0           return 0;
245             }
246              
247             # make sure we can locate arcconf
248 0           my $arcconf_bin = `/bin/sh -c 'which tw_cli 2> /dev/null'`;
249 0 0         if ( $? != 0 ) {
250 0           $self->{usable} = 0;
251 0           return 0;
252             }
253              
254             # make sure we have atleast one device
255             #
256             ## tw_cli show
257             #Ctl Model (V)Ports Drives Units NotOpt RRate VRate BBU
258             #------------------------------------------------------------------------
259             #c2 9690SA-8I 6 6 2 0 1 1 Charging
260 0           my $raw = `tw_cli show`;
261 0 0         if ( $? != 0 ) {
262 0           $self->{usable} = 0;
263 0           return 0;
264             }
265 0           my @raw_split = split( /\n/, $raw );
266              
267             # if we don't exit zero it means something went wrong and should not
268             # bother trying to do more with it
269 0 0         if ( $? != 0 ) {
270 0           $self->{usable} = 0;
271 0           return 0;
272             }
273              
274 0 0         if ( defined( $raw_split[2] ) ) {
275 0           my @third_line = split( /[\t\ ]/, $raw_split[2], 9 );
276              
277             # we don't have a BBU status
278 0 0         if ( !defined( $third_line[8] ) ) {
279 0           $self->{usable} = 0;
280 0           return 0;
281             }
282              
283             # the first column does not match /^c[0123456789]+$/, e.g. "c2",
284             # so something is wrong or their are no controllers
285 0 0         if ( $third_line[8] !~ /^c[0123456789]+$/ ) {
286 0           $self->{usable} = 0;
287 0           return 0;
288             }
289             }
290             else {
291             # no third line showing any devices
292 0           $self->{usable} = 0;
293 0           return 0;
294             }
295              
296             # if we get here, it is most likely good
297 0           $self->{usable} = 1;
298 0           return 1;
299             }
300              
301             =head1 AUTHOR
302              
303             Zane C. Bowers-Hadley, C<< >>
304              
305             =head1 BUGS
306              
307             Please report any bugs or feature requests to C, or through
308             the web interface at L. I will be
309             notified, and then you'll automatically be notified of progress on your bug as I make changes.
310              
311             =head1 SUPPORT
312              
313             You can find documentation for this module with the perldoc command.
314              
315             perldoc Device::RAID::Poller
316              
317              
318             You can also look for information at:
319              
320             =over 4
321              
322             =item * RT: CPAN's request tracker (report bugs here)
323              
324             L
325              
326             =item * AnnoCPAN: Annotated CPAN documentation
327              
328             L
329              
330             =item * CPAN Ratings
331              
332             L
333              
334             =item * Search CPAN
335              
336             L
337              
338             =back
339              
340              
341             =head1 ACKNOWLEDGEMENTS
342              
343              
344             =head1 LICENSE AND COPYRIGHT
345              
346             This software is Copyright (c) 2019 by Zane C. Bowers-Hadley.
347              
348             This is free software, licensed under:
349              
350             The Artistic License 2.0 (GPL Compatible)
351              
352              
353             =cut
354              
355             1; # End of Device::RAID::Poller