[Yum] failover patch -- part 2: "Is Round Robin Your Priority?"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



--KFztAG8eRSV9hGtP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Folks,

Attached is my failover patch again against the current 4_2 branch of
yum CVS.  The differences this time are 2 things: 1) I made roundRobin
into priority (cause that's what it was) and made a real roundRobin
failover class.  2) I tweaked config.py to add the proper option to the
failovermethod key,

Jack
-- 
Jack Neely <slack@xxxxxxxxxxxxxxx>
Linux Realm Kit Administration and Development 
PAMS Computer Operations at NC State University
GPG Fingerprint: 1917 5AC1 E828 9337 7AA4  EA6B 213B 765F 3B6A 5B89

--KFztAG8eRSV9hGtP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="failover.patch"

? archwork.pyc
? callback.pyc
? clientStuff.pyc
? comps.pyc
? config.pyc
? failover.patch
? failover.py
? failover.pyc
? i18n.pyc
? keepalive.pyc
? logger.pyc
? nevral.pyc
? pkgaction.pyc
? rpmUtils.pyc
? urlgrabber.pyc
? yum
? yumcomps.pyc
? yumlock.pyc
? yummain.pyc
Index: clientStuff.py
===================================================================
RCS file: /home//groups/yum/cvs/yum/clientStuff.py,v
retrieving revision 1.47.2.45
diff -u -r1.47.2.45 clientStuff.py
--- clientStuff.py	13 May 2003 05:24:03 -0000	1.47.2.45
+++ clientStuff.py	15 May 2003 21:18:03 -0000
@@ -599,7 +599,7 @@
         if not conf.cache:
             log(3, 'getting groups from server: %s' % serverid)
             try:
-                localgroupfile = retrygrab(remotegroupfile, localgroupfile, copy_local=1)
+                localgroupfile = grab(serverid, remotegroupfile, localgroupfile, copy_local=1)
             except URLGrabError, e:
                 log(3, 'Error getting file %s' % remotegroupfile)
                 log(3, '%s' % e)
@@ -634,7 +634,7 @@
         if not conf.cache:
             log(3, 'Getting header.info from server')
             try:
-                headerinfofn = retrygrab(serverheader, localheaderinfo, copy_local=1)
+                headerinfofn = grab(serverid, serverheader, localheaderinfo, copy_local=1)
             except URLGrabError, e:
                 errorlog(0, 'Error getting file %s' % serverheader)
                 errorlog(0, '%s' % e)
@@ -657,7 +657,8 @@
     for (name, arch) in nulist:
         LocalHeaderFile = HeaderInfo.localHdrPath(name, arch)
         RemoteHeaderFile = HeaderInfo.remoteHdrUrl(name, arch)
-
+        serverid = HeaderInfo.serverid(name, arch)
+        
         # if we have one cached, check it, if it fails, unlink it and continue
         # as if it never existed
         # else move along
@@ -681,8 +682,8 @@
         if not conf.cache:
             log(2, 'getting %s' % LocalHeaderFile)
             try:
-                hdrfn = retrygrab(RemoteHeaderFile, LocalHeaderFile, copy_local=1,
-                                  checkfunc=(rpmUtils.checkheader, (name, arch), {}))
+                hdrfn = grab(serverid, RemoteHeaderFile, LocalHeaderFile, copy_local=1,
+                             checkfunc=(rpmUtils.checkheader, (name, arch), {}))
             except URLGrabError, e:
                 errorlog(0, 'Error getting file %s' % RemoteHeaderFile)
                 errorlog(0, '%s' % e)
@@ -843,7 +844,7 @@
             else:
                 log(2, 'Getting %s' % (os.path.basename(rpmloc)))
                 try:
-                    localrpmpath = retrygrab(tsInfo.remoteRpmUrl(name, arch), rpmloc, copy_local=0) 
+                    localrpmpath = grab(serverid, tsInfo.remoteRpmUrl(name, arch), rpmloc, copy_local=0) 
                 except URLGrabError, e:
                     errorlog(0, 'Error getting file %s' % tsInfo.remoteRpmUrl(name, arch))
                     errorlog(0, '%s' % e)
