Files
plugin-system-updates/system_updates.py
Matthew Howle 7204f9e9b9 Initial commit
2021-05-28 10:19:58 -04:00

162 lines
4.5 KiB
Python

from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
---
module: system_updates
short_description: Collect system updates as ansible_facts
description:
- Collects system updates from APT or Yum
'''
from ansible.module_utils.basic import AnsibleModule
HAVE_PYTHON_APT = False
HAVE_PYTHON_YUM = False
try:
import apt
import apt_pkg
HAVE_PYTHON_APT = True
except ImportError:
pass
try:
import yum
from yum.logginglevels import __NO_LOGGING
HAVE_PYTHON_YUM = True
except ImportError:
pass
def get_updates_apt():
"""Collect upgrades from APT"""
def is_critical_package(version):
for origin in version.origins:
if 'security' in origin.site.lower():
return True
if 'security' in origin.label.lower():
return True
return False
cache = apt.Cache(progress=None)
updated_packages = []
for pkg in cache:
for ver in pkg.versions:
if not ver.is_installed:
continue
candidate_ver = pkg.candidate
if pkg.is_upgradable:
updated_packages.append(dict(
name=pkg.name,
version=candidate_ver.version,
arch=candidate_ver.architecture,
category=candidate_ver.section,
origin=candidate_ver.origins[0].origin,
installed_version=ver.version,
critical=is_critical_package(candidate_ver),
description=ver.summary
))
return updated_packages
def get_updates_yum():
"""Collect upgrades from Yum"""
def get_installed_version(package_name, arch=None):
search_results = yb.rpmdb.searchNevra(name=package_name, arch=arch)
return search_results[0].version if search_results else None
def is_critical_update(metadata):
for ref in metadata['references']:
if ref['type'].lower() in ('cve', 'security'):
return True
if 'CVE' in ref['title']:
return True
return False
# Make yum quiet
import logging
# grep -EIohr "getLogger\([^)]+\)" /usr/lib/python2.7/site-packages/yum/
loggers = ['yum', 'yum.Depsolve', 'yum.filelogging', 'yum.filelogging.RPMInstallCallback',
'yum.filelogging.YumBase', 'yum.plugin', 'yum.Repos', 'yum.ReposStorage', 'yum.update_md', 'yum.verbose',
'yum.verbose.Depsolve', 'yum.verbose.plugin', 'yum.ProcessTrasactionBaseCallback', 'yum.verbose.Repos',
'yum.verbose.update_md', 'yum.verbose.YumBase', 'yum.verbose.YumPlugins', 'yum.YumBase']
for name in loggers:
logger = logging.getLogger(name)
logger.setLevel(__NO_LOGGING)
yb = yum.YumBase()
yb.setCacheDir()
pkglist = yb.doPackageLists(pkgnarrow='updates')
umd = yum.update_md.UpdateMetadata()
repos = []
for update in pkglist.updates:
if update.repo not in repos:
repos.append(update.repo)
try:
umd.add(update.repo)
except yum.Errors.RepoMDError:
pass
updated_packages = []
for update in pkglist.updates:
critical_update = False
notice = umd.get_notice((update.name, update.ver, update.rel))
if notice:
metadata = notice.get_metadata()
critical_update = is_critical_update(metadata)
candidate = dict(
name=update.name,
version=update.version,
release=update.release,
epoch=update.epoch,
arch=update.arch,
installed_version=get_installed_version(update.name, update.arch),
critical=critical_update,
description=update.description
)
updated_packages.append(candidate)
return updated_packages
def get_updates():
if HAVE_PYTHON_APT:
return get_updates_apt()
if HAVE_PYTHON_YUM:
return get_updates_yum()
return None
def main():
module = AnsibleModule(argument_spec=dict(),
supports_check_mode=True)
results = dict()
facts = dict()
updates = get_updates()
if updates is None:
results['skipped'] = True
results['msg'] = 'WARNING: Could not obtain updates'
else:
facts = updates
results['changed'] = False
results['ansible_facts'] = {'system_updates': facts }
module.exit_json(**results)
if __name__ == '__main__':
main()