mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
f5ec73735f
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>
173 lines
5.2 KiB
Python
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()
|