#!/usr/bin/python #author : Felix Dewaleyne #version : 1.2.2 #will work for 5.4 and 5.5 # 1.2 : fixed genation of the repodata for all channels and moved to using warnings.warn for warnings # 1.2.1 : it can't work for 5.3 as the main call used isn't part of the api. # 1.2.2 : inclusion of patches suggested (change the timestamps instead of removing the repodata) ### # To the extent possible under law, Red Hat, Inc. has dedicated all copyright to this software to the public domain worldwide, pursuant to the CC0 Public Domain Dedication. # This software is distributed without any warranty. See . ### import xmlrpclib, sys, getpass, ConfigParser, os, optparse, warnings, stat #global variables client=None; SATELLITE_LOGIN=None; config = ConfigParser.ConfigParser() config.read(['.satellite', os.path.expanduser('~/.satellite'), '/etc/sysconfig/rhn/satellite']) # this will initialize a session and return its key. # for security reason the password is removed from memory before exit, but we want to keep the current username. def session_init(orgname='baseorg'): global client; global config; global SATELLITE_LOGIN; if config.has_section(orgname) and config.has_option(orgname,'username') and config.has_option(orgname,'password') and config.has_option('baseorg','url'): SATELLITE_LOGIN = config.get(orgname,'username') SATELLITE_PASSWORD = config.get(orgname,'password') SATELLITE_URL = config.get('baseorg','url') else: if not config.has_option('baseorg','url'): sys.stderr.write("enter the satellite url, such as https://satellite.example.com/rpc/api") sys.stderr.write("\n") SATELLITE_URL = raw_input().strip() else: SATELLITE_URL = config.get('baseorg','url') sys.stderr.write("Login details for %s\n\n" % SATELLITE_URL) sys.stderr.write("Login: ") SATELLITE_LOGIN = raw_input().strip() # Get password for the user SATELLITE_PASSWORD = getpass.getpass(prompt="Password: ") sys.stderr.write("\n") #inits the connection client = xmlrpclib.Server(SATELLITE_URL, verbose=0) key = client.auth.login(SATELLITE_LOGIN, SATELLITE_PASSWORD) # removes the password from memory del SATELLITE_PASSWORD return key def print_channels(key): global client; print "Channsls:" print "\t[ Label - name ]" try: for channel in client.channel.listSoftwareChannels(key): print "\t- "+channel['label']+" - "+channel['name'] except: warnings.warn("error trying to list channels") raise def regen_channel(key,force,channel=None): # this should be enough to ask the satellite to regenerate the yum cache - the repodata - but removing the /var/cache/rhn/repodata then running this might give better results (especially if need to force). if force: #TODO : add option to empty the list of regeneration required. print "removing previous content to force regeneration" import shutil,os folder = '/var/cache/rhn/repodata' if channel == None: for entry in os.listdir(folder): entry_path = os.path.join(folder,entry) if os.path.isdir(entry_path): setback_repomd_timestamp(entry_path) else: setback_repomd_timestamp(os.path.join(folder,channel)) if channel == None: print "requesting global regeneration of the repodata" for entry in client.channel.listAllChannels(key): try: client.channel.software.regenerateYumCache(key,entry['label']) print "successfully queued "+entry['label'] except: warnings.warn("error trying to request the repodata regeneration for "+entry['label']) pass try: client.channel.software.regenerateNeededCache(key) print "errata and package cache for all systems has been regenerated" except: warnings.warn("an exception occured durring the regenerateNeededCache call!") raise else: print "requesting that the repodata would be regenerated for "+channel try: client.channel.software.regenerateYumCache(key,channel) print "repodata should regenerate over the next 15 minutes for "+channel except: warnings.warn( "error trying to request the repodata regeneration for "+channel) raise try: client.channel.software.regenerateNeededCache(key,channel) print "errata and package cache for all systems subscribed to channel "+channel+" has been regenerated" except: warnings.warn( "an exception occured durring the regenerateNeededCache call!") raise def setback_repomd_timestamp(repocache_path): repomd_file = (repocache_path + '/repomd.xml') stat_info = os.stat(repomd_file) mtime = stat_info[stat.ST_MTIME] new_mtime = mtime - 3600 try: os.utime(repomd_file, (new_mtime, new_mtime)) except OSError, e: warnings.warn("error setting back timestamp on %s: %s" % (repomd_file, e.strerror)) def main(): parser = optparse.OptionParser("usage : %prog -c channelname|-l|-a [-f]") parser.add_option("-l", "--list", dest="listing", help="List all channels and quit", action="store_true") parser.add_option("-c", "--channel", dest="channel", help="Label of the channel to querry regeneration for") parser.add_option("-a",action="store_true",dest="regen_all",help="Causes a global regeneration instead of just one channel") parser.add_option("-f",action="store_true",dest="force_operation",help="Forces the operation ; can only work if the script is run on the satellite itself",default=False) #todo : add -F to make the changes directly into the database. will work with satellite 5.3 (options, args) = parser.parse_args() if options.listing: key = session_init() print_channels(key) client.auth.logout(key) elif options.regen_all: key = session_init() regen_channel(key,options.force_operation) client.auth.logout(key) elif options.channel: key = session_init() regen_channel(key,options.force_operation,options.channel) client.auth.logout(key) else: parser.error('no action given') #calls start here if __name__=="__main__": main()