Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

perl module that does parsing to config files

by liri (Acolyte)
on Nov 30, 2006 at 12:53 UTC ( [id://586922]=perlquestion: print w/replies, xml ) Need Help??

liri has asked for the wisdom of the Perl Monks concerning the following question:

Hey guys, I need to be able to parse (read/write) config files in this format:
checktimeout=10 checkinterval=2 autoreload=no logfile="local0" quiescent=yes virtual=10.107.0.51:80 real=10.107.0.163:80 gate fallback=127.0.0.1:80 gate service=http request="ldirector.html" [taken from ldirector.cf config file]
as you can see there are general values like the top ones (checktimeout, checkinterval) and there are values per section. for example the virtual=10.107.0.51 is a section by itself with sub-values of real, fallback, service and request (the section is noted in the config file by a tab or spaces). Does anyone know of a module available that is able to parse these kind of config files? Thanks.

Replies are listed 'Best First'.
Re: perl module that does parsing to config files
by Fengor (Pilgrim) on Nov 30, 2006 at 13:42 UTC
    Module? no but maybe something like this?
    #!/usr/bin/perl use strict; my $conffile = "ldirector.conf"; my %chash; my $key = ""; my $value = ""; my $virtual = ""; open(CONF, "< $conffile") or die "Couldn't open $conffile for reading: $!\n"; while(<CONF>) { chomp(); ($key,$value) = split(/=/); if ($key eq "virtual") { $virtual = $value; } elsif ($key =~ s/^\s+(.*)/$1/) { $chash{'virtual'}{$virtual}{$key}=$value; } else { $chash{$key}=$value; } }
    Caveats: This code was thrown together in mere minutes. so no responsibility taken if it accientally wipes your hard drive and stuff ;) It should read your config file though and put your variables into a hash with the part before the = as key and the part after the = as the value. Saves the virtual value if it encounters one and add every line that follows as a key value pair to $chash{'virtual'}{$lastvirtualencountered}{$key} = $value pairs

    So make sure that there is NO intendet line before the first virtual or else this code will not work correctly.

    --
    "WHAT CAN THE HARVEST HOPE FOR IF NOT THE CARE OF THE REAPER MAN"
    -- Terry Pratchett, "Reaper Man"

      Thank you! I did some small modification to ignore new lines and print it right :)
Re: perl module that does parsing to config files
by Limbic~Region (Chancellor) on Nov 30, 2006 at 13:38 UTC
    liri,
    I am not aware of any config parsing modules that uses whitespace to denote sections but that's because I always use Config::IniFiles. There is however a large suite of modules in the Config:: family - have you looked yourself yet?

    Cheers - L~R

      Yeah I started looking on cpan for some but you're more than right there is more than a handful, and not all of them mention how they work so it's a bit hard to know which module is right out of all the results. Thanks, I will check the IniConfig module.
