File Coverage

blib/lib/Net/Brcd.pm
Criterion Covered Total %
statement 27 291 9.2
branch 0 122 0.0
condition 0 38 0.0
subroutine 9 35 25.7
pod 22 24 91.6
total 58 510 11.3


line stmt bran cond sub pod time code
1             #!/usr/local/bin/perl
2             # @(#)Brcd.pm 1.5
3              
4             package Net::Brcd;
5              
6 1     1   16 use 5.008;
  1         3  
  1         35  
7 1     1   5 use Carp;
  1         1  
  1         50  
8 1     1   4 use Data::Dumper;
  1         2  
  1         34  
9 1     1   4 use Socket;
  1         2  
  1         556  
10              
11 1     1   4 use strict;
  1         2  
  1         26  
12 1     1   15 use constant DEBUG => 0;
  1         2  
  1         39  
13              
14 1     1   5 use base qw(Exporter);
  1         7  
  1         2757  
15              
16             # Variables de gestion du package
17             our $VERSION = 1.13;
18              
19             # Variables privées
20             my $_brcd_wwn_re = join(":",("[0-9A-Za-z][0-9A-Za-z]") x 8);
21             my $_brcd_port_id = qr/\d+,\d+/;
22              
23             sub new {
24 0     0 1   my ($class)=shift;
25              
26 0   0       $class = ref($class) || $class;
27 0           my $self = {};
28              
29 0           bless $self, $class;
30 0           return $self;
31             }
32              
33             sub connect {
34 0     0 1   my ($self,$switch,$user,$pass)=@_;
35              
36 0   0       $user ||= $ENV{BRCD_USER} || 'admin';
      0        
37 0   0       $pass ||= $ENV{BRCD_PASS};
38 0   0       $switch ||= $ENV{BRCD_SWITCH};
39              
40 0 0         unless ($switch) {
41 0           croak __PACKAGE__,": Need switch \@IP or name.\n";
42             }
43 0 0 0       unless ($user and $pass) {
44 0           croak __PACKAGE__,": Need user or password.\n";
45             }
46 0           $self->{FABRICS}->{$switch} = {};
47 0           $self->{FABRIC} = $switch;
48 0           $self->{USER} = $user;
49              
50 0           return $self->proto_connect($switch,$user,$pass);
51             }
52              
53             sub proto_connect {
54 0     0 0   my ($self,$switch,$user,$pass) = @_;
55            
56 0           croak __PACKAGE__, "Error - proto_connect is a virtual function.\n";
57             }
58              
59             sub cmd {
60 0     0 1   my ($self, $cmd, @cmd)=@_;
61              
62 0           croak __PACKAGE__, "Error - cmd is a virtual function.\n";
63             }
64              
65             sub sendcmd {
66 0     0 1   my ($self, $cmd, @cmd)=@_;
67              
68 0           croak __PACKAGE__, "Error - sendcmd is a virtual function.\n";
69             }
70              
71             sub sendeof {
72 0     0 1   my ($self, $cmd, @cmd)=@_;
73              
74 0           croak __PACKAGE__, "Error - sendeof is a virtual function.\n";
75             }
76              
77             sub readline {
78 0     0 1   my ($self, $arg_ref) = @_;
79            
80 0           croak __PACKAGE__, "Error - readline is a virtual function.\n";
81             }
82              
83             sub cfgSave {
84 0     0 1   my $self = shift;
85 0           my %args = (
86             -verbose => 0,
87             @_,
88             );
89 0           my @rc = $self->cmd('cfgSave');
90            
91 0           my $rc = '';
92 0           SWITCH: {
93 0           DEBUG && warn "DEBUG:cfgsave", Dumper(\@rc);
94 0 0         unless (@rc) {
95 0           last SWITCH;
96             }
97 0 0         if ($args{-verbose}) {
98 0           warn join("\n", @rc), "\n";
99             }
100 0           $rc = pop @rc;
101 0 0         return 1 if ($rc =~ m/Nothing/i); # Pas de modif
102 0 0         return 1 if ($rc =~ m/Updating/i); # Update fait
103             }
104            
105 0           croak "Error - Cannot save current configuration: $rc.\n";
106             }
107              
108             sub aliShow {
109 0     0 1   my $self=shift;
110              
111 0           my %args=(
112             -bywwn => 0,
113             -byport => 0,
114             -cache => 0,
115             -onlywwn => 1,
116             -filter => '*',
117             @_
118             );
119              
120 0           my $fab_name = $self->{FABRIC};
121 0           my $fab = $self->{FABRICS}->{$fab_name};
122 0 0         $args{-onlywwn} = 0 if $args{-byport};
123              
124 0           my ($alias);
125 0           $fab->{PORTID} = {};
126 0           $fab->{WWN} = {};
127 0           $fab->{ALIAS} = {};
128 0           foreach ($self->cmd('aliShow "' . $args{-filter} . '"')) {
129 0 0         next unless $_;
130 0 0         if (m/alias:\s+(\w+)/) {
131 0           $alias=$1;
132 0           next;
133             }
134 0 0 0       if ($alias && m/${_brcd_wwn_re}/) {
135 0           s/^\s*//; # on enleve les blancs de devant
136 0           DEBUG && warn "DEBUG: aliShow: $alias: $_\n";
137 0           my @wwn_for_alias = split m/\s*;\s*/;
138 0           foreach my $wwn (@wwn_for_alias) {
139 0           $fab->{WWN}->{$wwn} = $alias;
140             }
141 0 0         if (exists $fab->{ALIAS}->{$alias}) {
142 0           my $old_alias_value = $fab->{ALIAS}->{$alias};
143 0 0         unless (ref $old_alias_value) {
144 0           $fab->{ALIAS}->{$alias} = [$old_alias_value];
145             }
146 0           push @{$fab->{ALIAS}->{$alias}}, @wwn_for_alias;
  0            
147             } else {
148 0 0         $fab->{ALIAS}->{$alias} = (@wwn_for_alias == 1) ? $wwn_for_alias[0]
149             : \@wwn_for_alias;
150             }
151            
152 0           next;
153             }
154            
155 0 0         next if $args{-onlywwn};
156            
157 0 0 0       if ($alias && m/(${_brcd_port_id})/) {
158 0           my $port_id = $1;
159 0           $fab->{PORTID}->{$port_id} = $alias;
160 0           $fab->{ALIAS}->{$alias} = $port_id;
161 0           next;
162             }
163             }
164             #}
165 0           DEBUG && warn "DEBUG:zone.?:", Dumper($fab);
166              
167 0           return ($args{'-bywwn'}) ? (%{$fab->{WWN}}) :
  0            
168 0           ($args{'-byport'}) ? (%{$fab->{PORTID}}) :
169 0 0         (%{$fab->{ALIAS}});
    0          
170             }
171              
172             sub zoneShow {
173 0     0 1   my $self = shift;
174              
175 0           my %args = (
176             -bymember => 0,
177             -cache => 0,
178             -filter => '*',
179             @_
180             );
181              
182 0           my $fab_name = $self->{FABRIC};
183 0           my $fab = $self->{FABRICS}->{$fab_name};
184              
185 0           my ($zone);
186 0           foreach ($self->cmd('zoneShow "' . $args{-filter} . '"')) {
187 0           DEBUG && warn "DEBUG:CMDDUMP: $_\n";
188 0 0         if (m/zone:\s+(\w+)/) {
189 0           $zone = $1;
190 0           next;
191             }
192 0 0 0       if ($zone && m/\s*(\w[:\w\s;]+)/) {
193 0           my $members = $1;
194 0           my @member = split m/;\s+/, $members;
195              
196 0           foreach my $member (@member) {
197 0           $fab->{ZONE}->{$zone}->{$member}++;
198 0           $fab->{MEMBER}->{$member}->{$zone}++;
199             }
200             }
201             }
202            
203 0 0 0       unless ($fab->{MEMBER} and $fab->{ZONE}) {
204 0           croak "Warning - Empty zone.\n";
205             }
206              
207 0 0         if (wantarray()) {
208 0 0         return ($args{'-bymember'})?(%{$fab->{MEMBER}}):(%{$fab->{ZONE}});
  0            
  0            
209             }
210             }
211              
212             sub zoneMember {
213 0     0 1   my ($self, $zone)=@_;
214              
215 0           my $fab_name = $self->{FABRIC};
216 0           my $fab = $self->{FABRICS}->{$fab_name};
217              
218 0 0         return unless exists $fab->{ZONE}->{$zone};
219              
220 0           return sort keys %{$fab->{ZONE}->{$zone}};
  0            
221             }
222              
223             sub memberZone {
224 0     0 1   my ($self,$member)=@_;
225              
226 0           my $fab_name = $self->{FABRIC};
227 0           my $fab = $self->{FABRICS}->{$fab_name};
228              
229 0 0         return unless exists $fab->{MEMBER}->{$member};
230              
231 0           return sort keys %{$fab->{MEMBER}->{$member}};
  0            
232             }
233              
234             sub switchShow {
235 0     0 1   my $self=shift;
236              
237 0           my %args=(
238             -bywwn => 0,
239             -withportname => 0,
240             -byslot => 0,
241             @_
242             );
243              
244 0           my $fab_name = $self->{FABRIC};
245 0           my $fab = $self->{FABRICS}->{$fab_name};
246              
247 0           my (%wwn);
248 0           foreach ($self->cmd("switchShow")) {
249 0 0         next unless $_;
250 0           DEBUG && warn "SWITCHSHOW : $_\n";
251 0 0         if (m/^(\w+):\s+(.+)/) {
252 0           $fab->{$1} = $2;
253 0           next;
254             }
255             #12000 : 0 1 0 id 2G Online E-Port (Trunk port, master is Slot 1 Port
256             #48000 : 13 1 13 0a0d00 id N2 Online F-Port 10:00:00:00:c9:35:99:4b
257             #48000 : 12 1 12 0a0c00 id N4 No_Light
258             #4100 : 0 0 id 2G Online E-Port 10:00:00:05:1e:35:f6:e5 "PS4100A"
259             #5100 : 0 0 010000 id N4 Online FC F-Port 50:0a:09:81:98:4c:a8:9d
260             #5100 : 1 1 010100 id N4 No_Light FC
261             #3800 : port 0: id 2G Online F-Port 50:06:01:60:10:60:04:26
262            
263 0 0         if (m{
264             ^[port\s]*(\d+):? \s* # Le port number forme ok:port 1: ; 12;144
265             (?:
266             (?:
267             (\d{1,3})\s+ # Le slot que sur les directeurs
268             )?
269             (\d{1,3}) # Le port dans le slot
270             \s*
271             (
272             [0-9a-zA-Z]
273             [0-9a-zA-Z]
274             [0-9a-zA-Z]
275             [0-9a-zA-Z]
276             [0-9a-zA-Z]
277             [0-9a-zA-Z]
278             )? # Adresse FC, qu'à partir de FabOS 5.2.0a
279             )?
280             \s+ [i-][d-] \s+ # Le mot magique qui dit que c'est la bonne ligne
281             [a-zA-Z]*(\d+)[a-zA-Z]* \s+ # Vitesse du port plusieurs format à priori toujours en Go/s
282             (\w+) \s* # Status du port
283             (.*) # Toutes les autres informations (notamment le WWN si connectés)
284             }mxs) {
285 0           DEBUG && warn "SWITCHSHOW-RE: #$1# #$2# #$3# #$4# #$5# #$6# #$7#\n";
286             # Récupération des champs, les champs dans les même ordre que les $
287 0           my @fields = qw(SLOT NUMBER ADDRESS SPEED STATUS INFO);
288 0           my $port_number = $1;
289 0           my $port_info = $7;
290 0           foreach my $re ($2, $3, $4, $5, $6, $7) {
291 0           my $field = shift @fields;
292 0 0         if (defined $re) {
293 0           $fab->{PORT}->{$port_number}->{$field} = $re;
294             }
295             }
296 0 0         $fab->{PORT}->{$port_number}->{PORTNAME} = $self->portShow($port_number) if $args{-withportname};
297             $fab->{SLOTN}->{
298 0 0         (($fab->{PORT}->{$port_number}->{SLOT}) ? $fab->{PORT}->{$port_number}->{SLOT} . '/'
299             : "")
300             . $fab->{PORT}->{$port_number}->{NUMBER}
301             }->{PORT} = $port_number;
302              
303 0 0 0       if ($port_info and $port_info =~ m/^(\w-\w+)\s+(${_brcd_wwn_re})?/) {
304 0           my ($type, $wwn) = ($1,$2);
305 0           $fab->{PORT}->{$port_number}->{TYPE} = $type;
306 0 0         $fab->{PORT}->{$port_number}->{WWN} = $wwn if $wwn;
307            
308              
309 0 0         if ($type eq "F-Port") {
310 0           $wwn{$wwn} = $port_number;
311             }
312             }
313             } else {
314 0           DEBUG && warn "DEBUG:???? >>$_<<\n";
315             }
316             }
317              
318 0           return ($args{'-bywwn'}) ? %wwn
319 0           : ($args{'-byslot'}) ? %{$fab->{SLOTN}}
320 0 0         : (exists $fab->{PORT}) ? %{$fab->{PORT}}
    0          
    0          
321             : undef;
322             }
323              
324             sub toSlot {
325 0     0 1   my $self = shift;
326 0           my $port_number = shift;
327            
328 0           my $fab_name = $self->{FABRIC};
329 0           my $fab = $self->{FABRICS}->{$fab_name};
330              
331 0           DEBUG && warn "TOSLOT: $port_number\n";
332            
333 0 0         unless (exists $fab->{PORT}->{$port_number}) {
334 0           $@ = __PACKAGE__.":toSlot: port number $port_number does not exist\n";
335            
336 0           DEBUG && warn "$@\n";
337              
338 0           return;
339             }
340 0 0         unless (exists $fab->{PORT}->{$port_number}->{SLOT}) {
341            
342 0           $@ = __PACKAGE__.":toSlot: port number $port_number is not a director\n";
343 0           DEBUG && warn "$@\n";
344              
345 0           return;
346             }
347            
348 0           DEBUG && warn "TOSLOT: ",$fab->{PORT}->{$port_number}->{SLOT}."/".$fab->{PORT}->{$port_number}->{NUMBER},"\n";
349              
350 0 0         return (wantarray())?($fab->{PORT}->{$port_number}->{SLOT},$fab->{PORT}->{$port_number}->{NUMBER}):
351             $fab->{PORT}->{$port_number}->{SLOT}."/".$fab->{PORT}->{$port_number}->{NUMBER};
352             }
353              
354             sub portShow {
355 0     0 1   my $self = shift;
356 0           my $port_number = shift;
357              
358 0           my $fab_name = $self->{FABRIC};
359 0           my $fab = $self->{FABRICS}->{$fab_name};
360            
361 0           DEBUG && warn "PORTSHOW-PORTNUMBER:test: $port_number\n";
362 0   0       $port_number = $self->toSlot($port_number) || $port_number;
363 0           DEBUG && warn "PORTSHOW-PORTNUMBER:set: $port_number\n";
364 0           my (%port, $param, $value, $portname);
365            
366 1     1   8 no warnings;
  1         2  
  1         2581  
367 0           foreach ($self->cmd("portShow $port_number")) {
368 0           DEBUG && warn "PORTSHOW:parse: $_\n";
369              
370 0 0         if (m/^([\w\s]+):\s+(.+)/) {
371 0           $param = $1;
372 0           $value = $2;
373            
374 0           DEBUG && warn "PORTSHOW: param #$param# value #$value#\n";
375            
376 0           $port{$param} = $value;
377             SWITCH: {
378 0 0         if ($param eq 'portName') {
  0            
379 0           $fab->{SLOTN}->{$port_number}->{PORTNAME} = $value;
380 0           $portname = $value;
381 0           last SWITCH;
382             }
383             }
384 0           next;
385             }
386            
387 0 0         if (m/^([\w\s]+):\s*$/) {
388 0           $param = $1;
389 0           next;
390             }
391            
392 0 0         if (m/^\s+(.+)/) {
393 0           $port{$param} = $1;
394 0           next;
395             }
396             }
397 1     1   13 use warnings;
  1         2  
  1         1342  
398              
399 0 0         return (wantarray())?(%port):($portname);
400             }
401              
402             sub output {
403 0     0 1   my $self=shift;
404              
405 0           return join("\n",@{$self->{OUTPUT}})."\n";
  0            
406             }
407              
408             sub wwn_re {
409 0     0 1   return ${_brcd_wwn_re};
410             }
411              
412             sub fabricShow {
413 0     0 1   my $self=shift;
414 0           my %args=(
415             -bydomain => 0,
416             @_
417             );
418 0           my (%fabric,%domain);
419            
420 0           foreach ($self->cmd('fabricShow')) {
421 0 0         next unless $_;
422 0           DEBUG && warn "DEBUG:: $_\n";
423 0 0         if (m{
424             ^\s* (\d+) : \s+ \w+ \s+ # Domain id + identifiant FC
425             ${_brcd_wwn_re} \s+ # WWN switch
426             (\d+\.\d+\.\d+\.\d+) \s+ # Adresse IP switch
427             \d+\.\d+\.\d+\.\d+ \s+ # Adresse IP FC switch (FCIP)
428             (>?)"([^"]+) # Master, nom du switch
429             }msx) {
430 0           my ($domain_id, $switch_ip, $switch_master, $switch_name) = ($1, $2, $3, $4);
431 0           my $switch_host = gethostbyaddr(inet_aton($switch_ip), AF_INET);
432 0           my @fields = qw(DOMAIN IP MASTER FABRIC NAME MASTER);
433 0           foreach my $re ($domain_id, $switch_ip, $switch_master, $switch_host, $switch_name) {
434 0           my $field = shift @fields;
435 0 0         if ($re) {
436 0           $domain{$domain_id}->{$field} = $re;
437 0           $fabric{$switch_name}->{$field} = $re;
438             }
439             }
440            
441 0 0         $fabric{$switch_host} = $switch_name if $switch_host;
442             }
443             }
444            
445 0 0         return ($args{-bydomain}) ? (%domain) :
446             (%fabric);
447             }
448              
449             sub currentFabric {
450 0     0 1   my $self = shift;
451            
452 0           return $self->{FABRIC};
453             }
454              
455              
456             sub isWwn {
457 0     0 1   my $self = shift;
458 0           my $wwn = shift;
459            
460 0 0         ($wwn =~ m/^${_brcd_wwn_re}/)?(return 1):(return);
461            
462             }
463              
464             sub portAlias {
465 0     0 1   my $self = shift;
466 0           my $port_alias = shift;
467            
468 0 0         if ($port_alias =~ m/(\d+),(\d+)/){
469 0           return ($1, $2);
470             }
471 0           return;
472             }
473              
474             sub rename {
475 0     0 0   my ($self, $old_zone_object, $new_zone_object) = @_;
476            
477 0 0 0       unless ($old_zone_object and $new_zone_object) {
478 0           croak "Error - Need old and new name.\n";
479             }
480            
481 0           return $self->cmd("zoneObjectRename $old_zone_object, $new_zone_object");
482             }
483              
484             sub _zoning_cmd {
485 0     0     my ($self, $cmd_name, $zone_object, @cmd_args) = @_;
486            
487 0 0         unless ($cmd_name) {
488 0           croak "Error - Need command name.\n";
489             }
490 0 0         unless ($zone_object) {
491 0           croak "Error - Need object name.\n";
492             }
493            
494 0           my $cmd = "$cmd_name $zone_object";
495 0           my $str_args;
496 0 0         if (@cmd_args == 1) {
    0          
497 0           $str_args = shift @cmd_args;
498 0 0         if (ref $str_args eq 'ARRAY') {
499 0           $str_args = join(';', @{$str_args});
  0            
500             }
501             } elsif (@cmd_args) {
502 0           $str_args = join(';', @{$str_args});
  0            
503             }
504 0 0         if ($str_args) {
505 0           $cmd .= ", \"$str_args\"";
506             }
507            
508 0           return $self->cmd($cmd);
509             }
510              
511             sub _build_cmd_name {
512 0     0     my ($prefix, $args_ref) = @_;
513            
514 0           my @exclude = (
515             '^-name',
516             '^-members',
517             );
518 0           my $action;
519 0           ARG_CMD: foreach my $arg (keys %{$args_ref}) {
  0            
520 0 0         next unless ($args_ref->{$arg});
521 0           foreach my $exclude (@exclude) {
522 0 0         if ($arg =~ m/$exclude/) {
523 0           next ARG_CMD;
524             }
525             }
526 0           $arg =~ s/^[-]*//;
527 0           $action = $arg;
528             }
529 0 0         unless ($action) {
530 0           croak "Error - cannot find action.\n";
531             }
532            
533 0           return $prefix . $action;
534             }
535              
536             sub zone {
537 0     0 1   my $self = shift;
538            
539 0           my %args = (
540             -create => 0,
541             -add => 0,
542             -delete => 0,
543             -remove => 0,
544             -name => "",
545             -members => "",
546             @_,
547             );
548 0           my $cmd_name = _build_cmd_name('zone', \%args);
549            
550 0           return $self->_zoning_cmd($cmd_name, $args{-name}, $args{-members});
551             }
552              
553             sub ali {
554 0     0 1   my $self = shift;
555            
556 0           my %args = (
557             -create => 0,
558             -add => 0,
559             -delete => 0,
560             -remove => 0,
561             -name => "",
562             -members => "",
563             @_,
564             );
565 0           my $cmd_name = _build_cmd_name('ali', \%args);
566            
567 0           DEBUG && warn "DEBUG:ALI:", Dumper($cmd_name, \%args);
568              
569 0           return $self->_zoning_cmd($cmd_name, $args{-name}, $args{-members});
570             }
571              
572              
573             1;
574              
575             __END__