Initial commit of system_updates
This commit is contained in:
161
system_updates.py
Normal file
161
system_updates.py
Normal file
@@ -0,0 +1,161 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user