1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# (c) 2013, Raul Melo
5# Written by Raul Melo <raulmelo@gmail.com>
6# Based on yum module written by Seth Vidal <skvidal at fedoraproject.org>
7#
8# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
9
10from __future__ import absolute_import, division, print_function
11__metaclass__ = type
12
13
14ANSIBLE_METADATA = {'metadata_version': '1.1',
15                    'status': ['preview'],
16                    'supported_by': 'community'}
17
18
19DOCUMENTATION = '''
20---
21module: swdepot
22short_description: Manage packages with swdepot package manager (HP-UX)
23description:
24    - Will install, upgrade and remove packages with swdepot package manager (HP-UX)
25version_added: "1.4"
26notes: []
27author: "Raul Melo (@melodous)"
28options:
29    name:
30        description:
31            - package name.
32        required: true
33        version_added: 1.4
34    state:
35        description:
36            - whether to install (C(present), C(latest)), or remove (C(absent)) a package.
37        required: true
38        choices: [ 'present', 'latest', 'absent']
39        version_added: 1.4
40    depot:
41        description:
42            - The source repository from which install or upgrade a package.
43        version_added: 1.4
44'''
45
46EXAMPLES = '''
47- swdepot:
48    name: unzip-6.0
49    state: present
50    depot: 'repository:/path'
51
52- swdepot:
53    name: unzip
54    state: latest
55    depot: 'repository:/path'
56
57- swdepot:
58    name: unzip
59    state: absent
60'''
61
62import re
63
64from ansible.module_utils.basic import AnsibleModule
65from ansible.module_utils.six.moves import shlex_quote
66
67
68def compare_package(version1, version2):
69    """ Compare version packages.
70        Return values:
71        -1 first minor
72        0 equal
73        1 first greater """
74
75    def normalize(v):
76        return [int(x) for x in re.sub(r'(\.0+)*$', '', v).split(".")]
77    normalized_version1 = normalize(version1)
78    normalized_version2 = normalize(version2)
79    if normalized_version1 == normalized_version2:
80        rc = 0
81    elif normalized_version1 < normalized_version2:
82        rc = -1
83    else:
84        rc = 1
85    return rc
86
87
88def query_package(module, name, depot=None):
89    """ Returns whether a package is installed or not and version. """
90
91    cmd_list = '/usr/sbin/swlist -a revision -l product'
92    if depot:
93        rc, stdout, stderr = module.run_command("%s -s %s %s | grep %s" % (cmd_list, shlex_quote(depot), shlex_quote(name), shlex_quote(name)),
94                                                use_unsafe_shell=True)
95    else:
96        rc, stdout, stderr = module.run_command("%s %s | grep %s" % (cmd_list, shlex_quote(name), shlex_quote(name)), use_unsafe_shell=True)
97    if rc == 0:
98        version = re.sub(r"\s\s+|\t", " ", stdout).strip().split()[1]
99    else:
100        version = None
101
102    return rc, version
103
104
105def remove_package(module, name):
106    """ Uninstall package if installed. """
107
108    cmd_remove = '/usr/sbin/swremove'
109    rc, stdout, stderr = module.run_command("%s %s" % (cmd_remove, name))
110
111    if rc == 0:
112        return rc, stdout
113    else:
114        return rc, stderr
115
116
117def install_package(module, depot, name):
118    """ Install package if not already installed """
119
120    cmd_install = '/usr/sbin/swinstall -x mount_all_filesystems=false'
121    rc, stdout, stderr = module.run_command("%s -s %s %s" % (cmd_install, depot, name))
122    if rc == 0:
123        return rc, stdout
124    else:
125        return rc, stderr
126
127
128def main():
129    module = AnsibleModule(
130        argument_spec=dict(
131            name=dict(aliases=['pkg'], required=True),
132            state=dict(choices=['present', 'absent', 'latest'], required=True),
133            depot=dict(default=None, required=False)
134        ),
135        supports_check_mode=True
136    )
137    name = module.params['name']
138    state = module.params['state']
139    depot = module.params['depot']
140
141    changed = False
142    msg = "No changed"
143    rc = 0
144    if (state == 'present' or state == 'latest') and depot is None:
145        output = "depot parameter is mandatory in present or latest task"
146        module.fail_json(name=name, msg=output, rc=rc)
147
148    # Check local version
149    rc, version_installed = query_package(module, name)
150    if not rc:
151        installed = True
152        msg = "Already installed"
153
154    else:
155        installed = False
156
157    if (state == 'present' or state == 'latest') and installed is False:
158        if module.check_mode:
159            module.exit_json(changed=True)
160        rc, output = install_package(module, depot, name)
161
162        if not rc:
163            changed = True
164            msg = "Package installed"
165
166        else:
167            module.fail_json(name=name, msg=output, rc=rc)
168
169    elif state == 'latest' and installed is True:
170        # Check depot version
171        rc, version_depot = query_package(module, name, depot)
172
173        if not rc:
174            if compare_package(version_installed, version_depot) == -1:
175                if module.check_mode:
176                    module.exit_json(changed=True)
177                # Install new version
178                rc, output = install_package(module, depot, name)
179
180                if not rc:
181                    msg = "Package upgraded, Before " + version_installed + " Now " + version_depot
182                    changed = True
183
184                else:
185                    module.fail_json(name=name, msg=output, rc=rc)
186
187        else:
188            output = "Software package not in repository " + depot
189            module.fail_json(name=name, msg=output, rc=rc)
190
191    elif state == 'absent' and installed is True:
192        if module.check_mode:
193            module.exit_json(changed=True)
194        rc, output = remove_package(module, name)
195        if not rc:
196            changed = True
197            msg = "Package removed"
198        else:
199            module.fail_json(name=name, msg=output, rc=rc)
200
201    if module.check_mode:
202        module.exit_json(changed=False)
203
204    module.exit_json(changed=changed, name=name, state=state, msg=msg)
205
206
207if __name__ == '__main__':
208    main()
209