File Coverage

blib/lib/BigIP/LTM/ParseConfig.pm
Criterion Covered Total %
statement 6 273 2.2
branch 0 144 0.0
condition 0 68 0.0
subroutine 2 43 4.6
pod 20 37 54.0
total 28 565 4.9


line stmt bran cond sub pod time code
1             package BigIP::LTM::ParseConfig;
2              
3 1     1   73509 use strict;
  1         2  
  1         28  
4 1     1   6 use warnings;
  1         2  
  1         3816  
5             #no warnings qw 'uninitialized';
6             our $VERSION = '0.8.3';
7              
8             # CURRENTLY UNDER DEVELOMENT BY WENWU YAN
9             #----------------------------------------------------------------------------
10             # The contents of this file are subject to the iControl Public License
11             # Version 4.5 (the "License"); you may not use this file except in
12             # compliance with the License. You may obtain a copy of the License at
13             # http://www.f5.com/.
14             #
15             # Software distributed under the License is distributed on an "AS IS"
16             # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17             # the License for the specific language governing rights and limitations
18             # under the License.
19             #
20             # The Original Code is iControl Code and related documentation
21             # distributed by F5.
22             #
23             # The Initial Developer of the Original Code is F5 Networks,
24             # Inc. Seattle, WA, USA. Portions created by F5 are Copyright (C) 1996-2020 F5 Networks,
25             # Inc. All Rights Reserved. iControl (TM) is a registered trademark of F5 Networks, Inc.
26             #
27             # Alternatively, the contents of this file may be used under the terms
28             # of the GNU General Public License (the "GPL"), in which case the
29             # provisions of GPL are applicable instead of those above. If you wish
30             # to allow use of your version of this file only under the terms of the
31             # GPL and not to allow others to use your version of this file under the
32             # License, indicate your decision by deleting the provisions above and
33             # replace them with the notice and other provisions required by the GPL.
34             # If you do not delete the provisions above, a recipient may use your
35             # version of this file under either the License or the GPL.
36             #----------------------------------------------------------------------------
37              
38             #----------------------------------------------------------------------------
39             # Initialize the module
40             #----------------------------------------------------------------------------
41             sub new {
42 0     0 1   my $class = shift;
43              
44 0           my $self = {};
45 0           bless $self, $class;
46              
47 0           $self->{'ConfigFile'} = shift;
48              
49 0           return $self;
50             }
51              
52             #----------------------------------------------------------------------------
53             # Return a list of objects for ltm
54             #----------------------------------------------------------------------------
55 0     0 1   sub virtuals { return shift->_objectlist('ltm virtual')}
56 0     0 1   sub pools { return shift->_objectlist('ltm pool') }
57 0     0 1   sub rules { return shift->_objectlist('ltm rule') }
58 0     0 1   sub nodes { return shift->_objectlist('ltm node') }
59 0     0 1   sub monitors { return shift->_objectlist('ltm monitor') }
60 0     0 1   sub profiles { return shift->_objectlist('ltm profile') }
61 0     0 0   sub persistences { return shift->_objectlist('ltm persistence') }
62              
63             #----------------------------------------------------------------------------
64             # Return a list of objects for net
65             #----------------------------------------------------------------------------
66 0     0 0   sub selfs { return shift->_objectlist('net self') }
67 0     0 0   sub vlans { return shift->_objectlist('net vlan') }
68 0     0 1   sub routes { return shift->_objectlist('net route') }
69 0     0 0   sub trunks { return shift->_objectlist('net trunk') }
70 0     0 0   sub interfaces { return shift->_objectlist('net interface') }
71              
72             #----------------------------------------------------------------------------
73             # Return a list of objects for others
74             #----------------------------------------------------------------------------
75 0     0 1   sub users { return shift->_objectlist('auth user') }
76              
77              
78             #----------------------------------------------------------------------------
79             # Return an object hash for ltm
80             #----------------------------------------------------------------------------
81 0     0 1   sub virtual { return shift->_object( 'ltm virtual', shift ) }
82 0     0 1   sub pool { return shift->_object( 'ltm pool', shift ) }
83 0     0 1   sub rule { return shift->_object( 'ltm rule', shift ) }
84 0     0 1   sub node { return shift->_object( 'ltm node', shift ) }
85 0     0 1   sub profile { return shift->_object( 'ltm profile', shift ) }
86 0     0 1   sub monitor { return shift->_object( 'ltm monitor', shift ) }
87 0     0 0   sub persistence { return shift->_object( 'ltm persistence', shift ) }
88              
89             # Return an object hash for net
90 0     0 0   sub self { return shift->_object( "net self", shift ); }
91 0     0 0   sub vlan { return shift->_object( "net vlan", shift ); }
92 0     0 0   sub trunk { return shift->_object( "net trunk", shift ); }
93 0     0 0   sub interface { return shift->_object( "net interface", shift ); }
94 0     0 1   sub route { return shift->_object( "net route", shift ); }
95              
96             # Return an object hash for sys
97 0     0 0   sub ntp { return shift->_object( "sys", "ntp" );}
98 0     0 0   sub sshd { return shift->_object( "sys", "sshd" ); }
99 0     0 0   sub snmp { return shift->_object( "sys", "snmp" ); }
100 0     0 0   sub syslog { return shift->_object( "sys", "syslog" ); }
101 0     0 0   sub state_mirror { return shift->_object( "sys", "state-mirroring" ); }
102              
103             # Return an object hash for others
104 0     0 1   sub user { return shift->_object( 'auth user', shift ); }
105              
106             #----------------------------------------------------------------------------
107             # Return a list of pool members
108             #----------------------------------------------------------------------------
109             sub members {
110 0     0 1   my $self = shift;
111 0           my $pool = shift;
112              
113 0   0       $self->{'Parsed'} ||= $self->_parse();
114              
115 0 0         return 0 unless $self->{'Parsed'}->{'ltm pool'}->{$pool}->{'members'};
116              
117 0 0         if ( ref $self->{'Parsed'}->{'ltm pool'}->{$pool}->{'members'} eq 'HASH' ) {
118 0           return keys %{$self->{'Parsed'}->{'pool'}->{$pool}->{'members'}};
  0            
119             }
120             else {
121 0           return $self->{'Parsed'}->{'ltm pool'}->{$pool}->{'members'};
122             }
123             }
124              
125             #----------------------------------------------------------------------------
126             # Return hashs of virtual servers
127             #----------------------------------------------------------------------------
128             sub virtuals_all {
129 0     0 0   my $self = shift;
130 0           my @virtuals = $self->virtuals();
131              
132 0           foreach (@virtuals) {
133 0           my $virtual = $self->virtual($_);
134 0 0         my $pool = $virtual->{pool} if exists $virtual->{pool};
135 0 0         my @persist = keys %{$virtual->{persist}} if exists $virtual->{persist} ;
  0            
136 0 0         $virtual->{"pool_details"} = $self->pool($pool) if $pool;
137 0 0         $virtual->{"persist_mode"} = $self->persistence($persist[0])->{"mode"} if $persist[0];
138             }
139              
140 0           return $self->{Parsed}{"ltm virtual"};
141             }
142              
143             #----------------------------------------------------------------------------
144             # Return details of virtual server
145             #----------------------------------------------------------------------------
146             sub virtual_detail {
147 0     0 0   my $self = shift;
148 0           my $server = shift;
149 0           my @virtuals = $self->virtuals();
150              
151 0           foreach (@virtuals) {
152 0           my $virtual = $self->virtual($_);
153 0 0         my $pool = $virtual->{pool} if exists $virtual->{pool};
154 0 0         my @persist = keys %{$virtual->{persist}} if exists $virtual->{persist};
  0            
155 0 0         $virtual->{"pool_details"} = $self->pool($pool) if $pool;
156 0 0         $virtual->{"persist_mode"} = $self->persistence($persist[0])->{"mode"} if $persist[0];
157             }
158              
159 0           return $self->{Parsed}{"ltm virtual"}{$server};
160             }
161              
162             # Modify an object
163             sub modify {
164 0     0 1   my $self = shift;
165 0           my ($arg);
166 0           %{$arg} = @_;
  0            
167              
168 0 0 0       return 0 unless $arg->{'type'} && $arg->{'key'};
169              
170 0           my $obj = $arg->{'type'};
171 0           my $key = $arg->{'key'};
172 0           delete $arg->{'type'};
173 0           delete $arg->{'key'};
174              
175 0   0       $self->{'Parsed'} ||= $self->_parse();
176              
177 0 0         return 0 unless $self->{'Parsed'}->{$obj}->{$key};
178              
179 0           foreach my $attr ( keys %{$arg} ) {
  0            
180 0 0         next unless $self->{'Parsed'}->{$obj}->{$key}->{$attr};
181 0           $self->{'Modify'}->{$obj}->{$key}->{$attr} = $arg->{$attr};
182             }
183              
184 0           return 1;
185             }
186              
187             # Write out a new configuration file
188             sub write {
189 0     0 1   my $self = shift;
190 0   0       my $file = shift || $self->{'ConfigFile'};
191              
192 0 0         die "No changes found; no write necessary" unless $self->{'Modify'};
193              
194 0           foreach my $obj (
195             qw( self partition route user monitor auth profile node pool rule virtual )
196             )
197             {
198 0           foreach my $key ( sort keys %{ $self->{'Parsed'}->{$obj} } ) {
  0            
199 0 0         if ( $self->{'Modify'}->{$obj}->{$key} ) {
200 0           $self->{'Output'} .= "$obj $key {\n";
201 0           foreach my $attr ( $self->_order($obj) ) {
202 0 0         next unless $self->{'Parsed'}->{$obj}->{$key}->{$attr};
203             $self->{'Modify'}->{$obj}->{$key}->{$attr}
204 0   0       ||= $self->{'Parsed'}->{$obj}->{$key}->{$attr};
205 0 0         if (ref $self->{'Modify'}->{$obj}->{$key}->{$attr} eq
206             'ARRAY' )
207             {
208 0 0         if ( @{ $self->{'Modify'}->{$obj}->{$key}->{$attr} }
  0            
209             > 1 )
210             {
211 0           $self->{'Output'} .= " $attr\n";
212 0           foreach my $val (
213 0           @{ $self->{'Modify'}->{$obj}->{$key}->{$attr}
214             }
215             )
216             {
217 0           $self->{'Output'} .= " $val\n";
218 0 0         if ( $self->{'Parsed'}->{$obj}->{$key}
219             ->{'_xtra'}->{$val} )
220             {
221             $self->{'Output'}
222             .= ' '
223             . $self->{'Parsed'}->{$obj}->{$key}
224 0           ->{'_xtra'}->{$val} . "\n";
225             }
226             }
227             }
228             else {
229             $self->{'Output'}
230             .= " $attr "
231             . $self->{'Modify'}->{$obj}->{$key}
232 0           ->{$attr}[0] . "\n";
233             }
234             }
235             else {
236             $self->{'Output'}
237             .= " $attr "
238 0           . $self->{'Modify'}->{$obj}->{$key}->{$attr}
239             . "\n";
240             }
241             }
242 0           $self->{'Output'} .= "}\n";
243             }
244             else {
245 0           $self->{'Output'} .= $self->{'Raw'}->{$obj}->{$key};
246             }
247             }
248             }
249              
250 0   0       open FILE, ">$file" || return 0;
251 0           print FILE $self->{'Output'};
252 0           close FILE;
253              
254 0           return 1;
255             }
256              
257             #----------------------------------------------------------------------------
258             # Return an object hash
259             #----------------------------------------------------------------------------
260             sub _object {
261 0     0     my $self = shift;
262 0           my $obj = shift;
263 0           my $var = shift;
264              
265 0   0       $self->{'Parsed'} ||= $self->_parse();
266              
267 0   0       return $self->{'Parsed'}->{$obj}->{$var} || 0;
268             }
269              
270             #----------------------------------------------------------------------------
271             # Return a list of objects
272             #----------------------------------------------------------------------------
273             sub _objectlist {
274 0     0     my $self = shift;
275 0           my $obj = shift;
276              
277 0   0       $self->{'Parsed'} ||= $self->_parse();
278              
279 0 0         if ( $self->{'Parsed'}->{$obj} ) {
280 0           return keys %{ $self->{'Parsed'}->{$obj} };
  0            
281             }
282             else {
283 0           return 0;
284             }
285             }
286              
287             #----------------------------------------------------------------------------
288             # Define object attribute ordering
289             #----------------------------------------------------------------------------
290             sub _order {
291 0     0     my $self = shift;
292              
293 0           for (shift) {
294 0 0         /auth/ && return qw( bind login search servers service ssl user );
295 0 0         /ltm monitor/
296             && return
297             qw( default base debug filter mandatoryattrs password security username interval timeout manual dest recv send );
298 0 0         /ltm node/ && return qw( monitor screen );
299 0 0         /partition/ && return qw( description );
300 0 0         /ltm pool/ && return qw( lb nat monitor members );
301 0 0         /net self/ && return qw( netmask unit floating vlan allow );
302 0 0         /auth user/ && return qw( password description id group home shell role );
303 0 0         /ltm virtual/
304             && return
305             qw( translate snat pool destination ip rules profiles persist );
306              
307 0           return 0;
308             }
309             }
310              
311             #----------------------------------------------------------------------------
312             # Parse the configuration file
313             #----------------------------------------------------------------------------
314             sub _parse {
315 0     0     my $self = shift;
316 0   0       my $file = shift || $self->{'ConfigFile'};
317              
318             die "File not found: $self->{'ConfigFile'}\n"
319 0 0         unless -e $self->{'ConfigFile'};
320              
321 0   0       open FILE, $file || return 0;
322 0           my @file = ;
323 0           close FILE;
324              
325 0           my ( $parsed, $obj, $key, $attr1, $attr2, $attr3 );
326              
327 0           until ( !$file[0] ) {
328 0           my $ln = shift @file;
329              
330             #user attribute
331 0 0         if ( $ln=~ /^(auth user)\s(.*)\s\{(\s\})?$/) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
332 0 0         next if $3;
333 0           $obj = $1;
334 0           $key = $2;
335             }
336             #ltm attribute
337             elsif ( $ln =~ /^(ltm virtual|ltm pool|ltm node|ltm rule)\s(.*)\s\{(\s\})?$/ ) {
338 0 0         next if $3;
339 0           $obj = $1;
340 0           $key = $2;
341             }
342             #net attribute
343             elsif ( $ln =~ /^(net self|net route|net interface|net vlan|net trunk)\s(.*)\s\{(\s\})?$/ ) {
344 0 0         next if $3;
345 0           $obj = $1;
346 0           $key = $2;
347             }
348             #sys attribute
349             elsif ($ln =~ /^(sys)\s(sshd|syslog|ntp|snmp|state-mirroring)\s\{(\s\})?$/) {
350 0 0         next if $3;
351 0           $obj = $1;
352 0           $key = $2;
353             }
354             #persistence attribute
355             elsif ($ln =~ /^((ltm persistence)\s(cookie|source-addr|universal|destination-addr))\s(\S+)\s\{(\s\})?$/) {
356 0 0         next if $5;
357 0           $obj = $2;
358 0           $key = $4;
359 0           $parsed->{$obj}{$key}{"mode"} = $3;
360             }
361             #monitor attribute
362             elsif ($ln =~ /^((ltm monitor)\s(http|tcp|udp|icmp))\s(\S+)\s\{(\s\})?$/) {
363 0 0         next if $5;
364 0           $obj = $2;
365 0           $key = $4;
366 0           $parsed->{$obj}{$key}{"mode"} = $3;
367             }
368             #profile attribute
369             elsif ($ln =~ /^((ltm profile)\s(web-acceleration|tcp|udp|request-log))\s(\S+)\s\{(\s\})?$/) {
370 0 0         next if $5;
371 0           $obj = $2;
372 0           $key = $4;
373 0           $parsed->{$obj}{$key}{"mode"} = $3;
374             }
375             #end of {}
376             elsif ( $ln =~ /^\}$/ ) {
377 0           $obj = undef;
378 0           $key = undef;
379 0           next;
380             }
381            
382             # mungle data structure
383 0 0 0       if ( $obj && $key ) {
384 0           $self->{'Raw'}->{$obj}{$key} .= $ln;
385            
386             #Indent=4 { not empty }
387 0 0         if ( $ln =~ /^\s{4}(\S+)\s\{$/ ) {
388 0           $attr1 = $1;
389 0           next;
390             }
391            
392             #$intdent=8 { not empty }
393 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{$/ ) {
394 0           $attr2 = $1;
395 0           next;
396             }
397              
398             #$intdent=12 { not empty }
399 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{$/ ) {
400 0           $attr3 = $1;
401 0           next;
402             }
403            
404             #Indent=4 with }$
405 0 0         if ( $ln =~ /^\s{4}\}$/ ) {
406 0           $attr1 = undef;
407 0           next;
408             }
409            
410             #Indent=8 with }$
411 0 0         if ( $ln =~ /^\s{8}\}$/ ) {
412 0           $attr2 = undef;
413 0           next;
414             }
415              
416             #Indent=12 with }$
417 0 0         if ( $ln =~ /^\s{12}\}$/ ) {
418 0           $attr2 = undef;
419 0           next;
420             }
421            
422             #Indent=4 {}
423 0 0         if ( $ln =~ /^\s{4}(\S+)\s\{\s\}$/ ) {
424 0           $parsed->{$obj}{$key}{$1} = undef;
425 0           next;
426             }
427            
428             #Indent=4 { scalar }
429 0 0         if ( $ln =~ /^\s{4}(\S+)\s\{(.*)\}$/ ) {
430 0   0       $parsed->{$obj}{$key}{$1} ||= [];
431 0           push @{ $parsed->{$obj}{$key}{$1} },
432 0           grep { not /^\s*$/ } split( /\s+/, $2 );
  0            
433 0           next;
434             }
435            
436 0 0 0       if ( defined $attr1 && $attr1 ) {
437             #Indent=8 {}
438 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{\s\}$/ ) {
439 0           $parsed->{$obj}{$key}{$attr1}{$1} = undef;
440 0           next;
441             }
442            
443             #Indent=8 { scalar }
444 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{(.*)\}$/ ) {
445 0   0       $parsed->{$obj}{$key}{$1} ||= [];
446 0           push @{ $parsed->{$obj}{$key}{$1} },
447 0           grep { not /^\s*$/ } split( /\s+/, $2 );
  0            
448 0           next;
449             }
450            
451             #Indent=8 match { key => value }
452 0 0         if ( $ln =~ /^\s{8}(\S+)\s(.*)$/ ) {
453 0           $parsed->{$obj}{$key}{$attr1}{$1} = $2;
454 0           next;
455             }
456            
457             #Indent=8 match scalar
458 0 0         if ( $ln =~ /^\s{8}(\S.+)$/ ) {
459 0 0         if ( ref( $parsed->{$obj}{$key}{$attr1} ) eq 'HASH' ) {
460 0           $parsed->{$obj}{$key}{$attr1}{$1} = undef;
461             }
462             else {
463 0   0       $parsed->{$obj}{$key}{$attr1} ||= [];
464 0           push @{ $parsed->{$obj}{$key}{$attr1} }, $1;
  0            
465             }
466 0           next;
467             }
468             }
469            
470 0 0 0       if (defined $attr2 && ($attr1 && $attr2)) {
      0        
471             #Indent=12 match { }
472 0 0         if ( $ln =~ /^\s{12}(\S+)\s\{\s\}$/ ) {
473 0           $parsed->{$obj}{$key}{$attr1}{$attr2}{$1} = undef;
474 0           next;
475             }
476              
477             #Indent=12 { scalar }
478 0 0         if ( $ln =~ /^\s{12}(\S+)\s\{(.*)\}$/ ) {
479 0   0       $parsed->{$obj}{$key}{$attr1} ||= [];
480 0           push @{ $parsed->{$obj}{$key}{$attr1}{$attr2}{$1} },
481 0           grep { not /^\s*$/ } split(/\s+/, $2);
  0            
482 0           next;
483             }
484              
485             #Indent=12 match { key => value }
486 0 0         if ( $ln =~ /^\s{12}(\S+)\s(.*)\s?$/ ) {
487 0           $parsed->{$obj}->{$key}{$attr1}{$attr2}{$1} = $2;
488 0           next;
489             }
490              
491             #Indent=12 match scalar
492 0 0         if ( $ln =~ /^\s{12}(.*)\s?$/ ) {
493 0 0         if ( ref($parsed->{$obj}{$key}{$attr1}{$attr2}) eq 'HASH' ) {
494 0           $parsed->{$obj}{$key}{$attr1}{$attr2}{$1} = undef;
495             }
496             else {
497 0   0       $parsed->{$obj}{$key}{$attr1}{$attr2} ||= [];
498 0           push @{ $parsed->{$obj}{$key}{$attr1}{$attr2} }, $1;
  0            
499             }
500 0           next;
501             }
502             }
503              
504 0 0 0       if (defined $attr3 && ($attr1 && $attr2 && $attr3)) {
      0        
      0        
505             #Indent=16 match { }
506 0 0         if ( $ln =~ /^\s{16}(\S+)\s\{\s\}$/ ) {
507 0           $parsed->{$obj}{$key}{$attr1}{$attr2}{$attr3}{$1} = undef;
508 0           next;
509             }
510              
511             #Indent=16 { scalar }
512 0 0         if ( $ln =~ /^\s{16}(\S+)\s\{(.*)\}$/ ) {
513 0   0       $parsed->{$obj}{$key}{$attr1} ||= [];
514 0           push @{ $parsed->{$obj}{$key}{$attr1}{$attr2}{$attr3}{$1} },
515 0           grep { not /^\s*$/ } split(/\s+/, $2);
  0            
516 0           next;
517             }
518              
519             #Indent=16 match { key => value }
520 0 0         if ( $ln =~ /^\s{16}(\S+)\s(.*)\s?$/ ) {
521 0           $parsed->{$obj}->{$key}{$attr1}{$attr2}{$attr3}{$1} = $2;
522 0           next;
523             }
524              
525             #Indent=16 match scalar
526 0 0         if ( $ln =~ /^\s{16}(.*)\s?$/ ) {
527 0 0         if ( ref($parsed->{$obj}{$key}{$attr1}{$attr2}{$attr3}) eq 'HASH' ) {
528 0           $parsed->{$obj}{$key}{$attr1}{$attr2}{$attr3}{$1} = undef;
529             }
530             else {
531 0   0       $parsed->{$obj}{$key}{$attr1}{$attr2} ||= [];
532 0           push @{ $parsed->{$obj}{$key}{$attr1}{$attr2}{$attr3} }, $1;
  0            
533             }
534 0           next;
535             }
536             }
537              
538             #Indent=4 match { key => value }
539 0 0         if ( $ln =~ /^\s{4}(\S+)\s(.*)$/ ) {
540 0           $parsed->{$obj}{$key}{$1} = $2;
541 0           next;
542             }
543             }
544             }
545              
546             # Fill in ill-formatted objects
547 0           foreach my $object ( keys %{ $self->{'Raw'} } ) {
  0            
548 0           foreach my $attr ( keys %{ $self->{'Raw'}->{$object} } ) {
  0            
549 0   0       $parsed->{$object}->{$attr} ||= $self->{'Raw'}->{$object}->{$attr};
550             }
551             }
552              
553 0           return $parsed;
554             }
555              
556             1;
557              
558             __END__