summaryrefslogtreecommitdiff
path: root/packaging/os/apt_rpm.py
blob: e8a702e9a09d3fac4c3b802fb28802bbdd0dbac1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/python -tt
# -*- coding: utf-8 -*-

# (c) 2013, Evgenii Terechkov
# Written by Evgenii Terechkov <evg@altlinux.org> 
# Based on urpmi module written by Philippe Makowski <philippem@mageia.org> 
#
# This module 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.
#
# This software 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 this software.  If not, see <http://www.gnu.org/licenses/>.


DOCUMENTATION = '''
---
module: apt_rpm
short_description: apt_rpm package manager
description:
  - Manages packages with I(apt-rpm). Both low-level (I(rpm)) and high-level (I(apt-get)) package manager binaries required.
version_added: "1.5"
options:
  pkg:
    description:
      - name of package to install, upgrade or remove.
    required: true
    default: null
  state:
    description:
      - Indicates the desired package state
    required: false
    default: present
    choices: [ "absent", "present" ]
  update_cache:
    description:
      - update the package database first C(apt-get update).
    required: false
    default: no
    choices: [ "yes", "no" ]
author: "Evgenii Terechkov (@evgkrsk)"
notes:  []
'''

EXAMPLES = '''
# install package foo
- apt_rpm:
    pkg: foo
    state: present

# remove package foo
- apt_rpm:
    pkg: foo
    state: absent

# description: remove packages foo and bar
- apt_rpm:
    pkg: foo,bar
    state: absent

# description: update the package database and install bar (bar will be the updated if a newer version exists)
- apt_rpm:
    name: bar
    state: present
    update_cache: yes
'''


try:
    import json
except ImportError:
    import simplejson as json

import shlex
import os
import sys

APT_PATH="/usr/bin/apt-get"
RPM_PATH="/usr/bin/rpm"

def query_package(module, name):
    # rpm -q returns 0 if the package is installed,
    # 1 if it is not installed
    rc, out, err = module.run_command("%s -q %s" % (RPM_PATH,name))
    if rc == 0:
        return True
    else:
        return False

def query_package_provides(module, name):
    # rpm -q returns 0 if the package is installed,
    # 1 if it is not installed
    rc, out, err = module.run_command("%s -q --provides %s" % (RPM_PATH,name))
    return rc == 0

def update_package_db(module):
    rc, out, err = module.run_command("%s update" % APT_PATH)

    if rc != 0:
        module.fail_json(msg="could not update package db: %s" % err)

def remove_packages(module, packages):
    
    remove_c = 0
    # Using a for loop incase of error, we can report the package that failed
    for package in packages:
        # Query the package first, to see if we even need to remove
        if not query_package(module, package):
            continue

        rc, out, err = module.run_command("%s -y remove %s" % (APT_PATH,package))

        if rc != 0:
            module.fail_json(msg="failed to remove %s: %s" % (package, err))
    
        remove_c += 1

    if remove_c > 0:
        module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)

    module.exit_json(changed=False, msg="package(s) already absent")


def install_packages(module, pkgspec):

    packages = ""
    for package in pkgspec:
        if not query_package_provides(module, package):
            packages += "'%s' " % package

    if len(packages) != 0:

        rc, out, err = module.run_command("%s -y install %s" % (APT_PATH, packages))

        installed = True
        for packages in pkgspec:
            if not query_package_provides(module, package):
                installed = False

        # apt-rpm always have 0 for exit code if --force is used
        if rc or not installed:
            module.fail_json(msg="'apt-get -y install %s' failed: %s" % (packages, err))
        else:
            module.exit_json(changed=True, msg="%s present(s)" % packages)
    else:
        module.exit_json(changed=False)


def main():
    module = AnsibleModule(
            argument_spec    = dict(
                state        = dict(default='installed', choices=['installed', 'removed', 'absent', 'present']),
                update_cache = dict(default=False, aliases=['update-cache'], type='bool'),
                package      = dict(aliases=['pkg', 'name'], required=True)))
                

    if not os.path.exists(APT_PATH) or not os.path.exists(RPM_PATH):
        module.fail_json(msg="cannot find /usr/bin/apt-get and/or /usr/bin/rpm")

    p = module.params

    if p['update_cache']:
        update_package_db(module)

    packages = p['package'].split(',')

    if p['state'] in [ 'installed', 'present' ]:
        install_packages(module, packages)

    elif p['state'] in [ 'removed', 'absent' ]:
        remove_packages(module, packages)

# this is magic, see lib/ansible/module_common.py
from ansible.module_utils.basic import *
    
main()