]> TLD Linux GIT Repositories - packages/ansible.git/commitdiff
- added support for poldek package manager
authorMarcin Krol <hawk@tld-linux.org>
Fri, 21 Jun 2019 21:38:15 +0000 (23:38 +0200)
committerMarcin Krol <hawk@tld-linux.org>
Fri, 21 Jun 2019 21:38:15 +0000 (23:38 +0200)
ansible.spec
poldek.patch [new file with mode: 0644]
poldek.py [new file with mode: 0644]

index 65796ee2946e686848253802596a440e614be8e5..74c5e3af1a7d6a22642cfaf33da8e780ff4a5a81 100644 (file)
@@ -1,11 +1,13 @@
 Summary:       SSH-based configuration management, deployment, and task execution system
 Name:          ansible
 Version:       2.8.0
-Release:       1
+Release:       2
 License:       GPL v3+
 Group:         Development/Libraries
 Source0:       https://releases.ansible.com/ansible/%{name}-%{version}.tar.gz
 # Source0-md5: 9320cd9e26f929568038db49781df245
+Source1:       poldek.py
+Patch0:                poldek.patch
 URL:           http://ansible.github.com/
 BuildRequires: python3-modules
 BuildRequires: rpm-pythonprov
@@ -29,6 +31,7 @@ are transferred to managed machines automatically.
 
 %prep
 %setup -q
+%patch0 -p1
 
 %build
 %py3_build
@@ -38,6 +41,8 @@ are transferred to managed machines automatically.
 rm -rf $RPM_BUILD_ROOT
 %py3_install
 
+install -p %{SOURCE1} $RPM_BUILD_ROOT%{py3_sitescriptdir}/ansible/modules/packaging/os
+
 install -d $RPM_BUILD_ROOT{%{_sysconfdir}/%{name},%{_mandir}}
 sed -re '/^#/ !s,[^#]+$,#&,' examples/hosts > $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/hosts
 cp -p examples/ansible.cfg $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