@@ -922,3 +923,50 @@
     else:
         size = size / 1000000000.0
         return "%.2f GB" % size
+        
+        
+def grab(serverID, url, filename=None, copy_local=0, close_connection=0,
+          progress_obj=None, throttle=None, bandwidth=None,
+          numtries=3, retrycodes=[-1,2,4,5,6,7], checkfunc=None):
+              
+    """Wrap retry grab and add in failover stuff.  This needs access to
+    the conf class as well as the serverID.
+        
+    We do look at retrycodes here to see if we should return or failover.
+    On fail we will raise the last exception that we got."""
+        
+    fc = conf.get_failClass(serverID)
+    base = ''
+    for root in conf.serverurl[serverID]:
+        if string.find(url, root) == 0:
+            # We found the current base this url is made of
+            base = root
+            break
+    if base == '':
+        # We didn't find the base...something is wrong
+        raise Exception, "%s isn't made from a base URL I know about" % url
+    url = url[len(base):]
+    log(3, "failover: baseURL = " + base)
+    log(3, "failover: path = " + url)
+    
+    # don't trust the base that the user supplied
+    base = fc.get_serverurl()
+    while base != None:
+        # Loop over baseURLs until one works or all are dead
+        try:
+            # XXX need some urlparse magic to keep this from breaking
+            return retrygrab(base+url, filename, copy_local,
+                             close_connection, progress_obj, throttle,
+                             bandwidth, numtries, retrycodes, checkfunc)
+            # What?  We were successful?
+        except URLGrabError, e:
+            if e.errno in retrycodes:
+                log(2, "retrygrab() failed -- executing failover method")
+                fc.server_failed()
+                base = fc.get_serverurl()
+                if base == None:
+                    log(1, "failover: out of servers to try")
+                    raise
+            else:
+                raise
+        
Index: config.py
===================================================================
RCS file: /home//groups/yum/cvs/yum/config.py,v
retrieving revision 1.14.2.13
diff -u -r1.14.2.13 config.py
--- config.py	11 May 2003 06:04:03 -0000	1.14.2.13
+++ config.py	15 May 2003 21:18:03 -0000
@@ -23,6 +23,7 @@
 import urllib
 import rpm
 import re
+import failover
 import archwork
 import rpmUtils
 
@@ -53,8 +54,9 @@
         self.serverpkgdir = {}
         self.serverhdrdir = {}
         self.servercache = {}
-        self.servergpgcheck= {}
-        self.excludes= []
+        self.servergpgcheck={}
+        self.failoverclass = {}
+        self.excludes=[]
         
         #defaults
         self.cachedir = '/var/cache/yum'
@@ -117,23 +119,33 @@
             for section in self.cfg.sections(): # loop through the list of sections
                 if section != 'main': # must be a serverid
                     name = self._getoption(section,'name')
-                    url = self._getoption(section,'baseurl')
-                    if name != None and url != None:
+                    urls = self._doreplace(self._getoption(section,'baseurl'))
+                    url = string.split(urls, ' ')
+                    if name != None and url != []:
                         self.servers.append(section)
                         name = self._doreplace(name)
-                        url = self._doreplace(url)
                         self.servername[section] = name
                         self.serverurl[section] = url
+                        failmeth = self._getoption(section,'failovermethod')
+                        if failmeth == 'roundrobin':
+                            failclass = failover.roundRobin(self, section)
+                        elif failmeth == 'priority':
+                            failclass = failover.priority(self, section)
+                        else:
+                            failclass = failover.roundRobin(self, section)
+                        self.failoverclass[section] = failclass
                         if self._getoption(section,'gpgcheck') != None:
                             self.servergpgcheck[section]=self.cfg.getboolean(section,'gpgcheck')
                         else:
                             self.servergpgcheck[section]=0
