Hi Team,

I've found and squashed a *ahem* glaring bug in the last release of my
RHN errata cloning script.

Version 0.3 attached.
-- 
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.
#
# 0.3 - 2009-09-17 - Andy Speagle
#
#       Fixed a rather glaring bug in the logic regarding relevant channel
#       for package selection.  Ugh.

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 = 'USER'
    passRHN = 'PASS'

#   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 != 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()

Attachment: 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

Reply via email to