1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 07:51:50 +00:00
community.general/plugins/modules/svr4pkg.py
2025-11-01 13:46:53 +01:00

267 lines
7.6 KiB
Python

#!/usr/bin/python
# Copyright (c) 2012, Boyd Adamson <boyd () boydadamson.com>
#
# 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 annotations
DOCUMENTATION = r"""
module: svr4pkg
short_description: Manage Solaris SVR4 packages
description:
- Manages SVR4 packages on Solaris 10 and 11.
- These were the native packages on Solaris <= 10 and are available as a legacy feature in Solaris 11.
- Note that this is a very basic packaging system. It does not enforce dependencies on install or remove.
author: "Boyd Adamson (@brontitall)"
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: full
diff_mode:
support: none
options:
name:
description:
- Package name, for example V(SUNWcsr).
required: true
type: str
state:
description:
- Whether to install (V(present)), or remove (V(absent)) a package.
- If the package is to be installed, then O(src) is required.
- The SVR4 package system does not provide an upgrade operation. You need to uninstall the old, then install the new
package.
required: true
choices: ["present", "absent"]
type: str
src:
description:
- Specifies the location to install the package from. Required when O(state=present).
- "Can be any path acceptable to the C(pkgadd) command's C(-d) option. For example: V(somefile.pkg), V(/dir/with/pkgs),
V(http://server/mypkgs.pkg)."
- If using a file or directory, they must already be accessible by the host. See the M(ansible.builtin.copy) module
for a way to get them there.
type: str
proxy:
description:
- HTTP[s] proxy to be used if O(src) is a URL.
type: str
response_file:
description:
- Specifies the location of a response file to be used if package expects input on install.
required: false
type: str
zone:
description:
- Whether to install the package only in the current zone, or install it into all zones.
- The installation into all zones works only if you are working with the global zone.
required: false
default: "all"
choices: ["current", "all"]
type: str
category:
description:
- Install/Remove category instead of a single package.
required: false
type: bool
default: false
"""
EXAMPLES = r"""
- name: Install a package from an already copied file
community.general.svr4pkg:
name: CSWcommon
src: /tmp/cswpkgs.pkg
state: present
- name: Install a package directly from an http site
community.general.svr4pkg:
name: CSWpkgutil
src: 'http://get.opencsw.org/now'
state: present
zone: current
- name: Install a package with a response file
community.general.svr4pkg:
name: CSWggrep
src: /tmp/third-party.pkg
response_file: /tmp/ggrep.response
state: present
- name: Ensure that a package is not installed
community.general.svr4pkg:
name: SUNWgnome-sound-recorder
state: absent
- name: Ensure that a category is not installed
community.general.svr4pkg:
name: FIREFOX
state: absent
category: true
"""
import os
import tempfile
from ansible.module_utils.basic import AnsibleModule
def package_installed(module, name, category):
cmd = [module.get_bin_path("pkginfo", True), "-q"]
if category:
cmd.append("-c")
cmd.append(name)
rc, out, err = module.run_command(cmd)
if rc == 0:
return True
else:
return False
def create_admin_file():
(desc, filename) = tempfile.mkstemp(prefix="ansible_svr4pkg", text=True)
fullauto = b"""
mail=
instance=unique
partial=nocheck
runlevel=quit
idepend=nocheck
rdepend=nocheck
space=quit
setuid=nocheck
conflict=nocheck
action=nocheck
networktimeout=60
networkretries=3
authentication=quit
keystore=/var/sadm/security
proxy=
basedir=default
"""
os.write(desc, fullauto)
os.close(desc)
return filename
def run_command(module, cmd):
progname = cmd[0]
cmd[0] = module.get_bin_path(progname, True)
return module.run_command(cmd)
def package_install(module, name, src, proxy, response_file, zone, category):
adminfile = create_admin_file()
cmd = ["pkgadd", "-n"]
if zone == "current":
cmd += ["-G"]
cmd += ["-a", adminfile, "-d", src]
if proxy is not None:
cmd += ["-x", proxy]
if response_file is not None:
cmd += ["-r", response_file]
if category:
cmd += ["-Y"]
cmd.append(name)
(rc, out, err) = run_command(module, cmd)
os.unlink(adminfile)
return (rc, out, err)
def package_uninstall(module, name, src, category):
adminfile = create_admin_file()
if category:
cmd = ["pkgrm", "-na", adminfile, "-Y", name]
else:
cmd = ["pkgrm", "-na", adminfile, name]
(rc, out, err) = run_command(module, cmd)
os.unlink(adminfile)
return (rc, out, err)
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(required=True),
state=dict(required=True, choices=["present", "absent"]),
src=dict(),
proxy=dict(),
response_file=dict(),
zone=dict(default="all", choices=["current", "all"]),
category=dict(default=False, type="bool"),
),
supports_check_mode=True,
)
state = module.params["state"]
name = module.params["name"]
src = module.params["src"]
proxy = module.params["proxy"]
response_file = module.params["response_file"]
zone = module.params["zone"]
category = module.params["category"]
rc = None
out = ""
err = ""
result = {}
result["name"] = name
result["state"] = state
if state == "present":
if src is None:
module.fail_json(name=name, msg="src is required when state=present")
if not package_installed(module, name, category):
if module.check_mode:
module.exit_json(changed=True)
(rc, out, err) = package_install(module, name, src, proxy, response_file, zone, category)
# Stdout is normally empty but for some packages can be
# very long and is not often useful
if len(out) > 75:
out = f"{out[:75]}..."
elif state == "absent":
if package_installed(module, name, category):
if module.check_mode:
module.exit_json(changed=True)
(rc, out, err) = package_uninstall(module, name, src, category)
out = out[:75]
# Returncodes as per pkgadd(1m)
# 0 Successful completion
# 1 Fatal error.
# 2 Warning.
# 3 Interruption.
# 4 Administration.
# 5 Administration. Interaction is required. Do not use pkgadd -n.
# 10 Reboot after installation of all packages.
# 20 Reboot after installation of this package.
# 99 (observed) pkgadd: ERROR: could not process datastream from </tmp/pkgutil.pkg>
if rc in (0, 2, 3, 10, 20):
result["changed"] = True
# no install nor uninstall, or failed
else:
result["changed"] = False
# rc will be none when the package already was installed and no action took place
# Only return failed=False when the returncode is known to be good as there may be more
# undocumented failure return codes
if rc not in (None, 0, 2, 10, 20):
result["failed"] = True
else:
result["failed"] = False
if out:
result["stdout"] = out
if err:
result["stderr"] = err
module.exit_json(**result)
if __name__ == "__main__":
main()