Re: perl module that does parsing to config files
by salva (Canon) on Nov 30, 2006 at 17:01 UTC
    this is copy & pasted from a webmin module for LVS (that I am not allowed to share :-( ). It reads the data on the config file and mixes it with runtime information:
    sub _host_to_ip { join '.', map { ord $_ } split //, scalar gethostbyn +ame($_[0]) } sub _service_to_port { return $_[0] if $_[0] =~ /^\d+$/; return scalar getservbyname($_[0], $_[1]); } sub lvs_read_config { open my $fh, "/etc/ha.d/ldirectord.cf" or return (); my %other; my @virtual; my $virtual; while (<$fh>) { next if /^\s*(?:#.*)?$/; my ($k, $v) = /^\s*(.*?)\s*=\s*(.*?)\s*$/ or return _lvs_error "error reading configuration file: ba +d entry '$_'"; if (defined $virtual and /^\s/) { if ($k eq 'real') { my ($host, $service, $forward, $weight, $request) = $v =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::(\ +d+))?\s+(\w+)(?:\s+(\d+)(?:\s+(\w+))?)?\s*$/ or return _lvs_error "error reading configurat +ion file: bad real entry '$v'"; my $real = { host => $host, service => $service, forward => $forward, weight => (defined($weight) ? $weight : 1 +), request => $request }; push @{$virtual->{real}}, $real; } else { $virtual->{$k} = $v; } } else { if ($k eq 'virtual') { my ($host, $service) = $v =~ /^(\w+(?:\.\w+)*)(?::(\w+))?$/ or return _lvs_error "error reading configurat +ion file: bad virtual entry '$v'"; $virtual = { scheduler => 'rr', protocol => 'tcp', persistent => '0', real => [] }; push @virtual, $virtual; $virtual->{_service} = $service; $virtual->{_host} = $host; } else { $other{$k} = $v; } } } my @ifaces = active_interfaces(); my $runtime = $other{_runtime} = lvs_read_runtime(); my %virtual; for my $v (@virtual) { my $proto = $v->{proto} ||= 'tcp'; $v->{_port} = _service_to_port($v->{_service}, $proto); $v->{_ip} = _host_to_ip($v->{_host}); my $k = $v->{_key} = "$v->{_ip}:$v->{_port}:$v->{proto}"; $virtual{$k} = $v; for my $real (@{$virtual->{real}}) { $real->{ip} = _host_to_ip($real->{host}); $real->{port} = _service_to_port($real->{service}, $proto) +; my $key = $real->{_key} = "$real->{ip}:$real->{port}"; $virtual->{_real}{$key} = $real; my $rsch = ( $runtime->{$k}{_found} ? $runtime->{$k} : $v +)->{scheduler}; my $weightable = $runtime->{$k}{weightable} = $rsch =~ /^w +/; my $rrt = $runtime->{$k}{_real}{$key}; my $found = $rrt->{_found}; my $status = $rrt->{_status} = ( $found ? ( ($weightable and $rrt +->{weight} == 0) ? 1 : 2 ) : 0 ); $real->{_status} = $status; } } $other{virtual} = \%virtual; $other{_ifaces} = \@ifaces; return \%other } # sample ipvsadm -L output: # # IP Virtual Server version 1.2.0 (size=4096) # Prot LocalAddress:Port Scheduler Flags # -> RemoteAddress:Port Forward Weight ActiveConn InActCon +n # TCP 192.168.1.60:22 rr # -> 192.168.1.57:22 Tunnel 1 0 0 # -> 192.168.1.56:22 Tunnel 1 0 0 sub lvs_read_runtime { open my $ipvs, '-|', $IPVSADM, '-L', or _lvs_error("can't find $IPVSADM"); for (1..3) { defined <$ipvs> or return _lvs_error("$IPVSADM failed"); } my @ifaces = active_interfaces(); my %virtual; my $virtual; while(<$ipvs>) { if (/^\s*(\w+)\s+(\w+(?:\.\w+)*):(\w+)\s+(\w+)(?:\s+(\S.*?))?\ +s*$/) { $virtual = { proto => lc($1), _host => $2, _service => $3, scheduler => $4, flags => (defined $5 ? $5 : ''), _found => 1, real => [], _real => {} }; $virtual->{_ip} = _host_to_ip($virtual->{_host}); $virtual->{_port} = _service_to_port($virtual->{_service}, + $virtual->{proto}); $virtual->{_flags} = { split(' ', $virtual->{flags}) }; $virtual->{persistent} = $virtual->{_flags}{persistent} || + 0; my $k = $virtual->{_key} = "$virtual->{_ip}:$virtual->{_po +rt}:$virtual->{proto}"; $virtual{$k} = $virtual; $virtual->{_active} = grep { $_->{address} eq $virtual->{_ip} } @ifaces; } elsif (/^\s*->\s+(\w+(?:\.\w+)*):(\w+)\s+(\w+)\s+(\d+)\s+(\d+) +\s+(\d+)\s*$/) { $virtual or return _lvs_error("bad output from $IPVSADM"); my $real = { host => $1, service => $2, forward => $fwdname{$3}, weight => $4, active_conn => $5, inactive_conn => $6, _found => 1 }; $real->{ip} = _host_to_ip($real->{host}); $real->{port} = _service_to_port($real->{service}, $virtua +l->{proto}); my $key = $real->{_key} = "$real->{ip}:$real->{port}"; push @{$virtual->{real}}, $real; $virtual->{_real}{$key} = $real; } } \%virtual; } sub _lvs_error { ... } sub active_interfaces { # that's available from another Webmin module }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://586922]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-04-25 11:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found