summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/general/plugins/modules/pkg5.py
blob: c4aace9f28291e813f10888c836bcd0b015cd603 (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
183
184
185
186
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (c) 2014, Peter Oliver <ansible@mavit.org.uk>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function
__metaclass__ = type

DOCUMENTATION = '''
---
module: pkg5
author:
- Peter Oliver (@mavit)
short_description: Manages packages with the Solaris 11 Image Packaging System
description:
  - IPS packages are the native packages in Solaris 11 and higher.
notes:
  - The naming of IPS packages is explained at U(http://www.oracle.com/technetwork/articles/servers-storage-admin/ips-package-versioning-2232906.html).
extends_documentation_fragment:
  - community.general.attributes
attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
options:
  name:
    description:
      - An FRMI of the package(s) to be installed/removed/updated.
      - Multiple packages may be specified, separated by V(,).
    required: true
    type: list
    elements: str
  state:
    description:
      - Whether to install (V(present), V(latest)), or remove (V(absent)) a package.
    choices: [ absent, latest, present, installed, removed, uninstalled ]
    default: present
    type: str
  accept_licenses:
    description:
      - Accept any licences.
    type: bool
    default: false
    aliases: [ accept, accept_licences ]
  be_name:
    description:
      - Creates a new boot environment with the given name.
    type: str
  refresh:
    description:
      - Refresh publishers before execution.
    type: bool
    default: true
'''
EXAMPLES = '''
- name: Install Vim
  community.general.pkg5:
    name: editor/vim

- name: Install Vim without refreshing publishers
  community.general.pkg5:
    name: editor/vim
    refresh: false

- name: Remove finger daemon
  community.general.pkg5:
    name: service/network/finger
    state: absent

- name: Install several packages at once
  community.general.pkg5:
    name:
    - /file/gnu-findutils
    - /text/gnu-grep
'''

import re

from ansible.module_utils.basic import AnsibleModule


def main():
    module = AnsibleModule(
        argument_spec=dict(
            name=dict(type='list', elements='str', required=True),
            state=dict(type='str', default='present', choices=['absent', 'installed', 'latest', 'present', 'removed', 'uninstalled']),
            accept_licenses=dict(type='bool', default=False, aliases=['accept', 'accept_licences']),
            be_name=dict(type='str'),
            refresh=dict(type='bool', default=True),
        ),
        supports_check_mode=True,
    )

    params = module.params
    packages = []

    # pkg(5) FRMIs include a comma before the release number, but
    # AnsibleModule will have split this into multiple items for us.
    # Try to spot where this has happened and fix it.
    for fragment in params['name']:
        if re.search(r'^\d+(?:\.\d+)*', fragment) and packages and re.search(r'@[^,]*$', packages[-1]):
            packages[-1] += ',' + fragment
        else:
            packages.append(fragment)

    if params['state'] in ['present', 'installed']:
        ensure(module, 'present', packages, params)
    elif params['state'] in ['latest']:
        ensure(module, 'latest', packages, params)
    elif params['state'] in ['absent', 'uninstalled', 'removed']:
        ensure(module, 'absent', packages, params)


def ensure(module, state, packages, params):
    response = {
        'results': [],
        'msg': '',
    }
    behaviour = {
        'present': {
            'filter': lambda p: not is_installed(module, p),
            'subcommand': 'install',
        },
        'latest': {
            'filter': lambda p: (
                not is_installed(module, p) or not is_latest(module, p)
            ),
            'subcommand': 'install',
        },
        'absent': {
            'filter': lambda p: is_installed(module, p),
            'subcommand': 'uninstall',
        },
    }

    if module.check_mode:
        dry_run = ['-n']
    else:
        dry_run = []

    if params['accept_licenses']:
        accept_licenses = ['--accept']
    else:
        accept_licenses = []

    if params['be_name']:
        beadm = ['--be-name=' + module.params['be_name']]
    else:
        beadm = []

    if params['refresh']:
        no_refresh = []
    else:
        no_refresh = ['--no-refresh']

    to_modify = list(filter(behaviour[state]['filter'], packages))
    if to_modify:
        rc, out, err = module.run_command(['pkg', behaviour[state]['subcommand']] + dry_run + accept_licenses + beadm + no_refresh + ['-q', '--'] + to_modify)
        response['rc'] = rc
        response['results'].append(out)
        response['msg'] += err
        response['changed'] = True
        if rc == 4:
            response['changed'] = False
            response['failed'] = False
        elif rc != 0:
            module.fail_json(**response)

    module.exit_json(**response)


def is_installed(module, package):
    rc, out, err = module.run_command(['pkg', 'list', '--', package])
    return not bool(int(rc))


def is_latest(module, package):
    rc, out, err = module.run_command(['pkg', 'list', '-u', '--', package])
    return bool(int(rc))


if __name__ == '__main__':
    main()