LVS
lvs-users
Google
 
Web LinuxVirtualServer.org

Re: ldirectord works for HTTP but Not FTP -- CAUSE ISOLATED

To: Joseph Mack NA3T <jmack@xxxxxxxx>
Subject: Re: ldirectord works for HTTP but Not FTP -- CAUSE ISOLATED
Cc: "LinuxVirtualServer.org users mailing list." <lvs-users@xxxxxxxxxxxxxxxxxxxxxx>
From: Horms <horms@xxxxxxxxxxxx>
Date: Tue, 18 Jul 2006 13:43:02 -0400
On Sun, Jul 16, 2006 at 05:49:44PM -0700, Joseph Mack NA3T wrote:
> On Sun, 16 Jul 2006, Robinson, Eric wrote:
> 
> >The root cause is that ipvsadm is misbehaving. Instead of changing the
> >realserver's weight, it is complaining that the destination exists.
> 
> There were a few of us who wanted this behaviour changed, 
> but at the time we were vetoed, but maybe times have 
> changed.
> 
> Hey Horms,
> 
>       I don't suppose the ipvsadm add/edit patch of yours 
> could be revisited? It seems the current behaviour is 
> causing problems with ldirectord.

Hi Joe,

Eric and I discussed this offline and I have formulated a patch which
seems to be working.  It should apply to 1.131 (the version he is
using), 1.141 (the version in CVS right now), and likely quite a few
other versions. Comments inline. Feedback welcome.

-- 
Horms                                           
  H: http://www.vergenet.net/~horms/
  W: http://www.valinux.co.jp/en/

--- from-0001/ldirectord
+++ to-work/ldirectord  2006-07-17 22:15:09.000000000 -0400
@@ -1496,6 +1496,44 @@ sub ld_setup
        }
 }
 
+# ld_read_ipvsadm
+#
+# Net::FTP seems to set the input record separator ($\) to null
+# putting IO into slurp (whole file at a time, rather than line at a time)
+# mode. Net::FTP does this using local $\, which should mean
+# that the change doesn' effect code here, but it does. It also
+# seems to be imposible to turn it off, by say setting $\ back to '\n'
+# Perhaps there is more to this than meets the eye. Perhaps its a perl bug.
+# In any case, this should fix the problem.
+#
+# This should not affect pid or config file parsing as they are called
+# before Net::FTP and as this appears to be a bit of a work around,
+# I'd rather use it in as few places as possible
+#
+# Observed with perl v5.8.8 (Debian's perl 5.8.8-6)
+# -- Horms, 17th July 2005
+sub ld_readline
+{
+       my ($fd, $buf) = (@_);
+       my $line;
+
+       # Uncomment the following line to turn off this work around
+       # return readline($fd);
+
+       $line = shift @$buf;
+       if (defined $line) {
+               return $line . "\n";
+       }
+
+       push @$buf, split /\n/, readline($fd);
+
+       $line = shift @$buf;
+       if (defined $line) {
+               return $line . "\n";
+       }
+
+       return undef;
+}
 
 # ld_read_ipvsadm
 # Parses the output of "ipvsadm -L -n" and puts into a structure of
@@ -1540,28 +1578,35 @@ sub ld_read_ipvsadm
        my %oldsrv;
        my $real_service;
        my $fwd;
+       my $buf = [];
+       my $fh;
+       my $line;
 
        # read status of current ipvsadm -L -n
-       unless(open(IPVS, "$IPVSADM -L -n |")){
+       unless(open($fh, "$IPVSADM -L -n 2>&1|")){
           &ld_exit(1, "Could not run $IPVSADM -L -n: $!");
         }
-       $_ = <IPVS>; $_ = <IPVS>; $_ = <IPVS>;
 
-       while (<IPVS>) {
-               if ($_ =~ 
/(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)\s+persistent\s+(\d+)\s+mask\s+(.*)/)
 {
+       # Skip the first three lines
+       $line = ld_readline($fh, $buf); 
+       $line = ld_readline($fh, $buf); 
+       $line = ld_readline($fh, $buf);
+
+       while ($line = ld_readline($fh, $buf)) {
+               if ($line =~ 
/(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)\s+persistent\s+(\d+)\s+mask\s+(.*)/)
 {
                        $real_service = "$2 ".lc($1);
                        $oldsrv{"$real_service"} = {"real"=>{}, 
"scheduler"=>$3, "persistent"=>$4, "netmask"=>$5};
-               } elsif ($_ =~ 
/(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)\s+persistent\s+(\d+)/) {
+               } elsif ($line =~ 
/(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)\s+persistent\s+(\d+)/) {
                        $real_service = "$2 ".lc($1);
                        $oldsrv{"$real_service"} = {"real"=>{}, 
"scheduler"=>$3, "persistent"=>$4};
-               } elsif ($_ =~ /(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)/) 
{
+               } elsif ($line =~ 
/(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)/) {
                        $real_service = "$2 ".lc($1);
                        $oldsrv{"$real_service"} = {"real"=>{}, 
"scheduler"=>$3};
                } else {
                        next;
                }
-               while(<IPVS>) {
-                       last unless $_ =~ / 
->\s+(\d+\.\d+\.\d+\.\d+\:\d+)\s+(\w+)\s+(\d+)/;
+               while ($line = ld_readline($fh, $buf)) {
+                       last unless $line =~ / 
->\s+(\d+\.\d+\.\d+\.\d+\:\d+)\s+(\w+)\s+(\d+)/;
                        if ($2 eq "Route") {
                                $fwd = "gate";
                        } elsif ($2 eq "Tunnel") {
@@ -1573,7 +1618,7 @@ sub ld_read_ipvsadm
                }
                redo;
        }
-       close(IPVS);
+       close($fh);
 
         return(\%oldsrv);
 }

<Prev in Thread] Current Thread [Next in Thread>