diff --git a/poldek.patch b/poldek.patch
new file mode 100644 (file)
index 0000000..37d2a10
--- /dev/null
@@ -0,0 +1,13 @@
+diff -ur ansible-2.8.0.orig/lib/ansible/module_utils/facts/system/pkg_mgr.py ansible-2.8.0/lib/ansible/module_utils/facts/system/pkg_mgr.py
+--- ansible-2.8.0.orig/lib/ansible/module_utils/facts/system/pkg_mgr.py        2019-06-21 22:50:15.462000000 +0200
++++ ansible-2.8.0/lib/ansible/module_utils/facts/system/pkg_mgr.py     2019-06-21 22:51:42.117000000 +0200
+@@ -13,7 +13,8 @@
+ # A list of dicts.  If there is a platform with more than one
+ # package manager, put the preferred one last.  If there is an
+ # ansible module, use that as the value for the 'name' key.
+-PKG_MGRS = [{'path': '/usr/bin/yum', 'name': 'yum'},
++PKG_MGRS = [{'path': '/usr/bin/poldek', 'name': 'poldek'},
++            {'path': '/usr/bin/yum', 'name': 'yum'},
+             {'path': '/usr/bin/dnf', 'name': 'dnf'},
+             {'path': '/usr/bin/apt-get', 'name': 'apt'},
+             {'path': '/usr/bin/zypper', 'name': 'zypper'},
diff --git a/poldek.py b/poldek.py
new file mode 100644 (file)
index 0000000..74672f1
--- /dev/null
+++ b/poldek.py
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Marcin Krol <hawk@tld-linux.org>
+# 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
+
+ANSIBLE_METADATA = {'metadata_version': '1.0',
+                    'status': ['preview'],
+                    'supported_by': 'community'}
+
+DOCUMENTATION = '''
+---
+module: poldek
+short_description: Manage packages with I(poldek)
+description:
+    - Manage packages with the I(poldek) package manager, which is used by TLD Linux and PLD Linux
+version_added: "1.0"
+author:
+    - Marcin Krol <hawk@tld-linux.org>
+options:
+    name:
+        description:
+            - Name or list of names of the package(s) or file(s) to install, upgrade, or remove.
+              Can't be used in combination with C(upgrade).
+        aliases: [ package, pkg ]
+
+    state:
+        description:
+            - Desired state of the package.
+        default: present
+        choices: [ absent, latest, present ]
+
+    extra_args:
+        description:
+            - Additional option to pass to poldek when enforcing C(state).
+        default:
+
+    update_cache:
+        description:
+            - Whether or not to refresh the master package lists.
+            - This can be run as part of a package installation or as a separate step.
+        default: no
+        type: bool
+        aliases: [ update-cache ]
+
+    update_cache_extra_args:
+        description:
+            - Additional option to pass to poldek when enforcing C(update_cache).
+        default:
+
+    upgrade:
+        description:
+            - Whether or not to upgrade the whole system.
+              Can't be used in combination with C(name).
+        default: no
+        type: bool
+
+    upgrade_extra_args:
+        description:
+            - Additional option to pass to poldek when enforcing C(upgrade).
+        default:
+'''
+
+RETURN = '''
+packages:
+    description: a list of packages that have been changed
+    returned: when upgrade is set to yes
+    type: list
+    sample: [ package, other-package ]
+'''
+
+EXAMPLES = '''
+- name: Install packages foo and bar
+  poldek:
+    name:
+      - foo
+      - bar
+    state: present
+
+- name: Update package cache and upgrade package foo
+  poldek:
+    name: foo
+    state: latest
+    update_cache: yes
+
+- name: Remove packages foo and bar
+  poldek:
+    name:
+      - foo
+      - bar
+    state: absent
+
+- name: Update package cache only
+  poldek:
+    update_cache: yes
+
+- name: Update package cache and upgrade all packages
+  poldek:
+    upgrade: yes
+    update_cache: yes
+'''
+
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def query_package(module, poldek_path, name):
+    """Query the package status in both the local system and the repository. Returns a boolean to indicate if the package is installed, a second
+    boolean to indicate if the package is up-to-date. Note: indexes must be up to date to ensure that poldek knows latest version of package.
+    """
+    lcmd = "%s -q --shcmd='ls -n --installed %s'" % (poldek_path, name)
+    lrc, lstdout, lstderr = module.run_command(lcmd, check_rc=False)
+    rcmd = "%s -q --shcmd='ls -n --installed --upgradeable %s'" % (poldek_path, name)
+    rrc, rstdout, rstderr = module.run_command(rcmd, check_rc=False)
+    if lrc != 0 or rrc != 0:
+        return False, False
+
+    pkg_latest = False
+    if rstdout == "":
+        return True, True
+    else:
+        return True, False
+
+
+def update_package_db(module, poldek_path):
+    if module.params['force']:
+        module.params["update_cache_extra_args"] += " --upa"
+
+    cmd = "%s --noask --up %s" % (poldek_path, module.params["update_cache_extra_args"])
+    rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+    if rc == 0:
+        return True
+    else:
+        module.fail_json(msg="error updating package database")
+
+
+def upgrade(module, poldek_path):
+    cmdupgrade = "%s -v --noask --upgrade-dist %s" % (poldek_path, module.params["upgrade_extra_args"])
+    cmdupgradeable = "%s -q --shcmd='ls -n --installed --upgradeable' %s" % (poldek_path, module.params["upgrade_extra_args"])
+    rc, stdout, stderr = module.run_command(cmdupgradeable, check_rc=False)
+
+    packages = stdout.split('\n')[:-1]
+    if stdout == "":
+        module.exit_json(changed=False, msg='Nothing to upgrade', packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+    else:
+        if module.check_mode:
+            module.exit_json(changed=True, msg="%s package(s) would be upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+        rc, stdout, stderr = module.run_command(cmdupgrade, check_rc=False)
+        if rc == 0:
+            module.exit_json(changed=True, msg="%s package(s) upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+        else:
+            module.fail_json(msg="Error while upgrading packages", stdout=stdout, stderr=stderr, rc=rc)
+
+
+def remove_packages(module, poldek_path, packages):
+    if module.params["force"]:
+        module.params["extra_args"] += " --force --nodeps"
+
+    remove_c = 0
+    out = ""
+    err = ""
+
+    for package in packages:
+        installed, updated = query_package(module, poldek_path, package)
+        if not installed:
+            continue
+
+        cmd = "%s -v --noask --erase %s %s" % (poldek_path, module.params["extra_args"], package)
+        rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+        out = out + stdout
+        err = err + stderr
+
+        if rc != 0:
+            module.fail_json(msg="failed to remove %s" % (package), stdout=out, stderr=err, rc=rc)
+
+        remove_c += 1
+
+    if remove_c > 0:
+        module.exit_json(changed=True, msg="removed %s package(s)" % (remove_c), packages=packages, stdout=out, stderr=err, rc=0)
+
+    module.exit_json(changed=False, msg="package(s) already absent", packages=packages, stdout=out, stderr=err, rc=0)
+
+
+def install_packages(module, poldek_path, state, packages):
+    if module.params["force"]:
+        module.params["extra_args"] += " --force --nodeps"
+
+    install_c = 0
+    out = ""
+    err = ""
+
+    for package in packages:
+        installed, updated = query_package(module, poldek_path, package)
+        if installed and (state == 'present' or (state == 'latest' and updated)):
+            continue
+
+        cmd = "%s -v --noask --upgrade %s %s" % (poldek_path, module.params["extra_args"], package)
+        rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+        out = out + stdout
+        err = err + stderr
+
+        if rc != 0:
+            module.fail_json(msg="failed to install %s" % (package), stdout=out, stderr=err, rc=rc)
+
+        install_c += 1
+
+    if install_c > 0:
+        module.exit_json(changed=True, msg="installed %s package(s)" % (install_c), packages=packages, stdout=out, stderr=err, rc=0)
+
+    module.exit_json(changed=False, msg="package(s) already installed", packages=packages, stdout=out, stderr=err, rc=0)
+
+
+def check_packages(module, poldek_path, packages, state):
+    would_be_changed = []
+
+    for package in packages:
+        installed, updated = query_package(module, poldek_path, package)
+        if ((state in ["present", "latest"] and not installed) or
+                (state == "absent" and installed) or
+                (state == "latest" and not updated)):
+            would_be_changed.append(package)
+
+    if state == "absent":
+        state = "removed"
+    if state == "present" or state == "latest":
+        state = "installed"
+
+    if would_be_changed:
+        module.exit_json(changed=True, msg="%s package(s) would be %s" % (
+            len(would_be_changed), state))
+    else:
+        module.exit_json(changed=False, msg="package(s) already %s" % state)
+
+
+def main():
+    module = AnsibleModule(
+        argument_spec=dict(
+            name=dict(type='list', aliases=['pkg', 'package']),
+            state=dict(type='str', default='present', choices=['present', 'installed', 'latest', 'absent', 'removed']),
+            extra_args=dict(type='str', default=''),
+            upgrade=dict(type='bool', default=False),
+            upgrade_extra_args=dict(type='str', default=''),
+            update_cache=dict(type='bool', default=False, aliases=['update-cache']),
+            update_cache_extra_args=dict(type='str', default=''),
+            force=dict(type='bool', default=False),
+        ),
+        required_one_of=[['name', 'update_cache', 'upgrade']],
+        mutually_exclusive=[['name', 'upgrade']],
+        supports_check_mode=True,
+    )
+
+    poldek_path = module.get_bin_path('poldek', True)
+
+    p = module.params
+
+    if p['state'] in ['present', 'installed']:
+        p['state'] = 'present'
+    elif p['state'] in ['absent', 'removed']:
+        p['state'] = 'absent'
+
+    if p["update_cache"] and not module.check_mode:
+        update_package_db(module, poldek_path)
+        if not (p['name'] or p['upgrade']):
+            module.exit_json(changed=True, msg='Updated package database')
+
+    if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
+        module.exit_json(changed=True, msg='Would have updated package database')
+
+    if p['upgrade']:
+        upgrade(module, poldek_path)
+
+    if p['name']:
+        pkgs = p['name']
+
+        if module.check_mode:
+            check_packages(module, poldek_path, pkgs, p['state'])
+
+        if p['state'] in ['present', 'latest']:
+            install_packages(module, poldek_path, p['state'], pkgs)
+        elif p['state'] == 'absent':
+            remove_packages(module, poldek_path, pkgs)
+    else:
+        module.exit_json(changed=False, msg="No package specified to work on")
+
+
+if __name__ == "__main__":
+    main()