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