File Coverage

blib/lib/BigIP/LTM/ParseConfig.pm
Criterion Covered Total %
statement 42 198 21.2
branch 0 72 0.0
condition 0 36 0.0
subroutine 14 42 33.3
pod 0 24 0.0
total 56 372 15.0


line stmt bran cond sub pod time code
1             package BigIP::LTM::ParseConfig;
2              
3             # CURRENTLY UNDER DEVELOMENT BY CARELINE
4              
5             our $VERSION = '0.8.2';
6             my $AUTOLOAD;
7              
8 1     1   54746 use warnings;
  1         2  
  1         27  
9 1     1   4 use strict;
  1         2  
  1         1530  
10              
11             # Initialize the module
12             sub new {
13 0     0 0   my $class = shift;
14              
15 0           my $self = {};
16 0           bless $self, $class;
17              
18 0           $self->{'ConfigFile'} = shift;
19              
20 0           return $self;
21             }
22              
23             # Return a list of objects
24 0     0 0   sub monitors { return shift->_objectlist('monitor'); }
25 0     0 0   sub nodes { return shift->_objectlist('ltm node'); }
26 0     0 0   sub partitions { return shift->_objectlist('partition'); }
27 0     0 0   sub pools { return shift->_objectlist('ltm pool'); }
28 0     0 0   sub profiles { return shift->_objectlist('ltm profile'); }
29 0     0 0   sub routes { return shift->_objectlist('net route'); }
30 0     0 0   sub interfaces { return shift->_objectlist('net interface'); }
31 0     0 0   sub rules { return shift->_objectlist('ltm rule'); }
32 0     0 0   sub users { return shift->_objectlist('auth'); }
33 0     0 0   sub virtuals { return shift->_objectlist('ltm virtual'); }
34              
35             # Return an object hash
36 0     0 0   sub monitor { return shift->_object( 'monitor', shift ); }
37 0     0 0   sub node { return shift->_object( 'ltm node', shift ); }
38 0     0 0   sub partition { return shift->_object( 'partition', shift ); }
39 0     0 0   sub pool { return shift->_object( 'ltm pool', shift ); }
40 0     0 0   sub profile { return shift->_object( 'ltm profile', shift ); }
41 0     0 0   sub route { return shift->_object( 'net route', shift ); }
42 0     0 0   sub interface { return shift->_object( 'net interface', shift ); }
43 0     0 0   sub rule { return shift->_object( 'ltm rule', shift ); }
44 0     0 0   sub user { return shift->_object( 'auth', shift ); }
45 0     0 0   sub virtual { return shift->_object( 'ltm virtual', shift ); }
46              
47             # Return a list of pool members
48             sub members {
49 0     0 0   my $self = shift;
50 0           my $pool = shift;
51              
52 0   0       $self->{'Parsed'} ||= $self->_parse();
53              
54 0 0         return 0 unless $self->{'Parsed'}->{'pool'}->{$pool}->{'members'};
55              
56 0 0         if ( ref $self->{'Parsed'}->{'pool'}->{$pool}->{'members'} eq 'ARRAY' ) {
57 0           return @{ $self->{'Parsed'}->{'pool'}->{$pool}->{'members'} };
  0            
58             }
59             else {
60 0           return $self->{'Parsed'}->{'pool'}->{$pool}->{'members'};
61             }
62             }
63              
64             # Modify an object
65             sub modify {
66 0     0 0   my $self = shift;
67              
68 0           my ($arg);
69 0           %{$arg} = @_;
  0            
70              
71 0 0 0       return 0 unless $arg->{'type'} && $arg->{'key'};
72              
73 0           my $obj = $arg->{'type'};
74 0           my $key = $arg->{'key'};
75 0           delete $arg->{'type'};
76 0           delete $arg->{'key'};
77              
78 0   0       $self->{'Parsed'} ||= $self->_parse();
79              
80 0 0         return 0 unless $self->{'Parsed'}->{$obj}->{$key};
81              
82 0           foreach my $attr ( keys %{$arg} ) {
  0            
83 0 0         next unless $self->{'Parsed'}->{$obj}->{$key}->{$attr};
84 0           $self->{'Modify'}->{$obj}->{$key}->{$attr} = $arg->{$attr};
85             }
86              
87 0           return 1;
88             }
89              
90             # Write out a new configuration file
91             sub write {
92 0     0 0   my $self = shift;
93 0   0       my $file = shift || $self->{'ConfigFile'};
94              
95 0 0         die "No changes found; no write necessary" unless $self->{'Modify'};
96              
97 0           foreach my $obj (
98             qw( self partition route user monitor auth profile node pool rule virtual )
99             )
100             {
101 0           foreach my $key ( sort keys %{ $self->{'Parsed'}->{$obj} } ) {
  0            
102 0 0         if ( $self->{'Modify'}->{$obj}->{$key} ) {
103 0           $self->{'Output'} .= "$obj $key {\n";
104 0           foreach my $attr ( $self->_order($obj) ) {
105 0 0         next unless $self->{'Parsed'}->{$obj}->{$key}->{$attr};
106             $self->{'Modify'}->{$obj}->{$key}->{$attr}
107 0   0       ||= $self->{'Parsed'}->{$obj}->{$key}->{$attr};
108 0 0         if (ref $self->{'Modify'}->{$obj}->{$key}->{$attr} eq
109             'ARRAY' )
110             {
111 0 0         if ( @{ $self->{'Modify'}->{$obj}->{$key}->{$attr} }
  0            
112             > 1 )
113             {
114 0           $self->{'Output'} .= " $attr\n";
115 0           foreach my $val (
116 0           @{ $self->{'Modify'}->{$obj}->{$key}->{$attr}
117             }
118             )
119             {
120 0           $self->{'Output'} .= " $val\n";
121 0 0         if ( $self->{'Parsed'}->{$obj}->{$key}
122             ->{'_xtra'}->{$val} )
123             {
124             $self->{'Output'}
125             .= ' '
126             . $self->{'Parsed'}->{$obj}->{$key}
127 0           ->{'_xtra'}->{$val} . "\n";
128             }
129             }
130             }
131             else {
132             $self->{'Output'}
133             .= " $attr "
134             . $self->{'Modify'}->{$obj}->{$key}
135 0           ->{$attr}[0] . "\n";
136             }
137             }
138             else {
139             $self->{'Output'}
140             .= " $attr "
141 0           . $self->{'Modify'}->{$obj}->{$key}->{$attr}
142             . "\n";
143             }
144             }
145 0           $self->{'Output'} .= "}\n";
146             }
147             else {
148 0           $self->{'Output'} .= $self->{'Raw'}->{$obj}->{$key};
149             }
150             }
151             }
152              
153 0   0       open FILE, ">$file" || return 0;
154 0           print FILE $self->{'Output'};
155 0           close FILE;
156              
157 0           return 1;
158             }
159              
160             # Return an object hash
161             sub _object {
162 0     0     my $self = shift;
163 0           my $obj = shift;
164 0           my $var = shift;
165              
166 0   0       $self->{'Parsed'} ||= $self->_parse();
167              
168 0   0       return $self->{'Parsed'}->{$obj}->{$var} || 0;
169             }
170              
171             # Return a list of objects
172             sub _objectlist {
173 0     0     my $self = shift;
174 0           my $obj = shift;
175              
176 0   0       $self->{'Parsed'} ||= $self->_parse();
177              
178 0 0         if ( $self->{'Parsed'}->{$obj} ) {
179 0           return keys %{ $self->{'Parsed'}->{$obj} };
  0            
180             }
181             else {
182 0           return 0;
183             }
184             }
185              
186             # Define object attribute ordering
187             sub _order {
188 0     0     my $self = shift;
189              
190 0           for (shift) {
191 0 0         /auth/ && return qw( bind login search servers service ssl user );
192 0 0         /monitor/
193             && return
194             qw( default base debug filter mandatoryattrs password security username interval timeout manual dest recv send );
195 0 0         /node/ && return qw( monitor screen );
196 0 0         /partition/ && return qw( description );
197 0 0         /pool/ && return qw( lb nat monitor members );
198 0 0         /self/ && return qw( netmask unit floating vlan allow );
199 0 0         /user/ && return qw( password description id group home shell role );
200 0 0         /virtual/
201             && return
202             qw( translate snat pool destination ip rules profiles persist );
203              
204 0           return 0;
205             }
206             }
207              
208             # Parse the configuration file
209             sub _parse {
210 0     0     my $self = shift;
211 0   0       my $file = shift || $self->{'ConfigFile'};
212              
213             die "File not found: $self->{'ConfigFile'}\n"
214 0 0         unless -e $self->{'ConfigFile'};
215              
216 0   0       open FILE, $file || return 0;
217 0           my @file = ;
218 0           close FILE;
219              
220 0           my ( $data, $parsed );
221              
222 0           until ( !$file[0] ) {
223 0           my $ln = shift @file;
224              
225 0 0         if ( $ln
226             =~ /^(auth|patition|cli|ltm node|ltm pool|ltm profile|ltm rule|ltm virtual|net self|net route|net interface)\s(.*)\s\{(\s?\}?)$/
227             )
228             {
229 0           $data->{'obj'} = $1;
230 0           $data->{'key'} = $2;
231             }
232              
233 0 0 0       if ( $data->{'obj'} && $data->{'key'} ) {
234 0           $self->{'Raw'}->{ $data->{'obj'} }->{ $data->{'key'} } .= $ln;
235              
236             #缩进为4且{}非空哈希
237 0 0         if ( $ln =~ /^\s{4}(\S+)\s\{$/ ) {
238 0           $data->{'list1'} = $1;
239 0           next;
240             }
241              
242             #缩进为8且{}非空哈希
243 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{$/ ) {
244 0           $data->{'list2'} = $1;
245 0           next;
246             }
247              
248             #捕捉代码块结束符并清空
249 0 0         if ( $ln =~ /^\s{4}\}$/ ) {
250 0           delete $data->{'list1'};
251 0           next;
252             }
253              
254             #捕捉代码块结束符并清空
255 0 0         if ( $ln =~ /^\s{8}\}$/ ) {
256 0           delete $data->{'list2'};
257 0           next;
258             }
259              
260             #缩进为4且携带{}空哈希
261 0 0         if ( $ln =~ /^\s{4}(\S+)\s\{\s\}$/ ) {
262 1     1   7 no strict 'refs';
  1         2  
  1         46  
263 0           $parsed->{ $data->{'obj'} }->{ $data->{'key'} }->{$1} = undef;
264 1     1   5 use strict 'refs';
  1         2  
  1         98  
265 0           next;
266             }
267              
268 0 0         if ( $data->{'list1'} ) {
269              
270             #缩进为8且携带{}空哈希
271 0 0         if ( $ln =~ /^\s{8}(\S+)\s\{\s\}$/ ) {
272 1     1   5 no strict 'refs';
  1         2  
  1         47  
273             $parsed->{ $data->{'obj'} }->{ $data->{'key'} }
274 0           ->{ $data->{'list1'} }->{$1} = undef;
275 1     1   5 use strict 'refs';
  1         2  
  1         72  
276 0           next;
277             }
278              
279             #缩进为8且为键值对
280 0 0         if ( $ln =~ /^\s{8}(\S+)\s(\S+)$/ ) {
281 1     1   5 no strict 'refs';
  1         2  
  1         41  
282             $parsed->{ $data->{'obj'} }->{ $data->{'key'} }
283 0           ->{ $data->{'list1'} }->{$1} = $2;
284 1     1   5 use strict 'refs';
  1         1  
  1         49  
285 0           next;
286             }
287              
288             #缩进为8且为标量数据
289 0 0         if ( $ln =~ /^\s{8}(\S+)$/ ) {
290 1     1   5 no strict 'refs';
  1         1  
  1         45  
291             $parsed->{ $data->{'obj'} }->{ $data->{'key'} }
292 0           ->{ $data->{'list1'} } = $1;
293 1     1   10 use strict 'refs';
  1         1  
  1         59  
294 0           next;
295             }
296             }
297              
298 0 0         if ( $data->{'list2'} ) {
299              
300             #缩进为12且为空哈希(暂时忽略缩进为12且嵌套键值对的清空) -- 待完善
301 0 0         if ( $ln =~ /^\s{12}(\S+)\s\{\s\}$/ ) {
302 1     1   5 no strict 'refs';
  1         1  
  1         51  
303             $parsed->{ $data->{'obj'} }->{ $data->{'key'} }
304 0           ->{ $data->{'list1'} }->{ $data->{'list2'} }->{$1}
305             = undef;
306 1     1   5 use strict 'refs';
  1         1  
  1         42  
307 0           next;
308             }
309              
310             #缩进为12且为键值对
311 0 0         if ( $ln =~ /^\s{12}(\S+)\s(\S+)$/ ) {
312 1     1   4 no strict 'refs';
  1         2  
  1         42  
313             $parsed->{ $data->{'obj'} }->{ $data->{'key'} }
314 0           ->{ $data->{'list1'} }->{ $data->{'list2'} }->{$1}
315             = $2;
316 1     1   5 use strict 'refs';
  1         1  
  1         204  
317 0           next;
318             }
319             }
320              
321             #兜底策略解析
322 0 0         if ( $ln =~ /^\s{4}(\S+)\s(\S+)\s+?$/ ) {
323 0           say $ln;
324 0           $parsed->{ $data->{'obj'} }->{ $data->{'key'} }->{$1} = $2;
325 0           next;
326             }
327             }
328             }
329              
330             # Fill in ill-formatted objects
331 0           foreach my $obj ( keys %{ $self->{'Raw'} } ) {
  0            
332 0           foreach my $key ( keys %{ $self->{'Raw'}->{$obj} } ) {
  0            
333 0   0       $parsed->{$obj}->{$key} ||= $self->{'Raw'}->{$obj}->{$key};
334             }
335             }
336              
337 0           return $parsed;
338             }
339              
340             1;