You could use the Susemanager API to accomplish that. It should work with traditional Spacewalk Clients and with Salt Clients.
I’ve created a small Example for you
#!/usr/bin/python
import xmlrpclib
from optparse import OptionParser, OptionGroup
MANAGER_URL = "http://manager.example.com/rpc/api"
MANAGER_LOGIN = "username"
MANAGER_PASSWORD = "password"
def main():
if options.server != '0':
sm = susemanager(options.user, options.passw, options.url)
sm.patchStatus(options.server)
else:
print "No Parameters specified! Use --help!"
class susemanager(object):
def __init__(self, user, password, url):
self.client = xmlrpclib.Server(url, verbose=0)
self.key = self.client.auth.login(user, password)
def __del__(self):
self.client.auth.logout(self.key)
self.client=""
self.key=""
#### SM - FUNCTIONS
### getSysId - Function
### - Parameter is Name of the System in Susemanager (STRING)
### - Returns the internal SystemID from Susemanager
### - SystemID is needed for other Functions
def getSysId (self, name):
system = self.client.system.getId(self.key, name)
systemid = system[0]['id']
return systemid
def listSystems(self):
systems = self.client.system.listSystems(self.key)
return systems
### getRelevantPatchesByType - Function
### - Parameter is Name of the System in Susemanager (STRING) and Patch - Type ('Security Advisory', 'Product Enhancement Advisory', 'Bug Fix Advisory')
### - Gets SystemId, Patch List and returns the Elements on the List
def getRelevantPatchesByType(self,name, type):
systemid = self.getSysId (name)
errata = self.client.system.getRelevantErrataByType(self.key, systemid, type)
return errata
### patchStatus - Function
### - Parameter is Name of the System in Susemanager (STRING)
### - Prints Current Patchstatus for the specified System as Output
def patchStatus (self, name):
security = self.getRelevantPatchesByType(name, 'Security Advisory')
crit = 0
crit_list = []
mod = 0
mod_list = []
imp = 0
imp_list = []
low = 0
low_list = []
for patch in security: ### Loop over the Result
if patch['advisory_synopsis'].find('critical') > -1:
crit += 1
crit_list.append(patch)
elif patch['advisory_synopsis'].find('important') > -1:
imp += 1
imp_list.append(patch)
elif patch['advisory_synopsis'].find('moderate') > -1:
mod += 1
mod_list.append(patch)
elif patch['advisory_synopsis'].find('low') > -1:
low += 1
low_list.append(patch)
enhancements = self.getRelevantPatchesByType(name, 'Product Enhancement Advisory')
bugfix = self.getRelevantPatchesByType(name, 'Bug Fix Advisory')
print "############################################################################"
print "### System Summary - %s " % (name)
print "############################################################################"
print "### Critical: %s Important: %s Moderate: %s Low: %s " % (crit, imp, mod, low)
print "### Bugfix: %s Enhancement: %s " % (len(bugfix), len(enhancements))
print "############################################################################"
print ""
print "Critical Patches:"
print "############################################################################"
for critcal in crit_list:
print critcal['advisory_name']+' - '+critcal['advisory_synopsis']
print ""
print "Important Patches:"
print "############################################################################"
for important in imp_list:
print important['advisory_name']+' - '+important['advisory_synopsis']
print ""
print "Moderate Patches:"
print "############################################################################"
for moderate in mod_list:
print moderate['advisory_name']+' - '+moderate['advisory_synopsis']
print ""
print "Low Patches:"
print "############################################################################"
for lows in low_list:
print lows['advisory_name']+' - '+lows['advisory_synopsis']
print ""
print "Bugfix Patches:"
print "############################################################################"
for sbugfix in bugfix:
print sbugfix['advisory_name']+' - '+sbugfix['advisory_synopsis']
print ""
print "Enhancement Patches:"
print "############################################################################"
for enh in mod_list:
print enh['advisory_name']+' - '+enh['advisory_synopsis']
parser = OptionParser()
usage = "usage: %prog [options]"
parser.add_option("--server", dest="server", default='0',
help="Patchstatus for single Server", metavar="SERVER")
parser.add_option("--url", dest="url", default=MANAGER_URL,
help="Susemanager API URL", metavar="URL")
parser.add_option("--user", dest="user", default=MANAGER_LOGIN,
help="Susemanager API User", metavar="USER")
parser.add_option("--pass", dest="passw", default=MANAGER_PASSWORD,
help="Susemanager API Password", metavar="PASS")
(options, args) = parser.parse_args()
#### Default Call to main() Function
if __name__ == "__main__":
main()
Example:
USAGE: <scriptname>.py --server=<name>
XXXXXX:/tmp # ./patchStatus.py --server=XXXXXXXXXXX
############################################################################
### System Summary - XXXXXXXXXXXXX
############################################################################
### Critical: 0 Important: 0 Moderate: 1 Low: 0
### Bugfix: 2 Enhancement: 0
############################################################################
Critical Patches:
############################################################################
Important Patches:
############################################################################
Moderate Patches:
############################################################################
SUSE-12-SP1-2017-150 - moderate: Security update for pcsc-lite
Low Patches:
############################################################################
Bugfix Patches:
############################################################################
SUSE-12-SP1-2017-156 - Recommended update for yast2-ruby-bindings
SUSE-12-SP1-2017-151 - Recommended update for kernel-firmware
Enhancement Patches:
############################################################################
SUSE-12-SP1-2017-150 - moderate: Security update for pcsc-lite