On Wed, 2009-09-09 at 09:09 -0500, Tom Brown wrote: > > I promised to post the script I adapted for cloning errata from RHN > to > > my Spacewalk server. I'm sad to say that it's not a completed work > at > > this point, but does the basic things. Some things that are missing > > and/or are caveats:
Still caveats and changes. Read on. > > 1) Updating errata that affect another channel, should you add a > channel > > that might be affected by an existing errata. This should work. As of right now, you'll process errata from RHN one RHN-channel at-a-time. If you add a channel that has an erratum that affects channels you had before... it should be trivial. (See further comments below). > > 2) I've been a little lazy and have hard-coded my own RHN > credentials in > > the script, rather than asking the user for the info, passing it as > an > > argument, or reading it from a file. I'll get around to it later. I still haven't gotten around to it... I'm not sure I will. It's trivial to update the script with your data. > > 3) I would avoid errata publishing for the time-being. The > > functionality exists in the script, but it's not right. If you pull > > down an errata that's for both RHEL 4 & 5 (for instance).. you'll > end up > > with RHEL 5 packages in your RHEL 4 channels. I need to work this > out. Ok, I have come up with another method for dealing with automagic errata publishing upon import. The problem, as I see it, is that the API has no way of "merging" errata. So, to effectively import errata from RHN and have it meaningful for the appropriate channels, I've taken to breaking up each erratum. This avoids having packages meant for RHEL 5... "published" into RHEL 4 channels. For instance, if erratum RHSA:XXXX is relevant for say both 64-bit RHEL 4 and RHEL 5, it will be broken up into multiple individual errata. The way I'm doing this on my system (and it's configurable) is this: RHEL 5 64-bit: RHSA:XXXX:R5-64 RHEL 4 64-bit: RHSA:XXXX:R4-64 Yes... this can potential create a ton of errata on your system, but to ensure packages are automagically published to the appropriate channels, this is the only method I could come up with quickly. There may be a way in the future to better handle this via the API, but right now, it eludes me. > > 4) This is my first attempt at anything with Python.. so it's > probably > > quite horrible. I will be updating this as I develop more, not sure > if > > the Spacewalk maintainers want to add something like this to their > list > > of user-contributed scripts... but I'd be happy to maintain it > there, if > > so. I continue to flounder. > Hi Andy > > Do you have any basic useage examples of this please?? eg > > # python spw-clone-errata.py -l myuser -p mypass -c > rhel-x86_64-server-5 > spw-clone-errata.py:31: DeprecationWarning: the sets module is > deprecated > from sets import Set > try: spw-clone-errata.py --help First, I've removed the dependency on the old-n-busted "sets" module. But, usage examples. In the new script (attached), there are two important maps that you as a user will need to configure, if you choose to do this my way. 1) Map RHN channel to Spacewalk (SPW) channel: This map is simply a python dictionary whose keys are the RHN channel labels and whose values are YOUR SPW channel labels. My SPW labels match almost identically the RHN channels, so this was mostly meaningless for my setup, but I wanted the user to be able to be more flexible. What this does for you, is when you give the script the variable [-c --src-channel], which is the RHN channel from which you want to pull errata, the errata get mapped to your SPW channel that corresponds. For instance, in my setup: The RHN channel: 'rhel-x86_64-server-5' is mapped to my SPW channel with the same label. Too easy. But, the RHN channel: 'rhel-x86_64-as-4' is mapped to my SPW channel named: 'rhel-x86_64-server-4' 2) Map RHN channel to Errata suffix: This map is another dictionary whose keys are again the RHN channel labels and whose values are the suffixes that I want added to the "advisory" value of each erratum. This is as discussed above. For instance: RHN channel: 'rhel-x86_64-server-5' has this suffix mapped to it: 'R5-64' Kinda straight-forward. There may be many philosophical problems with this, but for now, until something in the API is changed (which I have no skill for), this is all I got. So... usage case. Let's discuss how I use Spacewalk with RHN. 1) My goal is to have two sets of RHEL channels. One set of "default" channels which contain every package ever released in a given channel on RHN, such as 'rhel-x86_64-server-5' .. The other set of channels are my "production" channels to which I clone relevant errata (and therefore package updates) from the "default" channels. This gives me release management control over packages via Spacewalk. Servers are only subscribed to "production" channels... as distros and kickstarts are only based on "prod" channels. 2) To do this, I am collecting the packages on my SPW server using mrepo (quite handy) and using spacewalk-repo-sync to get them into my channels. This is all scheduled via cron. (I need to work out some notifications on nightly updates). I'd like to find time to work on a patch for the SPW devs that handles any local packages differently. As of now, I basically have package duplication on my system. I pull the packages from RHN into local yum repos on my SPW server and then sync them into SPW, which copies them into the packages repository that SPW uses... I'd like to fix it so that it handles anything pulled locally (via file:// URLs) as links (sym or hard) rather than duplicating it. Pie-in-the-sky. 3) I'm just now finishing up development of this errata script, and I should be ready to go. To use this script, in my environment, I invoke it like this: # ./spw-clone-errata.py -s <server> -l <user> -p <pass> -c <RHN channel> -u Usage details: # ./spw-clone-errata.py -h usage: spw-clone-errata.py [options] options: -h, --help show this help message and exit -s SRC_SERVER, --spw-server=SRC_SERVER Spacewalk Server (spacewalk.mydomain.org) -l LOGIN, --login=LOGIN RHN Login -p PASSWD, --password=PASSWD RHN password -c SRC_CHANNEL, --src-channel=SRC_CHANNEL Source Channel Label: ie."rhel-x86_64-server-5" -b BDATE, --begin-date=BDATE Beginning Date: ie. "19000101" (defaults to "19000101") -e EDATE, --end-date=EDATE Ending Date: ie. "19001231" (defaults to TODAY) -u, --publish Publish Errata (into destination channels) -v, --verbose -q, --quiet ----- I've not quite completed the exact procedure for cloning these errata to "production" channels... that's next. Does this help at all? New script is attached. > thanks Sure... hope this is helpful. -- Andy Speagle "THE Student" - UCATS Wichita State University
#!/bin/env python # Script that uses RHN API to clone RHN Errata to Satellite # or Spacewalk server. # Copyright (C) 2008 Red Hat # # Author: Andy Speagle (andy.spea...@wichita.edu) # # This script was written based on the "rhn-clone-errata.py" # script written by: Lars Jonsson (ljons...@redhat.com) # # (THANKS!) # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Version Information: # # 0.1 - 2009-09-01 - Andy Speagle # # Initial release. Lots of problems. Oof. # # 0.2 - 2009-09-11 - Andy Speagle # # Updated methodology for handling errata. Breaking up individual # errata appended with a channel identifier to better automate publishing # of errata. # # Some code reworking. I still suck at python. Removed deprecated "sets" # module. import xmlrpclib from optparse import OptionParser from time import time, localtime, strftime import sys import os import re class RHNServer: def __init__(self,servername,user,passwd): self.rhnServerName = servername self.login = user self.password = passwd self.rhnUrl = 'https://'+self.rhnServerName+'/rpc/api' self.server = xmlrpclib.Server(self.rhnUrl) self.rhnSession = self.rhnLogin(self.login,self.password,0) def rhnLogin(self, login, password, retry): try: rhnSession=self.server.auth.login(login,password) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode==-20: self.rhnLogin(login,password,retry) else: print "Failed to login",f raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.rhnLogin(login,password, (retry + 1)) return rhnSession def getErrataChannels(self,advisory,retry): channels = [] try: details = self.server.errata.applicableToChannels(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.applicableToChannels(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataChannels(advisory, (retry + 1)) return channels def getErrataDetails(self,advisory,retry): details = [] try: details = self.server.errata.getDetails(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.getDetails(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataDetails(advisory, (retry + 1)) return details def getErrataKeywords(self,advisory,retry): keywords = [] try: keywords = self.server.errata.listKeywords(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.listKeywords(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: print "Error Getting Keywords : "+advisory except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataKeywords(advisory, (retry + 1)) return keywords def getErrataBugs(self,advisory,retry): bugs = [] try: bugs = self.server.errata.bugzillaFixes(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.bugzillaFixes(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: print "Error Getting Bugs : "+advisory except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataBugs(advisory, (retry + 1)) return bugs def getErrataCVEs(self,advisory,retry): cves=[] try: cves = self.server.errata.listCves(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.listCves(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: print "Error Getting CVEs : %s" % advisory except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataCVEs(advisory, (retry + 1)) return cves def getErrataPackages(self,advisory,retry): packages=[] try: packages = self.server.errata.listPackages(self.rhnSession,advisory) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.listPackages(self.rhnSession,advisory) elif f.faultCode == -208: if options.verbose: print "Errata %s Doesn't Exist on %s ..." % (advisory,self.rhnServerName) return [] else: print "Error Getting Packages : %s" % advisory except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.getErrataPackages(advisory, (retry + 1)) return packages def listChannelErrata(self,dest_chan,dateStart,dateEnd,retry): out = [] try: out = self.server.channel.software.listErrata(self.rhnSession,dest_chan,dateStart,dateEnd) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.channel.software.listErrata(self.rhnSession,dest_chan,dateStart,dateEnd) else: raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.listChannelErrata(dest_chan,dateStart,dateEnd,(retry + 1)) return out def findPackageChannels(self,pkgid,retry): channels=[] try: channels = self.server.packages.listProvidingChannels(self.rhnSession,pkgid) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.packages.listProvidingChannels(self.rhnSession,pkgid) else: print "Error Finding Channels for Package : %s" % pkgid except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.server.packages.findPackageChannels(pkgid, (retrun + 1)) return channels def cloneErrata(self,dest_chan,errata,retry): out=[] try: print "Clone errata in progress, please be patient.." out = self.server.errata.clone(self.rhnSession,dest_chan,errata) except xmlrpclib.Fault, f: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.self.server.errata.clone(self.rhnSession,dest_chan,errata) else: raise except xmlrpclib.ProtocolError, err: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.cloneErrata(dest_chan,errata, (retry + 1)) return out class SPWServer(RHNServer): def searchNVREA(self,name,version,release,epoch,archlabel,retry): package=[] try: package = self.server.packages.findByNvrea(self.rhnSession,name,version,release,epoch,archlabel) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.packages.findByNvrea(self.rhnSession,name,version,release,archlabel) else: print "Error Finding Package via NVREA : %s" % name except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.searchNVREA(name,version,release,epoch,archlabel, (retry + 1)) return package def listChannelErrata(self,dest_chan,retry): out = [] try: out = self.server.channel.software.listErrata(self.rhnSession,dest_chan) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d\tFault String: %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.channel.software.listErrata(self.rhnSession,dest_chan) else: raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.listChannelErrata(dest_chan,(retry + 1)) return out def errataPublish(self,name,channels,retry): errata=[] try: errata = self.server.errata.publish(self.rhnSession,name,channels) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d - %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.publish(self.rhnSession,name,channels) elif f.faultCode == 2601: print "Errata Already Exists..." return [] else: print "Error Creating Errata!" raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.errataPublish(name,channels, (retry + 1)) return errata def errataCreate(self,info,bugs,keywords,packages,publish,channels,retry): new_errata=[] try: new_errata = self.server.errata.create(self.rhnSession,info,bugs,keywords,packages,publish,channels) except xmlrpclib.Fault, f: if options.verbose: print "Fault Code: %d - %s" % (f.faultCode,f.faultString) if f.faultCode == -20: self.rhnLogin(self.login,self.password) return self.server.errata.create(self.rhnSession,info,bugs,keywords,packages,publish,channels) elif f.faultCode == 2601: print "Errata Already Exists..." return [] else: print "Error Creating Errata!" raise except xmlrpclib.ProtocolError, err: if options.verbose: print "ProtocolError: %d - %s" % (err.errcode,err.errmsg) if retry > 3: raise else: return self.errataCreate(info,bugs,keywords,packages,publish,channels, (retry + 1)) return new_errata def parse_args(): parser = OptionParser() parser.add_option("-s", "--spw-server", type="string", dest="src_server", help="Spacewalk Server (spacewalk.mydomain.org)") parser.add_option("-l", "--login", type="string", dest="login", help="RHN Login") parser.add_option("-p", "--password", type="string", dest="passwd", help="RHN password") parser.add_option("-c", "--src-channel", type="string", dest="src_channel", help="Source Channel Label: ie.\"rhel-x86_64-server-5\"") parser.add_option("-b", "--begin-date", type="string", dest="bdate", help="Beginning Date: ie. \"19000101\" (defaults to \"19000101\")") parser.add_option("-e", "--end-date", type="string", dest="edate", help="Ending Date: ie. \"19001231\" (defaults to TODAY)") parser.add_option("-u", "--publish", action="store_true", dest="publish", default=False, help="Publish Errata (into destination channels)") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False) parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False) (options,args) = parser.parse_args() return options def main(): global chanMap global chanSuffixMap global RHNServer global RHNUser global RHNPass global options options = parse_args() if (options.src_server and options.login and options.passwd) is None: print "try: "+sys.argv[0]+" --help" sys.exit(2) # I don't reckon this should change anytime soon... # svrRHN = 'rhn.redhat.com' # Ok, configure your RHN credentials here... # userRHN = 'FIXME' passRHN = 'FIXME' # Here we setup our mappings from RHN to Local software channels. # Set these to what you have created for your SPW. # They are paired as: # # RHNChannel: SPWChannel # chanMap = { 'rhel-x86_64-server-5': 'rhel-x86_64-server-5', 'rhn-tools-rhel-x86_64-server-5': 'rhel-x86_64-server-rhntools-5', 'rhel-x86_64-server-productivity-5': 'rhel-x86_64-server-productivity-5', 'rhel-x86_64-server-supplementary-5': 'rhel-x86_64-server-supplementary-5', 'rhel-x86_64-server-vt-5': 'rhel-x86_64-server-vt-5', 'rhel-i386-server-5': 'rhel-i386-server-5', 'rhn-tools-rhel-i386-server-5': 'rhel-i386-server-rhntools-5', 'rhel-i386-server-productivity-5': 'rhel-i386-server-productivity-5', 'rhel-i386-server-supplementary-5': 'rhel-i386-server-supplementary-5', 'rhel-i386-server-vt-5': 'rhel-i386-server-vt-5', 'rhel-x86_64-as-4': 'rhel-x86_64-server-4', 'rhel-x86_64-as-4-extras': 'rhel-x86_64-server-extras-4', 'rhn-tools-rhel-4-as-x86_64': 'rhel-x86_64-server-rhntools-4', 'rhel-i386-as-4': 'rhel-i386-server-4', 'rhel-i386-as-4-extras': 'rhel-i386-server-extras-4', 'rhn-tools-rhel-4-as-i386': 'rhel-i386-server-rhntools-4' }; # Here we also setup mappings from RHN channels to errata suffixes. # Since we can't easily publish automagically, while ensuring that # the right packages go into the right channels, we're going to # split multi-channel affecting errata into individual errata # that are suffixed with something meaningful that identifies # each sub-errata per channel... blah blah... Of course, modify this # as you will. # # RHNChannel: ErrataSuffix # chanSuffixMap = { 'rhel-x86_64-server-5': 'R5-64', 'rhn-tools-rhel-x86_64-server-5': 'R5-64-T', 'rhel-x86_64-server-productivity-5': 'R5-64-P', 'rhel-x86_64-server-supplementary-5': 'R5-64-S', 'rhel-x86_64-server-vt-5': 'R5-64-V', 'rhel-i386-server-5': 'R5-32', 'rhn-tools-rhel-i386-server-5': 'R5-32-T', 'rhel-i386-server-productivity-5': 'R5-32-P', 'rhel-i386-server-supplementary-5': 'R5-32-S', 'rhel-i386-server-vt-5': 'R5-32-V', 'rhel-x86_64-as-4': 'R4-64', 'rhel-x86_64-as-4-extras': 'R4-64-E', 'rhn-tools-rhel-4-as-x86_64': 'R4-64-T', 'rhel-i386-as-4': 'R4-32', 'rhel-i386-as-4-extras': 'R4-32-E', 'rhn-tools-rhel-4-as-i386': 'R4-32-T' }; if chanMap[options.src_channel] is None: print "Invalid Channel!" sys.exit(2) myRHN = RHNServer(svrRHN,userRHN,passRHN) mySPW = SPWServer(options.src_server,options.login,options.passwd) dateStart = options.bdate or '19000101' dateEnd = options.edate or strftime("%Y%m%d", localtime()) for rhnErrata in myRHN.listChannelErrata(options.src_channel,dateStart,dateEnd,0): if not options.quiet: print rhnErrata['errata_advisory'] # Now, let's check if we already have this errata locally... spwErrataName = rhnErrata['errata_advisory']+':'+chanSuffixMap[options.src_channel] spwErrCheck = mySPW.getErrataDetails (spwErrataName,0) if not spwErrCheck: # Ok, so the errata doesn't already exists... let's get busy creating it. spwErrSolution = "Before applying this update, make sure that all "+\ "previously-released errata relevant to your system have been applied." spwErrPackages = [] for pkg in myRHN.getErrataPackages(rhnErrata['errata_advisory'],0): pkgFind = mySPW.searchNVREA(pkg['package_name'],\ pkg['package_version'],\ pkg['package_release'],\ '',\ pkg['package_arch_label'],\ 0) for pkgChan in pkg['providing_channels']: if pkgChan != chanMap[options.src_channel]: continue else: if not pkgFind: print "Hmmm... Package Missing: %s" % pkg['package_name'] else: spwErrPackages.append(pkgFind[0]['id']) break spwErrDetails = myRHN.getErrataDetails(rhnErrata['errata_advisory'],0) spwErrKeywords = myRHN.getErrataKeywords(rhnErrata['errata_advisory'],0) spwErrBugs = [] tmpBugs = myRHN.getErrataBugs(rhnErrata['errata_advisory'],0) for bug in tmpBugs: spwErrBugs.append({'id': int(bug), 'summary': tmpBugs[bug]}) if not options.quiet: print "\t%s - %s" % (spwErrDetails['errata_issue_date'],spwErrDetails['errata_synopsis']) spwErrObject = mySPW.errataCreate ({ 'synopsis': spwErrDetails['errata_synopsis'],\ 'advisory_name': spwErrataName,\ 'advisory_release': 1,\ 'advisory_type': spwErrDetails['errata_type'],\ 'product': 'RHEL',\ 'topic': spwErrDetails['errata_topic'],\ 'description': spwErrDetails['errata_description'],\ 'references': spwErrDetails['errata_references'],\ 'notes': spwErrDetails['errata_notes'],\ 'solution': spwErrSolution },\ spwErrBugs,\ spwErrKeywords,\ spwErrPackages,\ options.publish,\ [chanMap[options.src_channel]],\ 0) print "\tErrata Created: %d" % spwErrObject['id'] else: if not options.quiet: print "\tErrata already exists. %s" % spwErrataName if __name__ == "__main__": main()
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Spacewalk-list mailing list Spacewalk-list@redhat.com https://www.redhat.com/mailman/listinfo/spacewalk-list