[Yum-devel] RHN Support
Jack Neely
jjneely at pams.ncsu.edu
Tue Mar 22 03:06:36 UTC 2005
Folks,
So, apperently, that big, long traceback was urllib2's way of telling me
that it doesn't like non-string headers.
Attached is an actual working rhn.py. It can query and fetch files from
either Current (which I found some neat protocall brokenness in) and
RHN/RHN Proxies.
Have fun.
Jack
--
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
import zlib
import base64
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, str(self.headers[header])))
self.urlgrabber = urlgrabber.grabber.URLGrabber(http_headers=t)
return self.urlgrabber
def _getEncoding(self, fd):
"Return the Content-Encoding of the HTTP stream"
if not isinstance(fd, urlgrabber.grabber.URLGrabberFileObject):
raise RHNRepoError("Got passed something that was not a " \
"URLGrabberFileObject")
for line in str(fd.info()).split('\n'):
if line[0:17] in ["Content-Encoding:", "content-encoding:"]:
return string.strip(line[18:])
return "" # What's the default encoding?
def __loads(self, url):
"Make like xmlrpclib.loads() with a url"
grab = self.__getURLGrabber()
fd = grab.urlopen(url)
encoding = self._getEncoding(fd)
if encoding == "x-zlib":
# RHN
bin = base64.decodestring(fd.read())
params, methodname = xmlrpclib.loads(zlib.decompress(bin))
elif encoding == "x-gzip":
# Need a real file object -- and GzipFile bitches about
# python's tmpfile() objects
tmp = open("/tmp/rhncrap", "w")
tmp.write(fd.read())
tmp.close()
fd = gzip.GzipFile("/tmp/rhncrap")
params, methodname = xmlrpclib.loads(fd.read())
os.unlink("/tmp/rhncrap")
else:
# Ummm...try real hard
params, methodname = xmlrpclib.loads(fd.read())
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://localhost/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("rawhide")
#print r.getObsoletes("rhel-i386-ws-4")
print r.getRPMName(packages[3])
print packages[3]
#print r._RHN__getFile("getPackage", "rhel-i386-ws-4", r.getRPMName(packages[4]))
print r.getPackage("rawhide", "Canna-libs-3.7p3-10.i386.rpm")
print r.solveDependencies(['/etc/ntp.conf'])
if __name__ == "__main__":
main()
More information about the Yum-devel
mailing list