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
}
|