#!/usr/bin/python from pprint import pprint import datetime import time import xmlrpclib import os import re import sys import getpass from commands import getoutput #from distutils.version import LooseVersion from rpmUtils.miscutils import compareEVR from rpmUtils.miscutils import splitFilename args = len(sys.argv) - 1 if(args <> 1): print 'Missing Argument' print sys.argv[0], 'ServerName' print 'Eg: ' + sys.argv[0] + ' server-name' sys.exit (1) servername = sys.argv[1] RHS_Server = 'satellite.example.com' # create connection SATELLITE_URL = "http://" + RHS_Server + "/rpc/api" SATELLITE_LOGIN = getoutput("logname") SATELLITE_PASSWORD = getpass.getpass("Satellite password for " + SATELLITE_LOGIN + ": ") client = xmlrpclib.Server(SATELLITE_URL, verbose=0) key = client.auth.login(SATELLITE_LOGIN, SATELLITE_PASSWORD) # get system id system = client.system.getId(key,servername) serverId = system[0].get('id') print 'Server: ' + servername print 'ServerId: ' + str(serverId) ################################################################################ # Naming: # # base_channel: base channel of orig_channels or clone_channels. # # child_channels: child_channels of orig_channels or clone_channels # # orig channels: channels provided by red hat, eg. rhel-x86_64-server-6, # rhel-x86_64-server-optional-6 , ... # # clone channels: the cloned channels. ################################################################################ # Get subscribable base channels for the server, # if current_base=1, then its the current base channel base_channels = client.system.listSubscribableBaseChannels(key,serverId) for base in base_channels: if base.get('current_base') == 1: base_channel_server = base.get('label') print 'Cloned Base Channel: ', base_channel_server break # get child channels for the server child_channels = client.system.listSubscribedChildChannels(key,serverId) child_channels_server = [] for channel in child_channels: print ' Cloned Child Channel: ', channel.get('label') child_channels_server.append(channel.get('label')) ################################################################################ # get orig channels, the clone original, which itself has no 'clone_original' def getRootClone(label): root = '' details = client.channel.software.getDetails(key,label) if details.get('clone_original') == '': root = details.get('label') else: root = getRootClone(details.get('clone_original')) return root base_channel_orig = '' base_channel_orig = getRootClone(base_channel_server) print 'Original Base Channel: ', base_channel_orig # problem: # newest: # pcp-testsuite-3.8.4-2.el6.x86_64 Extra Packages for Enterprise Linux 6 - x86_64 # - or - # pcp-testsuite-3.9.4-5.el6.x86_64 RHEL Server Optional (v. 6 64-bit x86_64) # # -> remove epel channel, to be save # found a way to compare versions, -> no "need" to remove epel. child_channels_orig = [] for channel in child_channels_server: root_clone = getRootClone(channel) # if root_clone.startswith('epel'): # print 'Not adding ' + root_clone # else: # child_channels_orig.append(getRootClone(channel)) new_child = getRootClone(channel) print ' Original Child Channel: ', new_child child_channels_orig.append(new_child) channels_orig = child_channels_orig channels_orig.insert(0,base_channel_orig) ################################################################################ # compare pkgid # get latest pkgids for orig channels def pkg_ids_orig(channels_orig): ids = [] for channel in channels_orig: orig = client.channel.software.listLatestPackages(key,channel) for pkg in orig: ids.append(pkg.get('id')) return ids ids_orig = pkg_ids_orig(channels_orig) # get running kernel of system running_kernel = client.system.getRunningKernel(key,serverId) #print 'Running Kernel ', running_kernel #kernel_pkg = client.packages.search.name(key,running_kernel) #print kernel_pkg # get EVR for kernel running_kernel_split = splitFilename(running_kernel + '.rpm') #print running_kernel_split running_kernel_EVR = ( running_kernel_split[3] , running_kernel_split[1], running_kernel_split[2]) running_kernel_name_arch = 'kernel-' + running_kernel_split[4] #print running_kernel_EVR #print running_kernel_name_arch running_kernel_pkg = client.packages.findByNvrea(key,'kernel',running_kernel_split[1],running_kernel_split[2],running_kernel_split[3],running_kernel_split[4]) #print running_kernel_pkg running_kernel_pkg_id = running_kernel_pkg[0].get('id') # get pkgids of the server/clone channels pkgs_clone_server = client.system.listPackages(key,serverId) unknown_nr = 0 ids_clone_server = [] dict_clone_server_tup = {} def pkg_ids_clone_server(pkgs_clone_server): global unknown_nr # ids = [] # system.listPackages does not return pkd_id, get it, # and find out which pkg is not part of a RH channel (has not id?) for pkg in pkgs_clone_server: details = client.packages.findByNvrea(key, pkg.get('name'), pkg.get('version'), pkg.get('release'), pkg.get('epoch'), pkg.get('arch')) try: # ids.append(details[0].get('id')) ids_clone_server.append(details[0].get('id')) tup = (pkg.get('epoch'),pkg.get('version'),pkg.get('release'),details[0].get('id')) dict_clone_server_tup[pkg.get('name') + '-' + pkg.get('arch')] = tup except IndexError: print "Unknown Package: " + pkg.get('name') + ' ' \ + pkg.get('version') + ' ' + pkg.get('release') + ' ' \ + pkg.get('arch') unknown_nr = unknown_nr + 1 # return ids pkg_ids_clone_server(pkgs_clone_server) #ids_clone_server = pkg_ids_clone_server(pkgs_clone_server) # we only care about package(ids) which are outdated, # which means they are in ids_clone_server but not in ids_orig # ids_orig might be wrong! # eg for libsoup, (' ', '2.34.3', '2.el6', 65450) (' ', '2.34.3', '3.el6_6', 77944) there are two 'latest' pkgs # we have to do this late when the list is cleaned up # ids_clone_outdated = list(set(ids_clone_server) - set(ids_orig)) # print list(set(ids_orig)) ################################################################################ # find updates for the outdated pkgids # get orig pkgs # almost duplicate of: pkg_ids_orig(channels_orig) def get_pkgs_orig_latest(channels_orig): pkgs = [] for channel in channels_orig: pkgs_channel = client.channel.software.listLatestPackages(key,channel) pkgs = pkgs + pkgs_channel return pkgs pkgs_orig_latest = get_pkgs_orig_latest(channels_orig) # more problems: # wireshark-gnome-1.8.10-8.el6_6.x86_64.rpm rhel-x86_64-server-6 # - or - # wireshark-gnome-1.2.15-2.el6_2.1.x86_64.rpm rhel-x86_64-server-optional-6 # - the package changed the channel, and has some versioning voodoo attached. # so we have two "latest" packages, what a *. # it's probably better to build a dict first, to speed up searching. dict_orig_latest_tup = {} for pkg in pkgs_orig_latest: name = pkg.get('name') version = pkg.get('version') arch_label = pkg.get('arch_label') epoch = pkg.get('epoch') release = pkg.get('release') id = pkg.get('id') # make epoch,version,release,id tupel tup = (epoch,version,release,id) if name + '-' + arch_label in dict_orig_latest_tup: # need to check which is newer old_tup = dict_orig_latest_tup[name + '-' + arch_label] result = compareEVR(tup[0:3],old_tup[0:3]) if result > 0: dict_orig_latest_tup[name + '-' + arch_label] = tup else: dict_orig_latest_tup[name + '-' + arch_label] = tup # extrakt ids from dict_orig_latest_tup ids_orig_compared = [] for entry in dict_orig_latest_tup: tup = dict_orig_latest_tup[entry] ids_orig_compared.append(tup[3]) # print "Newest check" # print list(set(ids_orig) - set(ids_orig_compared)) # ids_clone_outdated = list(set(ids_clone_server) - set(ids_orig)) ids_clone_outdated = list(set(ids_clone_server) - set(ids_orig_compared)) def find_in_pkgs_orig_latest(name,version,arch): # even newer # if name == 'libsoup': # print 'In find_in_pkgs_orig_latest 1' # print name + '-' + version + '-' + release + arch_label + '-' + str(id) # print dict_orig_latest_tup[name + '-' + arch_label] if name + '-' + arch in dict_orig_latest_tup: # if name == 'libsoup': # print "In find_in_pkgs_orig_latest 2" # print name + '-' + version + '-' + release + arch_label + '-' + str(id) # print dict_orig_latest_tup[name + '-' + arch_label] return dict_orig_latest_tup[name + '-' + arch][3] print 'Warning no ', name + '-' + arch + ' in dict_orig_latest_tup' # new # only short checking # if name + '-' + version + '-' + arch in dict_orig_latest_long: # print 'New long' # return dict_orig_latest_long[name + '-' + version + '-' + arch] ## if name + '-' + arch in dict_orig_latest_short: # print 'New short' ## return dict_orig_latest_short[name + '-' + arch] ######### # # old # print 'OLD' # a = [name,version,arch] # b = [name,arch] # print a # # check if pkg with same 'version' is there # for pkg in pkgs_orig_latest: # if [pkg.get('name'), pkg.get('version'), pkg.get('arch_label')] == a: # print 'Old long' # return pkg.get('id') # # if 'version' is changed, lookup without version number. # # eg. tzdata-2014h-1.el6.noarch -> tzdata-2014j-1.el6.noarch # for pkg in pkgs_orig_latest: # if [pkg.get('name'), pkg.get('arch_label')] == b: ## print 'Old short' # return pkg.get('id') # find updates for ids_clone_outdated # and build a dict to find intermediate updates ids_orig_updates = [] dict_orig_updates = {} for pkgid in ids_clone_outdated: details = client.packages.getDetails(key,pkgid) name = details.get('name') arch_label = details.get('arch_label') version = details.get('version') release = details.get('release') # if name == 'libsoup': # print 'In for pkgid in ids_clone_outdated' # print name + '-' + version + '-' + release + arch_label + '-' + str(id) # print dict_orig_latest_tup[name + '-' + arch_label] # print ids_orig_updates.append(find_in_pkgs_orig_latest(name, version,arch_label)) tmpl = [ version + '-' + release , pkgid ] dict_orig_updates[name + '-' + arch_label] = tmpl ################################################################################ # build a list of all erratas for the outdated pkgids errata_list = [] for pkgid in ids_clone_outdated: details = client.packages.getDetails(key,pkgid) pid = find_in_pkgs_orig_latest(details.get('name'), details.get('version'), details.get('arch_label')) if pid == None: print 'Did not find new id for: ' + details.get('name') + ' ' \ + details.get('version') + ' ' \ + details.get('arch_label') continue try: erratas = client.packages.listProvidingErrata(key,pid) except TypeError: print 'No errata for: ' + details.get('name') for errata in erratas: advisory = errata.get('advisory') # only RH (not cloned advisories wanted) if advisory.startswith("RH"): errata_list.append(advisory) # only FEDORA-EPEL (not cloned advisories wanted) if advisory.startswith("FEDORA-EPEL"): errata_list.append(advisory) # no duplicates, please. errata_list = list(set(errata_list)) ################################################################################ # find intermediate updates # we have to check all packages. all_pkg_orig = [] for channel in channels_orig: pkgs_channel = client.channel.software.listAllPackages(key,channel) # print 'Get all pkgs for: ' + channel + ' count: ' + str(len(pkgs_channel)) all_pkg_orig.extend(pkgs_channel) #print 'Nr of pkgs: ' + str(len(all_pkg_orig)) # extract needed info and build a dict. # supposing higer id = newer # bug: all packages in list, but only newer packages needed dict_orig_inter = {} for pkg in all_pkg_orig: name = pkg.get('name') arch_label = pkg.get('arch_label') if name + '-' + arch_label in dict_orig_updates: # check if version is higher version = pkg.get('version') release = pkg.get('release') epoch = pkg.get('epoch') # should compare by EVR, not id tup = (epoch,version,release) result = compareEVR(tup,dict_clone_server_tup[name + '-' + arch_label][0:3]) if result > 0: # if pkg.get('id') > (dict_orig_updates[name + '-' + arch_label][1]): id = pkg.get('id') # forget older kernels if name + '-' + arch_label == running_kernel_name_arch: if running_kernel_pkg_id >= id: continue if name + '-' + arch_label in dict_orig_inter: dict_orig_inter[name + '-' + arch_label].append([version + '-' + release, id]) else: dict_orig_inter[name + '-' + arch_label] = [[version + '-' + release, id]] #pprint(dict_orig_inter) ################################################################################ # print erratas and their packages ad_nr = 0 pkg_nr = 0 RHSA_d = { 'Low': 0, 'Moderate': 0, 'Important': 0, 'Critical': 0 } RHSA_nr = 0 RHBA_nr = 0 RHEA_nr = 0 errata_i = [] RHSA_i_d = { 'Low': 0, 'Moderate': 0, 'Important': 0, 'Critical': 0 } RHSA_i_nr = 0 RHBA_i_nr = 0 RHEA_i_nr = 0 FEDORA_EPEL_nr = 0 seen_erratas = [] for errata in errata_list: if errata in seen_erratas: errata_new = False else: seen_erratas.append(errata) errata_new = True if errata_new: ad_nr = ad_nr + 1 details = client.errata.getDetails(key,errata) errata_type = details.get('type') errata_synopsis = details.get('synopsis') if errata.startswith("RHSA"): RHSA_nr = RHSA_nr + 1 RHSA_d[errata_synopsis.split(':')[0]] += 1 if errata.startswith("RHBA"): RHBA_nr = RHBA_nr + 1 if errata.startswith("RHEA"): RHEA_nr = RHEA_nr + 1 if errata.startswith("FEDORA-EPEL"): FEDORA_EPEL_nr = FEDORA_EPEL_nr + 1 pkgs = client.errata.listPackages(key,errata) print str(ad_nr) + ': ' + errata + ' ' + errata_type + ' ' + errata_synopsis for pkg in pkgs: if pkg.get('id') in ids_orig_updates: pkg_nr = pkg_nr + 1 print ' ' + str(pkg_nr) + ': ' + pkg.get('name') + '-' \ + pkg.get('version') + '-' + pkg.get('release') + '.' \ + pkg.get('arch_label') # + ' ' + str(pkg.get('id')) # print errata for intermediate pkgs if pkg.get('name') + '-' + pkg.get('arch_label') in dict_orig_inter: list_inter = dict_orig_inter[pkg.get('name') + '-' + pkg.get('arch_label')] else: print pkg.get('name') + '-' + pkg.get('arch_label') + ' not found' continue for inter in reversed(list_inter): if inter[1] <> pkg.get('id'): print ' Superseding version: ' + inter[0] + '.' + pkg.get('arch_label') errata_inter = client.packages.listProvidingErrata(key,inter[1]) for errata_item in errata_inter: advisory = errata_item.get('advisory') if advisory.startswith("RH"): synopsis = errata_item.get('synopsis') print ' From: ' + advisory + ' ' + errata_item.get('type') + ' ' + synopsis errata_i.append(advisory) # summary errata_i = list(set(errata_i)) for errata in errata_i: if errata.startswith("RHSA"): RHSA_i_nr = RHSA_i_nr + 1 erratum = client.errata.getDetails(key,errata) synopsis = erratum.get('synopsis') RHSA_i_d[synopsis.split(':')[0]] += 1 if errata.startswith("RHBA"): RHBA_i_nr = RHBA_i_nr + 1 if errata.startswith("RHEA"): RHEA_i_nr = RHEA_i_nr + 1 print print 'Summary for Server ' + servername + ':' print str(ad_nr) + ' Errata' print ' ' + str(RHSA_nr) + ' Security Advisory' print ' ' + str(RHSA_d['Critical']) + ' Critical' print ' ' + str(RHSA_d['Important']) + ' Important' print ' ' + str(RHSA_d['Moderate']) + ' Moderate' print ' ' + str(RHSA_d['Low']) + ' Low' print ' ' + str(RHBA_nr) + ' Bug Fix Advisory' print ' ' + str(RHEA_nr) + ' Product Enhancement Advisory' print ' ' + str(FEDORA_EPEL_nr) + ' EPEL Advisory' print str(len(errata_i)) + ' Superseded Errata' print ' ' + str(RHSA_i_nr) + ' Superseded Security Advisory' print ' ' + str(RHSA_i_d['Critical']) + ' Critical' print ' ' + str(RHSA_i_d['Important']) + ' Important' print ' ' + str(RHSA_i_d['Moderate']) + ' Moderate' print ' ' + str(RHSA_i_d['Low']) + ' Low' print ' ' + str(RHBA_i_nr) + ' Superseded Bug Fix Advisory' print ' ' + str(RHEA_i_nr) + ' Superseded Product Enhancement Advisory' print str(pkg_nr) + ' Packages' print str(unknown_nr) + ' Unknown Packages (3rd party)'