[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