File Coverage

blib/lib/AIX/LVM.pm
Criterion Covered Total %
statement 21 178 11.8
branch 0 86 0.0
condition n/a
subroutine 7 25 28.0
pod 9 12 75.0
total 37 301 12.2


line stmt bran cond sub pod time code
1             package AIX::LVM;
2 1     1   22743 use strict;
  1         2  
  1         33  
3 1     1   4 use warnings;
  1         2  
  1         24  
4 1     1   5 use Carp;
  1         5  
  1         90  
5 1     1   865 use IPC::Open3;
  1         4889  
  1         56  
6 1     1   198928 use IO::Select;
  1         1989  
  1         56  
7 1     1   1501 use IO::Handle;
  1         8856  
  1         45  
8              
9              
10 1     1   7 use vars qw( @ISA $VERSION);
  1         1  
  1         2246  
11             our $VERSION = '1.1';
12              
13             my @lslv_prop = (
14             "LOGICAL VOLUME:",
15             "VOLUME GROUP:",
16             "LV IDENTIFIER:",
17             "PERMISSION:",
18             "VG STATE:",
19             "LV STATE:",
20             "TYPE:",
21             "WRITE VERIFY:",
22             "MAX LPs:",
23             "PP SIZE:",
24             "COPIES:",
25             "SCHED POLICY:",
26             "LPs:",
27             "PPs:",
28             "STALE PPs:",
29             "BB POLICY:",
30             "INTER-POLICY:",
31             "RELOCATABLE:",
32             "INTRA-POLICY:",
33             "UPPER BOUND:",
34             "MOUNT POINT:",
35             "LABEL:",
36             "MIRROR WRITE CONSISTENCY:",
37             "EACH LP COPY ON A SEPARATE PV ?:",
38             "Serialize IO ?:"
39             );
40              
41             my @lsvg_prop = (
42             "VOLUME GROUP:",
43             "VG IDENTIFIER:",
44             "VG PERMISSION:",
45             "VG STATE:",
46             "PP SIZE:",
47             "TOTAL PPs:",
48             "MAX LVs:",
49             "FREE PPs:",
50             "USED PPs:",
51             "OPEN LVs:",
52             "QUORUM:",
53             "TOTAL PVs:",
54             "STALE PVs:",
55             "STALE PPs:",
56             "ACTIVE PVs:",
57             "AUTO ON:",
58             "MAX PPs per VG:",
59             "MAX PPs per PV:",
60             "MAX PVs:",
61             "LTG size (Dynamic):",
62             "AUTO SYNC:",
63             "HOT SPARE:",
64             "BB POLICY:",
65             "PV RESTRICTION:",
66             "VG DESCRIPTORS:",
67             "LVs:"
68             );
69              
70              
71             my @lspv_prop = (
72             "PHYSICAL VOLUME:",
73             "VOLUME GROUP:",
74             "PV IDENTIFIER:",
75             "VG IDENTIFIER",
76             "PV STATE:",
77             "STALE PARTITIONS:",
78             "ALLOCATABLE:",
79             "PP SIZE:",
80             "LOGICAL VOLUMES:",
81             "TOTAL PPs:",
82             "VG DESCRIPTORS:",
83             "FREE PPs:",
84             "HOT SPARE:",
85             "USED PPs:",
86             "MAX REQUEST:",
87             "FREE DISTRIBUTION:",
88             "USED DISTRIBUTION:",
89             "MIRROR POOL:"
90             );
91              
92              
93             sub new
94             {
95 0     0 0   my $class = shift;
96 0           my $self = {};
97 0           bless $self, $class;
98 0           return $self->init(@_);
99             }
100              
101              
102             sub init
103             {
104 0     0 0   my $self = shift;
105 0           my ($result, %lslv, %lspv, %lsvg, @lslv, @lsvg, @lspv);
106 0           my ($lsvg, $lsvg_error) = $self->_exec_open3("lsvg -o");
107 0 0         croak "Error found during execution of lsvg -o: $lsvg_error\n" if $lsvg_error;
108 0           @lsvg = $self->_splitter($lsvg, qr'\n+');
109 0           foreach my $lvg (@lsvg) {
110 0           $self->{$lvg}= $self->_get_lv_pv_props($lvg); #Hierarchy is lsvg -> lslv and lspv
111             }
112 0           return $self;
113             }
114              
115              
116             sub get_logical_volume_group
117             {
118 0     0 1   my $self = shift;
119 0           return sort keys %{$self};
  0            
120             }
121              
122              
123             sub get_logical_volumes
124             {
125 0     0 1   my $self = shift;
126 0           return map {keys %{$self->{$_}->{lvol}}}keys %{$self};
  0            
  0            
  0            
127             }
128              
129              
130             sub get_physical_volumes
131             {
132 0     0 1   my $self = shift;
133 0           return map {keys %{$self->{$_}->{pvol}}}keys %{$self};
  0            
  0            
  0            
134             }
135              
136              
137             sub get_volume_group_properties
138             {
139 0     0 1   my $self = shift;
140 0           my $vg = shift;
141 0 0         croak "Pass values for Volume Group\n" unless $vg;
142 0 0         exists $self->{$vg}->{prop}? %{$self->{$vg}->{prop}}:undef;
  0            
143             }
144              
145              
146             sub get_logical_volume_properties
147             {
148 0     0 1   my $self = shift;
149 0           my ($vg, $lv) = (shift, shift);
150 0 0         croak "Pass values for Volume Group\n" unless $vg;
151 0 0         croak "Pass values for Logical Volume Group\n" unless $lv;
152 0 0         exists $self->{$vg}->{lvol}->{$lv}->{prop}? %{$self->{$vg}->{lvol}->{$lv}->{prop}} : undef;
  0            
153             }
154              
155              
156             sub get_physical_volume_properties
157             {
158 0     0 1   my $self = shift;
159 0           my ($vg, $pv) = (shift, shift);
160 0 0         croak "Pass values for Volume Group\n" unless $vg;
161 0 0         croak "Pass values for Physical Volume Group\n" unless $pv;
162 0 0         exists $self->{$vg}->{pvol}->{$pv}->{prop}? %{$self->{$vg}->{pvol}->{$pv}->{prop}} : undef;
  0            
163             }
164              
165              
166             sub get_PV_PP_command
167             {
168 0     0 1   my $self = shift;
169 0           my ($vg, $pv) = (shift, shift);
170 0 0         croak "Pass values for Volume Group\n" unless $vg;
171 0 0         croak "Pass values for Physical Volume Group\n" unless $pv;
172 0 0         exists $self->{$vg}->{pvol}->{$pv}->{PV_PP_CMD_OUT}? $self->{$vg}->{pvol}->{$pv}->{PV_PP_CMD_OUT} : undef;
173             }
174              
175              
176             sub get_PV_LV_command
177             {
178 0     0 1   my $self = shift;
179 0           my ($vg, $pv) = (shift, shift);
180 0 0         croak "Pass values for Volume Group\n" unless $vg;
181 0 0         croak "Pass values for Physical Volume Group\n" unless $pv;
182 0 0         exists $self->{$vg}->{pvol}->{$pv}->{PV_LV_CMD_OUT}? $self->{$vg}->{pvol}->{$pv}->{PV_LV_CMD_OUT} : undef;
183             }
184              
185              
186             sub get_LV_logical_command
187             {
188 0     0 1   my $self = shift;
189 0           my ($vg, $lv) = (shift, shift);
190 0 0         croak "Pass values for Volume Group\n" unless $vg;
191 0 0         croak "Pass values for Logical Volume Group\n" unless $lv;
192 0 0         exists $self->{$vg}->{lvol}->{$lv}->{LV_LOGICAL_CMD_OUT}? $self->{$vg}->{lvol}->{$lv}->{LV_LOGICAL_CMD_OUT} : undef;
193             }
194              
195              
196             sub get_LV_M_command
197             {
198 0     0 0   my $self = shift;
199 0           my ($vg, $lv) = (shift, shift);
200 0 0         croak "Pass values for Volume Group\n" unless $vg;
201 0 0         croak "Pass values for Logical Volume Group\n" unless $lv;
202 0 0         exists $self->{$vg}->{lvol}->{$lv}->{LV_MIRROR_CMD_OUT}? $self->{$vg}->{lvol}->{$lv}->{LV_MIRROR_CMD_OUT} : undef;
203             }
204              
205              
206             #### Private methods ####
207              
208             # This subroutine is used to populate LV Values, PV Values and Properties of Volume Groups
209              
210             sub _get_lv_pv_props
211             {
212 0     0     my $self = shift;
213 0           my $lvg = shift;
214 0 0         croak "Logical volume group is not found\n" unless $lvg;
215 0           my (@lv, @pv, %lvg_hash);
216 0           my ($lslv, $lslv_error) = $self->_exec_open3("lsvg -l $lvg"); # Populate LV Values
217 0 0         croak "Error found during execution of lsvg -l $lvg: $lslv_error\n" if $lslv_error;
218 0           my @lslv = $self->_splitter($lslv, qr'\n+');
219 0           foreach my $lslv_l (@lslv[2..$#lslv]) {
220 0 0         push @lv, $1 if ($lslv_l=~/^(\S+)/);
221             }
222 0           foreach my $lv (@lv) {
223 0           $lvg_hash{lvol}->{$lv}= $self->_get_lslv_l_m_prop($lv);
224             }
225 0           my ($lspv, $lspv_error) = $self->_exec_open3("lsvg -p $lvg"); # Populate PV Values
226 0 0         croak "Error found during execution of lsvg -p $lvg: $lspv_error\n" if $lspv_error;
227 0           my @lspv = $self->_splitter($lspv, qr'\n+');
228 0           foreach my $lspv_l (@lspv[2..$#lspv]) {
229 0 0         push @pv, $1 if ($lspv_l=~/^(\S+)/);
230             }
231 0           foreach my $pv (@pv) {
232 0           $lvg_hash{pvol}->{$pv}= $self->_get_lspv_l_m_prop($pv);
233             }
234 0           my ($prop, $prop_error) = $self->_exec_open3("lsvg $lvg"); # Populate Properties
235 0 0         croak "Error found during execution of lsvg $lvg: $prop_error\n" if $prop_error;
236 0           $lvg_hash{prop} = $self->_parse_properties($prop, @lsvg_prop);
237 0           return \%lvg_hash;
238             }
239              
240             # This subroutine is used to populate LV Logical Values, LV Physical Values and Properties of Logical Volumes
241              
242             sub _get_lslv_l_m_prop
243             {
244 0     0     my $self = shift;
245 0           my $lv = shift;
246 0 0         croak "Logical volume is not found\n" unless $lv;
247 0           my (@lv, @pv, %lslv);
248 0           my ($lslv, $lslv_error) = $self->_exec_open3("lslv -l $lv"); # Populate LV Logical Values
249 0 0         croak "Error found during execution of lslv -l $lv: $lslv_error\n" if $lslv_error;
250 0           $lslv{"LV_LOGICAL_CMD_OUT"} = $lslv;
251 0           my ($lspv, $lspv_error) = $self->_exec_open3("lslv -m $lv"); # Populate LV Mirror Values
252 0 0         croak "Error found during execution of lslv -m $lv: $lspv_error\n" if $lspv_error;
253 0           $lslv{"LV_MIRROR_CMD_OUT"} = $lspv;
254 0           my ($prop, $prop_error) = $self->_exec_open3("lslv $lv"); # Populate LV Properties
255 0 0         croak "Error found during execution of lslv $lv: $prop_error\n" if $prop_error;
256 0           $lslv{prop} = $self->_parse_properties($prop, @lslv_prop);
257 0           return \%lslv;
258             }
259              
260             # # This subroutine is used to populate PV Logical Values, PV PP Values and Properties of Physical Volumes
261              
262             sub _get_lspv_l_m_prop
263             {
264 0     0     my $self = shift;
265 0           my $pv = shift;
266 0 0         croak "Physical volume is not found\n" unless $pv;
267 0           my (@lv, @pv, %lspv);
268 0           my ($lslv, $lslv_error) = $self->_exec_open3("lspv -l $pv"); # Populate PV Logical Values
269 0 0         croak "Error found during execution of lspv -l $pv: $lslv_error\n" if $lslv_error;
270 0           $lspv{"PV_LOGICAL_CMD_OUT"} = $lslv;
271 0           my ($lspv, $lspv_error) = $self->_exec_open3("lspv -M $pv"); # Populate PV in LV Values
272 0 0         croak "Error found during execution of lspv -M $pv: $lspv_error\n" if $lspv_error;
273 0           $lspv{"PV_LV_CMD_OUT"} = $lspv;
274 0           my ($lspp, $lspp_error) = $self->_exec_open3("lspv -p $pv"); # Populate PV Physical Partitions Values
275 0 0         croak "Error found during execution of lspv -p $pv: $lspp_error\n" if $lspp_error;
276 0           $lspv{"PV_PP_CMD_OUT"} = $lspp;
277 0           my ($prop, $prop_error) = $self->_exec_open3("lspv $pv"); # Populate PV Properties
278 0 0         croak "Error found during execution of lspv $pv: $prop_error\n" if $prop_error;
279 0           $lspv{prop} = $self->_parse_properties($prop, @lspv_prop);
280 0           return \%lspv;
281             }
282              
283             # This subroutine performs parsing the output of the commands for passed array values.
284              
285             sub _parse_properties
286             {
287 0     0     my $self = shift;
288 0           my $prop = shift;
289 0           my @defp = @_;
290 0           my %prop;
291 0           foreach my $defp (@defp) {
292 0           my $str = join '|', grep {"$_" ne $defp} @defp;
  0            
293 0 0         if ($prop=~/\Q$defp\E([^\n]*?)($str|\n|$)/s) {
294 0           my $value = $1;
295 0           $value =~s/^\s+|\s+$//g;
296 0           $prop{$defp} = $value;
297             } else {
298 0           carp "Property $defp not have value. Probably due to inconsistent identifier output\n";
299             }
300             }
301 0           return \%prop;
302             }
303              
304             # This subroutine is used to execute the commands using open3 to capture Error stream.
305              
306             sub _exec_open3
307             {
308 0     0     my $self = shift;
309 0           my ($result, $error);
310 0           my $writer_h = new IO::Handle;
311 0           my $reader_h = new IO::Handle;
312 0           my $error_h = new IO::Handle;
313 0 0         my $pid = open3($writer_h, $reader_h, $error_h, @_) or croak "Not able to open3: $! \n";
314 0           $reader_h->autoflush();
315 0           $error_h->autoflush();
316 0           my $selector = IO::Select->new();
317 0           $selector->add($reader_h, $error_h); ## Add the handlers to select call ##
318 0           while( my @ready = $selector->can_read ){
319 0           foreach my $fh ( @ready ){
320 0 0         if( fileno($fh) == fileno($reader_h) ){
321 0           my $ret = $reader_h->sysread($_, 1024);
322 0           $result .= $_;
323 0 0         $selector->remove($fh) unless $ret;
324             }
325 0 0         if( fileno($fh) == fileno($error_h) ){
326 0           my $ret = $error_h->sysread($_, 1024);
327 0           $error .= $_;
328 0 0         $selector->remove($fh) unless $ret;
329             }
330             }
331             }
332 0           $reader_h->autoflush();
333 0           $error_h->autoflush();
334 0           waitpid $pid, 0;
335 0           my $rc = $? >> 8;
336 0 0         carp "Error in executing the command\n" if ($rc);
337 0           return $result, $error;
338             }
339              
340             # Splitter based on pattern
341              
342             sub _splitter
343             {
344 0     0     my $self = shift;
345 0           my ($string, $pat) = (shift, shift);
346 0           return split /$pat/, $string;
347             }
348              
349              
350             __END__