File Coverage

blib/lib/NetApp/Volume.pm
Criterion Covered Total %
statement 77 318 24.2
branch 28 80 35.0
condition 0 3 0.0
subroutine 10 60 16.6
pod 37 50 74.0
total 152 511 29.7


line stmt bran cond sub pod time code
1              
2             package NetApp::Volume;
3              
4             our $VERSION = '500.002';
5             $VERSION = eval $VERSION; ## no critic: StringyEval
6              
7 1     1   949 use strict;
  1         2  
  1         50  
8 1     1   6 use warnings;
  1         3  
  1         39  
9 1     1   7 use English;
  1         3  
  1         10  
10 1     1   689 use Carp;
  1         11  
  1         78  
11              
12 1     1   6 use Class::Std;
  1         2  
  1         10  
13 1     1   151 use Params::Validate qw( :all );
  1         3  
  1         252  
14 1     1   8 use Regexp::Common;
  1         3  
  1         13  
15              
16 1     1   1658 use NetApp::Volume::Source;
  1         3  
  1         4795  
17              
18             {
19              
20             my %filer_of :ATTR( get => 'filer' );
21              
22             my %name_of :ATTR( get => 'name' );
23             my %state_of :ATTR;
24             my %status_of :ATTR;
25             my %options_of :ATTR;
26             my %source_of :ATTR( get => 'source' );
27              
28             my %plex_of :ATTR( get => 'plex' );
29              
30             my %aggregate_name_of :ATTR( get => 'aggregate_name' );
31              
32             my %clone_names_of :ATTR;
33             my %parent_name_of :ATTR( get => 'parent_name' );
34             my %snapshot_name_of :ATTR( get => 'snapshot_name' );
35              
36             my %path_of :ATTR( get => 'path' );
37              
38             sub BUILD {
39              
40 0     0 0 0 my ($self,$ident,$args_ref) = @_;
41              
42 0         0 my @args = %$args_ref;
43              
44 0         0 my (%args) = validate( @args, {
45             filer => { isa => 'NetApp::Filer' },
46             name => { type => SCALAR },
47             state => { type => HASHREF },
48             status => { type => HASHREF },
49             options => { type => HASHREF },
50             plex => { type => HASHREF },
51             aggregate_name => { type => SCALAR,
52             optional => 1 },
53             source => { type => HASHREF,
54             optional => 1 },
55             clone_names => { type => ARRAYREF,
56             default => [],
57             optional => 1 },
58             parent_name => { type => SCALAR,
59             optional => 1 },
60             snapshot_name => { type => SCALAR,
61             optional => 1 },
62             });
63              
64 0         0 $filer_of{$ident} = $args{filer};
65 0         0 $name_of{$ident} = $args{name};
66 0         0 $state_of{$ident} = $args{state};
67 0         0 $status_of{$ident} = $args{status};
68 0         0 $options_of{$ident} = $args{options};
69              
70 0         0 $plex_of{$ident} =
71             NetApp::Aggregate::Plex->new( $args{plex} );
72              
73 0 0       0 if ( $args{aggregate_name} ) {
74 0         0 $aggregate_name_of{$ident} = $args{aggregate_name};
75             }
76              
77 0 0       0 if ( $args{source} ) {
78 0         0 $source_of{$ident} =
79             NetApp::Volume::Source->new( $args{source} );
80             }
81              
82 0         0 $clone_names_of{$ident} = $args{clone_names};
83              
84 0 0       0 if ( $args{parent_name} ) {
85 0         0 $parent_name_of{$ident} = $args{parent_name};
86             }
87              
88 0 0       0 if ( $args{snapshot_of} ) {
89 0         0 $snapshot_name_of{$ident} = $args{snapshot_name};
90             }
91              
92 0         0 $path_of{$ident} = "/vol/$args{name}";
93              
94             }
95              
96             sub get_states {
97 0     0 1 0 return keys %{ $state_of{ident shift} };
  0         0  
98             }
99              
100             sub get_state {
101            
102 0     0 1 0 my $self = shift;
103 0         0 my $ident = ident $self;
104 0         0 my $state = shift;
105              
106 0         0 return $state_of{$ident}->{$state};
107              
108             }
109              
110             sub get_statuses { # Stati? Oh, hell no...
111 0     0 1 0 return keys %{ $status_of{ident shift} };
  0         0  
112             }
113              
114             sub get_status {
115              
116 0     0 1 0 my $self = shift;
117 0         0 my $ident = ident $self;
118 0         0 my $status = shift;
119              
120 0         0 return $status_of{$ident}->{$status};
121              
122             }
123            
124             sub get_options {
125 0     0 1 0 return keys %{ $options_of{ident shift} };
  0         0  
126             }
127              
128             sub get_option {
129              
130 0     0 1 0 my $self = shift;
131 0         0 my $ident = ident $self;
132 0         0 my $option = shift;
133              
134 0 0       0 if ( exists $options_of{$ident}->{$option} ) {
135 0         0 return $options_of{$ident}->{$option};
136             } else {
137 0         0 return undef;
138             }
139              
140             }
141              
142             sub set_option {
143              
144 0     0 1 0 my $self = shift;
145 0         0 my $option = shift;
146 0 0       0 my $value = $option eq 'root' ? '-f' : shift;
147              
148 0         0 my $ident = ident $self;
149              
150 0         0 my $name = $self->get_name;
151              
152 0         0 my @command = ( qw(vol options), $name, $option, $value );
153              
154 0         0 $self->get_filer->_run_command( command => @command );
155              
156 0 0       0 if ( $option eq 'root' ) {
157 0         0 $options_of{$ident}->{$option} = 1;
158             } else {
159 0         0 $options_of{$ident}->{$option} = $value;
160             }
161              
162 0         0 return 1;
163              
164             }
165              
166             sub get_aggregate {
167 0     0 1 0 my $self = shift;
168 0         0 return $self->get_filer->get_aggregate( $self->get_aggregate_name );
169             }
170              
171             sub get_qtree_names {
172 0     0 1 0 my $self = shift;
173 0         0 return map { $_->get_name } $self->get_qtrees;
  0         0  
174             }
175              
176             sub get_qtree {
177 0     0 1 0 my $self = shift;
178 0   0     0 my $name = shift || "/vol/" . $self->get_name;
179 0         0 return $self->get_filer->get_qtree( $name );
180             }
181              
182             sub get_qtrees {
183 0     0 1 0 my $self = shift;
184 0         0 return $self->get_filer->_get_qtree_status( volume => $self );
185             }
186              
187             sub get_language {
188              
189 0     0 1 0 my $self = shift;
190              
191 0         0 my $name = $self->get_name;
192            
193 0         0 $self->get_filer->_run_command(
194             command => [qw(vol language), $name],
195             );
196              
197 0         0 my @stdout = $self->get_filer->_get_command_stdout;
198              
199 0         0 my $language = "";
200              
201 0         0 while ( my $line = shift @stdout ) {
202 0 0       0 if ( $line =~ /Volume language is (\S+)/ ) {
203 0         0 $language = $1;
204             }
205             }
206              
207 0 0       0 if ( not $language ) {
208 0         0 croak(
209             "Unable to determine language for volume $name\n",
210             );
211             }
212              
213 0         0 return $language;
214              
215             }
216              
217             sub set_language {
218              
219 0     0 1 0 my $self = shift;
220 0         0 my $language = shift;
221              
222 0         0 my $name = $self->get_name;
223              
224 0         0 return $self->get_filer->_run_command(
225             command => [qw(vol language), $name, $language],
226             );
227              
228             }
229              
230             sub get_size {
231              
232 0     0 1 0 my $self = shift;
233              
234 0         0 my $name = $self->get_name;
235              
236 0         0 $self->get_filer->_run_command(
237             command => [qw(vol size), $name],
238             );
239              
240 0         0 my @stdout = $self->get_filer->_get_command_stdout;
241              
242 0         0 my $size = "";
243              
244 0         0 while ( defined(my $line = shift @stdout) ) {
245 0 0       0 if ( $line =~ /has size (\S+)\./ ) {
246 0         0 $size = $1;
247             }
248             }
249              
250 0 0       0 if ( not $size ) {
251 0         0 croak("Unable to determine size of volume $name\n");
252             }
253              
254 0         0 return $size;
255              
256             }
257              
258             sub set_size {
259              
260 0     0 1 0 my $self = shift;
261 0         0 my $size = shift;
262              
263 0         0 return $self->get_filer->_run_command(
264             command => [qw(vol size), $self->get_name, $size],
265             );
266              
267             }
268              
269             sub get_maxfiles {
270              
271 0     0 1 0 my $self = shift;
272              
273 0         0 my $name = $self->get_name;
274              
275 0         0 $self->get_filer->_run_command(
276             command => ['maxfiles', $name],
277             );
278              
279 0         0 my @stdout = $self->get_filer->_get_command_stdout;
280              
281 0         0 my $maxfiles = "";
282              
283 0         0 while ( my $line = shift @stdout ) {
284 0 0       0 if ( $line =~ /is currently (\d+)/ ) {
285 0         0 $maxfiles = $1;
286             }
287             }
288              
289 0 0       0 if ( not $maxfiles ) {
290 0         0 croak("Unable to determine maxfiles of volume $name\n");
291             }
292              
293 0         0 return $maxfiles;
294              
295             }
296              
297             sub set_maxfiles {
298              
299 0     0 1 0 my $self = shift;
300 0         0 my $maxfiles = shift;
301              
302 0         0 return $self->get_filer->_run_command(
303             command => ['maxfiles', $self->get_name, $maxfiles],
304             );
305              
306             }
307              
308             sub get_clone_names {
309              
310 0     0 0 0 my $self = shift;
311 0         0 my $ident = ident $self;
312              
313 0         0 return @{ $clone_names_of{$ident} };
  0         0  
314              
315             }
316              
317             sub get_clones {
318              
319 0     0 0 0 my $self = shift;
320              
321 0         0 my @clones = ();
322              
323 0         0 foreach my $clone_name ( $self->get_clone_names ) {
324 0         0 push @clones, $self->get_filer->get_volume( $clone_name );
325             }
326              
327 0         0 return @clones;
328              
329             }
330              
331             sub is_clone {
332 0     0 1 0 my $self = shift;
333 0 0       0 return ( $self->get_parent_name ? 1 : 0 );
334             }
335              
336             sub get_parent {
337 0     0 1 0 my $self = shift;
338 0 0       0 if ( $self->is_clone ) {
339 0         0 return $self->get_filer->get_volume( $self->get_parent_name );
340             } else {
341 0         0 return;
342             }
343             }
344              
345             sub get_snapmirrors {
346 0     0 1 0 my $self = shift;
347 0         0 return $self->get_filer->_get_snapmirrors( volume => $self );
348             }
349              
350             sub get_snapshots {
351 0     0 1 0 return NetApp::Snapshot->_get_snapshots( parent => shift );
352             }
353              
354             sub get_snapshot {
355 0     0 1 0 my $self = shift;
356 0         0 my ($name) = validate_pos( @_, { type => SCALAR } );
357 0         0 return grep { $_->get_name eq $name } $self->get_snapshots;
  0         0  
358             }
359              
360             sub create_snapshot {
361 0     0 1 0 my $self = shift;
362 0         0 my ($name) = validate_pos( @_, { type => SCALAR } );
363 0         0 return NetApp::Snapshot->_create_snapshot(
364             parent => $self,
365             name => $name,
366             );
367             }
368              
369             sub delete_snapshot {
370 0     0 1 0 my $self = shift;
371 0         0 my ($name) = validate_pos( @_, { type => SCALAR } );
372 0         0 return NetApp::Snapshot->_delete_snapshot(
373             parent => $self,
374             name => $name,
375             );
376             }
377              
378             sub delete_all_snapshots {
379              
380 0     0 0 0 croak(__PACKAGE__ . "->delete_all_snapshots not yet implemented\n");
381              
382             # XXX: This one's tricky to implement. Should we parse the
383             # output, and attempt to return a list of what was delete, and
384             # what was busy? Probably too ugly.
385              
386 0         0 my $self = shift;
387              
388 0         0 return $self->get_filer->_run_command(
389             command => [ qw( snap delete -a -f -q ), $self->get_name ],
390             );
391              
392             }
393              
394             sub get_snapshot_deltas {
395 0     0 1 0 return NetApp::Snapshot->_get_snapshot_deltas( parent => shift );
396             }
397              
398             sub get_snapshot_reserved {
399 0     0 1 0 return NetApp::Snapshot->_get_snapshot_reserved( parent => shift );
400             }
401              
402             sub set_snapshot_reserved {
403 0     0 1 0 my $self = shift;
404 0         0 my ($reserved) = validate_pos( @_, { type => SCALAR } );
405 0         0 return NetApp::Snapshot->_set_snapshot_reserved(
406             parent => $self,
407             reserved => $reserved,
408             );
409             }
410              
411             sub get_snapshot_schedule {
412 0     0 1 0 return NetApp::Snapshot->_get_snapshot_schedule(
413             parent => shift,
414             @_
415             );
416             }
417              
418             sub set_snapshot_schedule {
419 0     0 1 0 return NetApp::Snapshot->_set_snapshot_schedule(
420             parent => shift,
421             @_
422             );
423             }
424              
425             sub enable_snapshot_autodelete {
426 0     0 0 0 my $self = shift;
427 0         0 return $self->get_filer->_run_command(
428             command => [ qw(snap autodelete), $self->get_name, qw(on) ],
429             );
430             }
431              
432             sub disable_snapshot_autodelete {
433 0     0 1 0 my $self = shift;
434 0         0 return $self->get_filer->_run_command(
435             command => [ qw(snap autodelete), $self->get_name, qw(off) ],
436             );
437             }
438              
439             sub reset_snapshot_autodelete {
440 0     0 1 0 my $self = shift;
441 0         0 return $self->get_filer->_run_command(
442             command => [ qw(snap autodelete), $self->get_name, qw(reset) ],
443             );
444             }
445              
446             sub set_snapshot_autodelete_option {
447              
448 0     0 1 0 my $self = shift;
449              
450 0         0 my ($name,$value) = validate_pos(
451             @_,
452             { type => SCALAR },
453             { type => SCALAR },
454             );
455              
456 0         0 my @command = (
457             qw( snap autodelete ),
458             $self->get_name, $name, $value,
459             );
460              
461 0         0 return $self->get_filer->_run_command(
462             command => \@command,
463             );
464              
465             }
466              
467             sub get_snapshot_autodelete_option {
468              
469 0     0 1 0 my $self = shift;
470              
471 0         0 my ($name) = validate_pos(
472             @_,
473             { type => SCALAR },
474             );
475              
476 0         0 my @command = ( qw( snap autodelete ), $self->get_name );
477              
478 0         0 $self->get_filer->_run_command(
479             command => \@command,
480             );
481              
482 0         0 my @stdout = $self->get_filer->_get_command_stdout;
483              
484 0         0 my $found = 0;
485 0         0 my $value = "";
486              
487 0         0 while ( defined (my $line = shift @stdout) ) {
488 0 0       0 if ( $line =~ /^$name\s*:\s*(.*)/ ) {
489 0         0 $found = 1;
490 0         0 $value = $1;
491 0 0       0 $value = "" if $value eq '(not specified)';
492             }
493             }
494              
495 0 0       0 if ( not $found ) {
496 0         0 croak("Invalid autodelete option name '$name'\n");
497             }
498              
499 0         0 return $value;
500              
501             }
502              
503             sub get_temporary_exports {
504 0     0 0 0 return grep { $_->get_type eq 'temporary' } shift->get_exports;
  0         0  
505             }
506              
507             sub get_permanent_exports {
508 0     0 0 0 return grep { $_->get_type eq 'permanent' } shift->get_exports;
  0         0  
509             }
510              
511             sub get_active_exports {
512 0     0 0 0 return grep { $_->get_active } shift->get_exports;
  0         0  
513             }
514              
515             sub get_inactive_exports {
516 0     0 0 0 return grep { not $_->get_active } shift->get_exports;
  0         0  
517             }
518              
519             sub get_export {
520 0     0 0 0 my $self = shift;
521 0         0 my ($path) = validate_pos( @_, { type => SCALAR } );
522 0         0 return grep { $_->get_path eq $path } $self->get_exports;
  0         0  
523             }
524              
525             sub get_exports {
526 0     0 0 0 my $self = shift;
527             return
528 0 0       0 grep { $_->get_path eq $self->get_path ||
  0         0  
529             $_->get_actual eq $self->get_path }
530             $self->get_filer->get_exports;
531             }
532              
533             sub create_export {
534              
535 0     0 0 0 my $self = shift;
536              
537 0         0 my (%args) = validate( @_, {
538             exportas => { type => SCALAR,
539             optional => 1 },
540             type => { type => SCALAR,
541             optional => 1 },
542             nosuid => { type => SCALAR,
543             optional => 1 },
544             anon => { type => SCALAR,
545             optional => 1 },
546             sec => { type => ARRAYREF,
547             optional => 1 },
548             root => { type => ARRAYREF,
549             optional => 1 },
550             rw => { type => ARRAYREF,
551             optional => 1 },
552             ro => { type => ARRAYREF,
553             optional => 1 },
554             rw_all => { type => SCALAR,
555             optional => 1 },
556             ro_all => { type => SCALAR,
557             optional => 1 },
558             });
559              
560 0 0       0 if ( $args{exportas} ) {
561 0         0 $args{actual} = $self->get_path,
562             $args{path} = delete $args{exportas},
563             } else {
564 0         0 $args{path} = $self->get_path;
565             }
566              
567 0         0 my $export = NetApp::Filer::Export->new( \%args );
568              
569 0         0 return $export->update;
570              
571             }
572              
573             sub destroy_export {
574              
575 0     0 0 0 my $self = shift;
576              
577             # XXX: Hmm....
578              
579             }
580              
581             sub offline {
582              
583 0     0 1 0 my $self = shift;
584 0         0 my $ident = ident $self;
585              
586 0         0 my (%args) = validate( @_, {
587             cifsdelaytime => { type => SCALAR,
588             optional => 1 },
589             });
590              
591 0         0 my @command = ( qw(vol offline), $self->get_name );
592              
593 0 0       0 if ( $args{cifsdelaytime} ) {
594 0         0 push @command, '-t', $args{cifsdelaytime};
595             }
596              
597             $self->get_filer->_run_command(
598 0         0 command => \@command,
599             );
600              
601 0         0 delete $state_of{$ident}->{online};
602 0         0 delete $state_of{$ident}->{restricted};
603 0         0 $state_of{$ident}->{offline} = 1;
604            
605 0         0 return 1;
606              
607             }
608              
609             sub online {
610              
611 0     0 1 0 my $self = shift;
612 0         0 my $ident = ident $self;
613              
614 0         0 my (%args) = validate( @_, {
615             force => { type => SCALAR,
616             optional => 1 },
617             });
618              
619 0         0 my @command = ( qw( vol online ), $self->get_name );
620              
621 0 0       0 if ( $args{force} ) {
622 0         0 push @command, '-f';
623             }
624            
625             $self->get_filer->_run_command(
626 0         0 command => \@command,
627             );
628              
629 0         0 delete $state_of{$ident}->{offline};
630 0         0 delete $state_of{$ident}->{restricted};
631 0         0 $state_of{$ident}->{online} = 1;
632            
633 0         0 return 1;
634              
635             }
636              
637             sub rename {
638              
639 0     0 1 0 my $self = shift;
640 0         0 my $ident = ident shift;
641              
642 0         0 my (%args) = validate( @_, {
643             newname => { type => SCALAR },
644             });
645              
646 0         0 my $oldname = $self->get_name;
647              
648 0         0 $self->get_filer->_run_command(
649             command =>[qw(vol rename), $oldname, $args{newname}],
650             );
651              
652 0         0 $name_of{$ident} = $args{newname};
653              
654 0         0 return 1;
655              
656             }
657              
658             sub restrict {
659            
660 0     0 1 0 my $self = shift;
661 0         0 my $ident = ident shift;
662              
663 0         0 my (%args) = validate( @_, {
664             cifsdelaytime => { type => SCALAR,
665             optional => 1 },
666             });
667              
668 0         0 my @command = ( qw(vol restrict), $self->get_name );
669              
670 0 0       0 if ( $args{cifsdelaytime} ) {
671 0         0 push @command, '-t', $args{cifsdelaytime};
672             }
673              
674             $self->get_filer->_run_command(
675 0         0 command => \@command,
676             );
677              
678 0         0 delete $state_of{$ident}->{offline};
679 0         0 delete $state_of{$ident}->{online};
680 0         0 $state_of{$ident}->{restricted} = 1;
681              
682 0         0 return 1;
683              
684             }
685              
686             }
687              
688             sub _parse_vol_status_headers {
689              
690 6     6   5064 my $class = shift;
691 6         12 my $header = shift;
692              
693 6         7 my $indices = {};
694 6         8 my $index = 0;
695              
696 6 100       57 my ($volume) = ( $header =~ /(^\s+Volume\s+)/ ) or
697             croak(
698             "Unable to match 'Volume' column header\n"
699             );
700              
701 5         18 $indices->{volume} = [ 0, length($volume) ];
702 5         9 $index += length($volume);
703              
704 5 100       32 my ($state) = ( $header =~ /(State\s+)/ ) or
705             croak(
706             "Unable to match 'State' column header\n"
707             );
708              
709 4         10 $indices->{state} = [ $index, length($state) ];
710 4         6 $index += length($state);
711              
712 4 100       26 my ($status) = ( $header =~ /(Status\s+)/ ) or
713             croak(
714             "Unable to match 'Status' column header\n"
715             );
716            
717 3         7 $indices->{status} = [ $index, length($status) ];
718 3         7 $index += length($status);
719              
720 3 100       19 my ($options) = ( $header =~ /(Options\s*)/ ) or
721             croak(
722             "Unable to match 'Options' column header\n"
723             );
724            
725 2         6 $indices->{options} = [ $index ];
726              
727 2 100       8 if ( $header =~ /Source/ ) {
728 1         4 $indices->{options}->[1] = length($options);
729 1         3 $index += length($options);
730 1         5 $indices->{source} = [ $index ];
731             }
732              
733 2         7 $indices->{length} = $index + 1;
734              
735 2         6 return $indices;
736              
737             }
738              
739             sub _parse_vol_status_volume {
740              
741 4     4   15982 my $class = shift;
742            
743 4         213 my %args = validate( @_, {
744             indices => { type => HASHREF },
745             line => { type => SCALAR },
746             volume => { type => HASHREF,
747             default => {},
748             optional => 1 },
749             });
750            
751 4         32 my $indices = $args{indices};
752 4         6 my $volume = $args{volume};
753 4         15 my $line = $args{line};
754              
755 4 50       32 if ( $line =~ /Clone, backed by volume '(.*)', snapshot '(.*)'/ ) {
    50          
    50          
756              
757 0         0 $volume->{parent_name} = $1;
758 0         0 $volume->{snapshot_name} = $2;
759 0         0 return $volume;
760              
761             } elsif ( $line =~ /Volume has clones: (.*)/ ) {
762              
763 0         0 my $clones = $1;
764 0         0 $volume->{clone_names} = [ split( /[,\s]+/, $clones ) ];
765 0         0 return $volume;
766              
767             } elsif ( $line =~ /Containing aggregate: (\S+)/ ) {
768              
769 0         0 my $aggrname = $1;
770 0         0 $aggrname =~ s/'//g;
771 0 0       0 if ( $aggrname ne '' ) {
772 0         0 $volume->{aggregate_name} = $aggrname;
773             }
774 0         0 return $volume;
775              
776             }
777              
778 4 50       14 if ( length($line) < $indices->{length} ) {
779 0         0 $line .= " " x ( $indices->{length} - length($line) );
780             }
781              
782 4         8 foreach my $column ( qw( volume state status options source ) ) {
783              
784 20         27 my $value = "";
785              
786 20 100       52 next unless $indices->{$column};
787              
788 17 100       41 if ( defined $indices->{$column}->[1] ) {
789 13         62 $value = substr( $line,
790             $indices->{$column}->[0],
791             $indices->{$column}->[1] );
792             } else {
793 4         11 $value = substr( $line,
794             $indices->{$column}->[0] );
795             }
796              
797 17         83 $value =~ s/$RE{ws}{crop}//g;
798              
799 17 100       1704 if ( $column eq 'volume' ) {
    100          
800              
801 4 100       13 if ( $value ) {
802              
803 2         4 $volume->{name} = $value;
804              
805 2         8 my ($name) = split( /\s+/, $line );
806              
807 2 100       22 if ( length($name) > length($value) ) {
808 1         3 $volume->{name} = $name;
809 1         17 $line =~ s/^$name/$value/;
810             }
811              
812             }
813              
814             } elsif ( $column eq 'source' ) {
815              
816 1         4 my ($hostname,$source) = split( /:/, $value );
817              
818 1         5 $volume->{source} = {
819             hostname => $hostname,
820             volume => $source,
821             };
822              
823 1         3 $indices->{options}->[1] = undef;
824              
825 1         5 delete $indices->{source};
826              
827             } else {
828              
829 12         49 foreach my $entry ( split( /[,\s]+/, $value ) ) {
830              
831 15         17 my ($key,$value);
832              
833 15 100       29 if ( $entry =~ /=/ ) {
834 8         20 ($key,$value) = split( /=/, $entry, 2 );
835             } else {
836 7         11 ($key,$value) = ($entry,1);
837             }
838              
839 15         53 $volume->{$column}->{$key} = $value;
840              
841             }
842              
843             }
844              
845             }
846              
847 4         18 return $volume;
848              
849             }
850              
851             1;