[Yum-devel] RHN Support

Jack Neely jjneely at pams.ncsu.edu
Fri Mar 18 20:32:39 UTC 2005


So, Seth's been beating me about writing support for RHN repositories
for Yum.  Being that I maintain Current (http://current.tigris.org) I
can definately see some advantage here.  That and I'm like one of 2
people outside of Red Hat that knows the API.

So I've been hacking on the attached file that is supposed to be an
interface that other Yum objects can use to get data from an RHN
repository.

It works with Current.  (What I've done most of my testing with.)
However, against RHN itself urlgrabber (2.9.6) barfs up some interesting
tracebacks.  See attached.  Michael?

Of late I have been /very/ busy at work and have not had the time to
work on this as I'd like to.  But Seth still beats on me.  So, *shrug*
here ya go.  Maybe y'all will help motivate me more...or you could do my
job for me.  :-)

Jack Neely
-- 
Jack Neely <slack at quackmaster.net>
Realm Linux Administration and Development
PAMS Computer Operations at NC State University
GPG Fingerprint: 1917 5AC1 E828 9337 7AA4  EA6B 213B 765F 3B6A 5B89
-------------- next part --------------
import Errors
import xmlrpclib
import os
import os.path
import urlgrabber
import string
import xml
import gzip

class RHNRepoError(Errors.RepoError):
    pass


class RHN(object):
    """Handle Connecting to an RHN API"""

    def __init__(self, xmlrpc):
        # xmlrpc = URL to RHN API interface
        self.rhn = xmlrpclib.ServerProxy(xmlrpc)
        self.url = xmlrpc

        # systemid -- Identifies your system to RHN
        self.sysid = None

        # headers needed for the GET requests
        self.headers = None

        # A list of dicts describing each channel we have access to.
        # The most important of which is the 'label' key
        self.channels = {}

        # Urlgrabber object
        self.urlgrabber = None


    def checkRegistration(self, systemid="/etc/sysconfig/rhn/systemid"):
        """Return true if the system is registered.  You may specify path
           to the systemid file."""
        
        if os.access(systemid, os.F_OK) and not os.access(systemid, os.R_OK):
            raise RHNRepoError("Permissions error reading %s" % systemid)
        elif not os.access(systemid, os.F_OK):
            return False

        if self.sysid == None:
            fd = open(systemid)
            self.sysid = fd.read()
            fd.close()

        return True

        
    def login(self):
        "Login to RHN and get channel information"
        
        self.headers = self.doCall(self.rhn.up2date.login, (self.sysid,))
        
        self.channels = self.doCall(self.rhn.up2date.listChannels, 
                            (self.sysid,))


    def doCall(self, method, params):
        "Wrapper for all XMLRPC calls"

        try:
            ret = method(*params, **{})
        except xmlrpclib.ProtocolError, e:
            # XXX: Error checking here
            raise

        return ret


    def __getURLGrabber(self):
        "Setup the urlgrabber object for RHN"

        if self.headers == None:
            raise RHNRepoError("You must call RHN.login() before this functon.")

        if not self.urlgrabber == None:
            return self.urlgrabber

        t = []
        for header in self.headers.keys():
            if header == "X-RHN-Auth-Channels":
                l = []
                for chan in self.headers[header]:
                    l.append(str(chan))
                t.append((header, string.join(l, ",")))
            else:
                t.append((header, self.headers[header]))
        
        self.urlgrabber = urlgrabber.grabber.URLGrabber(http_headers=t)
        return self.urlgrabber

    
    def __loads(self, url):
        "Make like xmlrpclib.loads() with a url"

        grab = self.__getURLGrabber()
        
        # XXX: must fix this!!!
        file = grab.urlgrab(url)
        fd = open(file)
        data = fd.read()
        fd.close()

        try:
            params, methodname = xmlrpclib.loads(data)
        except xml.parsers.expat.ExpatError, e:
            # Oops, urlgrabber didn't decode the x-gzip data
            fd = gzip.GzipFile(file)
            params, methodname = xmlrpclib.loads(fd.read())

        os.unlink(file)

        return params, methodname
     
     
    def getLastModification(self, channel):
        "Return the last modification time for the given channel label."

        for chan in self.headers['X-RHN-Auth-Channels']:
            if chan[0] == channel:
                return chan[1]

        raise RHNRepoError("Channel %s not found." % channel)


    def listPackages(self, channel):
        "Return the package list for the given channel label"

        m = self.getLastModification(channel)
        url = os.path.join(self.url, "$RHN", channel, "listPackages", m)

        params, methodname = self.__loads(url)

        return params[0]


    def getObsoletes(self, channel):
        "Return the obsoletes list from the given channel label"

        m = self.getLastModification(channel)
        url = os.path.join(self.url, "$RHN", channel, "getObsoletes", m)

        params, methodname = self.__loads(url)

        return params[0]


    def getPackage(self, channel, filename):
        return self.__getFile("getPackage", channel, filename)


    def getPackageHeader(self, channel, filename):
        return self.__getFile("getPackageHeader", channel, filename)


    def getPackageSource(self, channel, filename):
        return self.__getFile("getPackageSource", channel, filename)

   
    def solveDependencies(self, unknowns):
        "Returns a dict of package lists keyed on the list of unknowns given"

        params = (self.sysid, unknowns)
        return self.doCall(self.rhn.up2date.solveDependencies, params)

    
    def __getFile(self, apicall, channel, filename):
        "Return a file something or other..."

        url = os.path.join(self.url, "$RHN", channel, apicall, filename)
        grab = self.__getURLGrabber()
        return grab.urlgrab(url)


    def __fileBase(self, package):
        
        # This is directly from up2date's code
        # If up2date does it this way it can't be wrong, can it?
        
        #  package list format
        # 0        1        2       3     4     5      6
        # name, version, release, epoch, arch, size, channel
                        
        return "%s-%s-%s.%s" % (package[0], package[1], package[2],
                            package[4])

        
    def getHeaderName(self, package):
        return self.__fileBase(package) + ".hdr"


    def getRPMName(self, package):
        return self.__fileBase(package) + ".rpm"


def main():
    r = RHN("https://rhn.linux.ncsu.edu/XMLRPC")
    if r.checkRegistration():
        print "System is Registered"
    else:
        print "System is NOT registered!!"
        return

    r.login()
    print r.headers
    print r.channels

    packages =  r.listPackages("realmlinux-ws4")
    print r.getObsoletes("rhel-i386-ws-4")

    print r.getRPMName(packages[3])
    print r._RHN__getFile("getPackage", "rhel-i386-ws-4", r.getRPMName(packages[4]))

    print r.getPackage("rhel-i386-ws-4", "ElectricFence-2.2.2-19.i386.rpm")

    print r.solveDependencies(['/etc/fedora-release'])


if __name__ == "__main__":
    main()

-------------- next part --------------
Traceback (most recent call last):
  File "rhn.py", line 224, in ?
    main()
  File "rhn.py", line 212, in main
    packages =  r.listPackages("realmlinux-ws4")
  File "rhn.py", line 136, in listPackages
    params, methodname = self.__loads(url)
  File "rhn.py", line 103, in __loads
    file = grab.urlgrab(url)
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 618, in urlgrab
    return self._retry(opts, retryfunc, url, filename)
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 547, in _retry
    return apply(func, (opts,) + args, {})
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 604, in retryfunc
    fo = URLGrabberFileObject(url, filename, opts)
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 727, in __init__
    self._do_open()
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 794, in _do_open
    fo, hdr = self._make_request(req, opener)
  File "/usr/lib/python2.3/site-packages/urlgrabber/grabber.py", line 885, in _make_request
    fo = opener.open(req)
  File "/usr/lib/python2.3/urllib2.py", line 326, in open
    '_open', req)
  File "/usr/lib/python2.3/urllib2.py", line 306, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.3/urllib2.py", line 908, in https_open
    return self.do_open(httplib.HTTPS, req)
  File "/usr/lib/python2.3/urllib2.py", line 880, in do_open
    h.putheader(k, v)
  File "/usr/lib/python2.3/httplib.py", line 1038, in putheader
    self._conn.putheader(header, '\r\n\t'.join(values))
TypeError: sequence item 0: expected string, int found



More information about the Yum-devel mailing list