From 79b56667e32bf86cd99d728c20e81451163b84ed Mon Sep 17 00:00:00 2001 From: Patrick Callahan Date: Thu, 6 Jun 2013 21:57:32 -0400 Subject: [PATCH 1/2] Simple zypper module to install, remove, or upgrades packages. --- library/packaging/zypper | 225 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 library/packaging/zypper diff --git a/library/packaging/zypper b/library/packaging/zypper new file mode 100644 index 00000000000..dcb9e1536c2 --- /dev/null +++ b/library/packaging/zypper @@ -0,0 +1,225 @@ +#!/usr/bin/python -tt +# -*- coding: utf-8 -*- + +# (c) 2013, Patrick Callahan +# based on +# openbsd_pkg +# (c) 2013 +# Patrik Lundin +# +# yum +# (c) 2012, Red Hat, Inc +# Written by Seth Vidal +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +import re + +DOCUMENTATION = ''' +--- +module: zypper +author: Patrick Callahan +version_added: "1.x" +short_description: Manage packages on SuSE and openSuSE +description: + - Manage packages on SuSE and openSuSE using the zypper and rpm tools. +options: + name: + description: + - package name or package specifier wth version C(name) or C(name-1.0). + required: true + aliases: [ 'pkg' ] + state: + description: + - C(present) will make sure the package is installed. + C(latest) will make sure the latest version of the package is installed. + C(absent) will make sure the specified package is not installed. + required: false + choices: [ present, latest, absent ] + default: "present" + disable_gpg_check: + description: + - Whether to disable to GPG signature checking of the package + signature being installed. Has an effect only if state is + I(present) or I(latest). + required: false + default: "no" + choices: [ "yes", "no" ] + aliases: [] + +examples: + - code: "zypper: name=nmap state=present" + - code: "zypper: name=nmap state=latest" + - code: "zypper: name=nmap state=absent" +notes: [] +# informational: requirements for nodes +requirements: [ zypper, rpm ] +author: Patrick Callahan +''' + +# Function used for getting the name of a currently installed package. +def get_current_name(m, name): + cmd = '/bin/rpm -q --qf \'%{NAME}-%{VERSION}\'' + (rc, stdout, stderr) = m.run_command("%s" % (cmd)) + + if rc != 0: + return (rc, stdout, stderr) + + syntax = "%s" + + for line in stdout.splitlines(): + if syntax % name in line: + current_name = line.split()[0] + + return current_name + +# Function used to find out if a package is currently installed. +def get_package_state(m, name): + cmd = ['/bin/rpm', '--query', '--info', name] + + rc, stdout, stderr = m.run_command(cmd, check_rc=False) + + if rc == 0: + return True + else: + return False + +# Function used to make sure a package is present. +def package_present(m, name, installed_state, disable_gpg_check): + if installed_state is False: + cmd = ['/usr/bin/zypper', '--non-interactive'] + # add global options before zypper command + if disable_gpg_check: + cmd.append('--no-gpg-check') + + cmd.extend(['install', '--auto-agree-with-licenses']) + cmd.append(name) + rc, stdout, stderr = m.run_command(cmd, check_rc=False) + + if rc == 0: + changed=True + else: + changed=False + else: + rc = 0 + stdout = '' + stderr = '' + changed=False + + return (rc, stdout, stderr, changed) + +# Function used to make sure a package is the latest available version. +def package_latest(m, name, installed_state, disable_gpg_check): + + if installed_state is True: + cmd = ['/usr/bin/zypper', '--non-interactive', 'update', '--auto-agree-with-licenses', name] + pre_upgrade_name = '' + post_upgrade_name = '' + + # Compare the installed package before and after to know if we changed anything. + pre_upgrade_name = get_current_name(m, name) + + rc, stdout, stderr = m.run_command(cmd, check_rc=False) + + post_upgrade_name = get_current_name(m, name) + + if pre_upgrade_name == post_upgrade_name: + changed = False + else: + changed = True + + return (rc, stdout, stderr, changed) + + else: + # If package was not installed at all just make it present. + return package_present(m, name, installed_state, disable_gpg_check) + +# Function used to make sure a package is not installed. +def package_absent(m, name, installed_state): + if installed_state is True: + cmd = ['/usr/bin/zypper', '--non-interactive', 'remove', name] + rc, stdout, stderr = m.run_command(cmd) + + if rc == 0: + changed=True + else: + changed=False + else: + rc = 0 + stdout = '' + stderr = '' + changed=False + + return (rc, stdout, stderr, changed) + +# =========================================== +# Main control flow + +def main(): + module = AnsibleModule( + argument_spec = dict( + name = dict(required=True, aliases=['pkg']), + state = dict(required=False, default='present', choices=['absent', 'installed', 'latest', 'present', 'removed']), + disable_gpg_check = dict(required=False, default='no', choices=BOOLEANS, type='bool'), + ), + supports_check_mode = False + ) + + + params = module.params + + name = params['name'] + state = params['state'] + disable_gpg_check = params['disable_gpg_check'] + + rc = 0 + stdout = '' + stderr = '' + result = {} + result['name'] = name + result['state'] = state + + # Decide if the name contains a version number. + match = re.search("-[0-9]", name) + if match: + specific_version = True + else: + specific_version = False + + # Get package state + installed_state = get_package_state(module, name) + + # Perform requested action + if state in ['installed', 'present']: + (rc, stdout, stderr, changed) = package_present(module, name, installed_state, disable_gpg_check) + elif state in ['absent', 'removed']: + (rc, stdout, stderr, changed) = package_absent(module, name, installed_state) + elif state == 'latest': + (rc, stdout, stderr, changed) = package_latest(module, name, installed_state, disable_gpg_check) + + if rc != 0: + if stderr: + module.fail_json(msg=stderr) + else: + module.fail_json(msg=stdout) + + result['changed'] = changed + + module.exit_json(**result) + +# this is magic, see lib/ansible/module_common.py +#<> +main() From c1ec8ead6c165b87cce1a045e52f24c150024a56 Mon Sep 17 00:00:00 2001 From: Patrick Callahan Date: Fri, 7 Jun 2013 23:31:21 -0400 Subject: [PATCH 2/2] BUG FIX: Add package name to the cmd. --- library/packaging/zypper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/packaging/zypper b/library/packaging/zypper index dcb9e1536c2..c1c7d012d5a 100644 --- a/library/packaging/zypper +++ b/library/packaging/zypper @@ -73,7 +73,7 @@ author: Patrick Callahan # Function used for getting the name of a currently installed package. def get_current_name(m, name): cmd = '/bin/rpm -q --qf \'%{NAME}-%{VERSION}\'' - (rc, stdout, stderr) = m.run_command("%s" % (cmd)) + (rc, stdout, stderr) = m.run_command("%s %s" % (cmd, name)) if rc != 0: return (rc, stdout, stderr)