1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/packaging/os/yum_versionlock.py
patchback[bot] 1f522c414e
[PR #4183/f5ec7373 backport][stable-4] yum_versionlock: Fix entry matching (#4228)
* yum_versionlock: Fix entry matching (#4183)

As an input the module receives names of packages to lock.
Those never matched existing entries and therefore always reported
changes.

For compatibility yum is symlinked to dnf on newer systems,
but versionlock entries defer. Try to parse both formats.

Signed-off-by: Florian Achleitner <flo@fopen.at>
(cherry picked from commit f5ec73735f)

* Empty commit to trigger CI.

Co-authored-by: fachleitner <flo@fopen.at>
Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-18 23:19:39 +01:00

173 lines
5.2 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Florian Paul Hoberg <florian.hoberg@credativ.de>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
---
module: yum_versionlock
version_added: 2.0.0
short_description: Locks / unlocks a installed package(s) from being updated by yum package manager
description:
- This module adds installed packages to yum versionlock to prevent the package(s) from being updated.
options:
name:
description:
- Package name or a list of package names with optional wildcards.
type: list
required: true
elements: str
state:
description:
- If state is C(present), package(s) will be added to yum versionlock list.
- If state is C(absent), package(s) will be removed from yum versionlock list.
choices: [ 'absent', 'present' ]
type: str
default: present
notes:
- Requires yum-plugin-versionlock package on the remote node.
- Supports C(check_mode).
requirements:
- yum
- yum-versionlock
author:
- Florian Paul Hoberg (@florianpaulhoberg)
- Amin Vakil (@aminvakil)
'''
EXAMPLES = r'''
- name: Prevent Apache / httpd from being updated
community.general.yum_versionlock:
state: present
name: httpd
- name: Prevent multiple packages from being updated
community.general.yum_versionlock:
state: present
name:
- httpd
- nginx
- haproxy
- curl
- name: Remove lock from Apache / httpd to be updated again
community.general.yum_versionlock:
state: absent
package: httpd
'''
RETURN = r'''
packages:
description: A list of package(s) in versionlock list.
returned: success
type: list
elements: str
sample: [ 'httpd' ]
state:
description: State of package(s).
returned: success
type: str
sample: present
'''
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from fnmatch import fnmatch
# on DNF-based distros, yum is a symlink to dnf, so we try to handle their different entry formats.
NEVRA_RE_YUM = re.compile(r'^(?P<exclude>!)?(?P<epoch>\d+):(?P<name>.+)-'
r'(?P<version>.+)-(?P<release>.+)\.(?P<arch>.+)$')
NEVRA_RE_DNF = re.compile(r"^(?P<exclude>!)?(?P<name>.+)-(?P<epoch>\d+):(?P<version>.+)-"
r"(?P<release>.+)\.(?P<arch>.+)$")
class YumVersionLock:
def __init__(self, module):
self.module = module
self.params = module.params
self.yum_bin = module.get_bin_path('yum', required=True)
def get_versionlock_packages(self):
""" Get an overview of all packages on yum versionlock """
rc, out, err = self.module.run_command([self.yum_bin, "versionlock", "list"])
if rc == 0:
return out
elif rc == 1 and 'o such command:' in err:
self.module.fail_json(msg="Error: Please install rpm package yum-plugin-versionlock : " + to_native(err) + to_native(out))
self.module.fail_json(msg="Error: " + to_native(err) + to_native(out))
def ensure_state(self, packages, command):
""" Ensure packages state """
rc, out, err = self.module.run_command([self.yum_bin, "-q", "versionlock", command] + packages)
if rc == 0:
return True
self.module.fail_json(msg="Error: " + to_native(err) + to_native(out))
def match(entry, name):
m = NEVRA_RE_YUM.match(entry)
if not m:
m = NEVRA_RE_DNF.match(entry)
if not m:
return False
return fnmatch(m.group("name"), name)
def main():
""" start main program to add/remove a package to yum versionlock"""
module = AnsibleModule(
argument_spec=dict(
state=dict(default='present', choices=['present', 'absent']),
name=dict(required=True, type='list', elements='str'),
),
supports_check_mode=True
)
state = module.params['state']
packages = module.params['name']
changed = False
yum_v = YumVersionLock(module)
# Get an overview of all packages that have a version lock
versionlock_packages = yum_v.get_versionlock_packages()
# Ensure versionlock state of packages
packages_list = []
if state in ('present', ):
command = 'add'
for single_pkg in packages:
if not any(match(pkg, single_pkg) for pkg in versionlock_packages.split()):
packages_list.append(single_pkg)
if packages_list:
if module.check_mode:
changed = True
else:
changed = yum_v.ensure_state(packages_list, command)
elif state in ('absent', ):
command = 'delete'
for single_pkg in packages:
if any(match(pkg, single_pkg) for pkg in versionlock_packages.split()):
packages_list.append(single_pkg)
if packages_list:
if module.check_mode:
changed = True
else:
changed = yum_v.ensure_state(packages_list, command)
module.exit_json(
changed=changed,
meta={
"packages": packages,
"state": state
}
)
if __name__ == '__main__':
main()