From e33875e3825696f866a97af878716e682014e3a0 Mon Sep 17 00:00:00 2001 From: Robin Roth Date: Thu, 4 Dec 2014 11:25:06 +0100 Subject: [PATCH] Allow multiple versions in rpm state Fix bug in ansible get_package_state and get_current_version that breaks when there are multiple versions of a package installed and there is a list of packages to install. The previous implementation used 'zip' to match requested names to installed names which fails, because rpm outputs multiple lines per package when there are multiple versions. Testcase: Install opensuse, install multiple kernel versions (happens by update) Before patch: calling zypper: state=present for name={{item}} with_items: - kernel-desktop - git leads to ansible aborting. After the patch ansible performs as expected and makes sure both packages are present. Also the last version number is used for further update information in this version (before if only one package name was given the oldest version number was used). --- .../modules/extras/packaging/os/zypper.py | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/ansible/modules/extras/packaging/os/zypper.py b/lib/ansible/modules/extras/packaging/os/zypper.py index 196a7e2782..2147779eee 100644 --- a/lib/ansible/modules/extras/packaging/os/zypper.py +++ b/lib/ansible/modules/extras/packaging/os/zypper.py @@ -95,25 +95,31 @@ def zypper_version(module): return rc, stderr # Function used for getting versions of currently installed packages. -def get_current_version(m, name): +def get_current_version( packages): cmd = ['/bin/rpm', '-q', '--qf', '%{NAME} %{VERSION}-%{RELEASE}\n'] - cmd.extend(name) - (rc, stdout, stderr) = m.run_command(cmd) + cmd.extend(packages) + + stdout = subprocess.check_output(cmd) current_version = {} rpmoutput_re = re.compile('^(\S+) (\S+)$') - for stdoutline, package in zip(stdout.splitlines(), name): - m = rpmoutput_re.match(stdoutline) - if m == None: + + for stdoutline in stdout.splitlines(): + match = rpmoutput_re.match(stdoutline) + if match == None: return None - rpmpackage = m.group(1) - rpmversion = m.group(2) - if package != rpmpackage: + package = match.group(1) + version = match.group(2) + current_version[package] = version + + for package in packages: + if package not in current_version: + print package + ' was not returned by rpm \n' return None - current_version[package] = rpmversion return current_version + # Function used to find out if a package is currently installed. def get_package_state(m, packages): cmd = ['/bin/rpm', '--query', '--qf', 'package %{NAME} is installed\n'] @@ -123,19 +129,21 @@ def get_package_state(m, packages): installed_state = {} rpmoutput_re = re.compile('^package (\S+) (.*)$') - for stdoutline, name in zip(stdout.splitlines(), packages): - m = rpmoutput_re.match(stdoutline) - if m == None: - return None - package = m.group(1) - result = m.group(2) - if not name.startswith(package): - print name + ':' + package + ':' + stdoutline + '\n' + for stdoutline in stdout.splitlines(): + match = rpmoutput_re.match(stdoutline) + if match == None: return None + package = match.group(1) + result = match.group(2) if result == 'is installed': - installed_state[name] = True + installed_state[package] = True else: - installed_state[name] = False + installed_state[package] = False + + for package in packages: + if package not in installed_state: + print package + ' was not returned by rpm \n' + return None return installed_state