-                        
-                        (s,b,p,q,f,o) = urlparse.urlparse(self.serverurl[section])
-                        # currently only allowing http, ftp and file url types
-                        if s not in ['http', 'ftp', 'file']:
-                            print _('Not using ftp, http or file for servers, Aborting - %s') % (self.serverurl[section])
-                            sys.exit(1)
+
+                        for url in self.serverurl[section]:
+                            (s,b,p,q,f,o) = urlparse.urlparse(url)
+                            # currently only allowing http and ftp servers 
+                            if s not in ['http', 'ftp', 'file', 'https']:
+                                print _('using ftp, http[s], or file for servers, Aborting - %s') % (url)
+                                sys.exit(1)
+
                         cache = os.path.join(self.cachedir,section)
                         pkgdir = os.path.join(cache, 'packages')
                         hdrdir = os.path.join(cache, 'headers')
@@ -155,13 +167,19 @@
             return None
             
     def remoteGroups(self, serverid):
-        return os.path.join(self.serverurl[serverid], 'yumgroups.xml')
+        return os.path.join(self.baseURL(serverid), 'yumgroups.xml')
     
     def localGroups(self, serverid):
         return os.path.join(self.servercache[serverid], 'yumgroups.xml')
         
     def baseURL(self, serverid):
-        return self.serverurl[serverid]
+        return self.get_failClass(serverid).get_serverurl()
+        
+    def server_failed(self, serverid):
+        self.failoverclass[serverid].server_failed()
+    
+    def get_failClass(self, serverid):
+        return self.failoverclass[serverid]
         
     def remoteHeader(self, serverid):
         return os.path.join(self.baseURL(serverid), 'headers/header.info')
Index: nevral.py
===================================================================
RCS file: /home//groups/yum/cvs/yum/nevral.py,v
retrieving revision 1.28.2.24
diff -u -r1.28.2.24 nevral.py
--- nevral.py	6 May 2003 03:00:05 -0000	1.28.2.24
+++ nevral.py	15 May 2003 21:18:03 -0000
@@ -144,7 +144,7 @@
         if l == 'in_rpm_db':
             return l
         hdrfn = self.hdrfn(name,arch)
-        base = conf.serverurl[i]
+        base = conf.baseURL(i)
         return base + '/headers/' + hdrfn
     
     def localHdrPath(self, name, arch=None):
@@ -175,7 +175,7 @@
             return None
         if l == 'in_rpm_db':
             return l
-        base = conf.serverurl[i]
+        base = conf.baseURL(i)
         return base +'/'+ l
     
     def localRpmPath(self, name, arch=None):

--KFztAG8eRSV9hGtP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="failover.py"

#!/usr/bin/python
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Copyright 2003 Jack Neely, NC State University

# Here we define a base class for failover methods.  The idea here is that each
# failover method uses a class derived from the base class so yum only has to
# worry about calling get_serverurl() and server_failed() and these classes will 
# figure out which URL to cough up based on the failover method.

import random

class baseFailOverMethod:

    def __init__(self, conf, serverID):
        # the yum conf structure
        self.conf = conf
        self.serverID = serverID
        self.failures = 0
    
    def get_serverurl(self):
        "Returns a serverurl based on this failover method or None if complete failure."
        return None
        
    def server_failed(self):
        "Tells the failover method that the current server is failed."
        self.failures = self.failures + 1
        
    def reset(self):
        "Reset the failures counter."
        self.failures = 0
        
            

class priority(baseFailOverMethod):

    """Chooses server based on the first success in the list."""
    
    def get_serverurl(self):
        "Returns a serverurl based on this failover method or None if complete failure."
        
        if self.failures >= len(self.conf.serverurl[self.serverID]):
            return None
        
        return self.conf.serverurl[self.serverID][self.failures]
        
        
    
class roundRobin(baseFailOverMethod):

    """Chooses server based on a round robin."""
    
    def __init__(self, conf, serverID):
        baseFailOverMethod.__init__(self, conf, serverID)
        random.seed()
        self.offset = random.randint(0, 37)
    
    def get_serverurl(self):
        "Returns a serverurl based on this failover method or None if complete failure."
        
        if self.failures >= len(self.conf.serverurl[self.serverID]):
            return None
        
        i = (self.failures + self.offset) % len(self.conf.serverurl[self.serverID])
        return self.conf.serverurl[self.serverID][i]    

--KFztAG8eRSV9hGtP--


[Index of Archives]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux