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/homebrew_services.py
Felix Fontein 3478863ef0
Address issues reported by ruff check (#11043)
* Resolve E713 and E714 (not in/is tests).

* Address UP018 (unnecessary str call).

* UP045 requires Python 3.10+.

* Address UP007 (X | Y for type annotations).

* Address UP035 (import Callable from collections.abc).

* Address UP006 (t.Dict -> dict).

* Address UP009 (UTF-8 encoding comment).

* Address UP034 (extraneous parantheses).

* Address SIM910 (dict.get() with None default).

* Address F401 (unused import).

* Address UP020 (use builtin open).

* Address B009 and B010 (getattr/setattr with constant name).

* Address SIM300 (Yoda conditions).

* UP029 isn't in use anyway.

* Address FLY002 (static join).

* Address B034 (re.sub positional args).

* Address B020 (loop variable overrides input).

* Address B017 (assert raise Exception).

* Address SIM211 (if expression with false/true).

* Address SIM113 (enumerate for loop).

* Address UP036 (sys.version_info checks).

* Remove unnecessary UP039.

* Address SIM201 (not ==).

* Address SIM212 (if expr with twisted arms).

* Add changelog fragment.

* Reformat.
2025-11-08 17:05:21 +13:00

224 lines
7.3 KiB
Python

#!/usr/bin/python
# Copyright (c) 2013, Andrew Dunham <andrew@du.nham.ca>
# Copyright (c) 2013, Daniel Jaouen <dcj24@cornell.edu>
# Copyright (c) 2015, Indrajit Raychaudhuri <irc+code@indrajit.com>
# Copyright (c) 2024, Kit Ham <kitizz.devside@gmail.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: homebrew_services
author:
- "Kit Ham (@kitizz)"
requirements:
- homebrew must already be installed on the target system
short_description: Services manager for Homebrew
version_added: 9.3.0
description:
- Manages daemons and services using Homebrew.
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: full
diff_mode:
support: none
options:
name:
description:
- An installed homebrew package whose service is to be updated.
aliases: ['formula']
type: str
required: true
path:
description:
- A V(:) separated list of paths to search for C(brew) executable. Since a package (I(formula) in homebrew parlance)
location is prefixed relative to the actual path of C(brew) command, providing an alternative C(brew) path enables
managing different set of packages in an alternative location in the system.
default: '/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin'
type: path
state:
description:
- State of the package's service.
choices: ['present', 'absent', 'restarted']
default: present
type: str
"""
EXAMPLES = r"""
- name: Install foo package
community.general.homebrew:
name: foo
state: present
- name: Start the foo service (equivalent to `brew services start foo`)
community.general.homebrew_services:
name: foo
state: present
- name: Restart the foo service (equivalent to `brew services restart foo`)
community.general.homebrew_services:
name: foo
state: restarted
- name: Remove the foo service (equivalent to `brew services stop foo`)
community.general.homebrew_services:
name: foo
state: absent
"""
RETURN = r"""
pid:
description:
- If the service is now running, this is the PID of the service, otherwise -1.
returned: success
type: int
sample: 1234
running:
description:
- Whether the service is running after running this command.
returned: success
type: bool
sample: true
"""
import json
from typing import NamedTuple, Optional
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.homebrew import (
HomebrewValidate,
parse_brew_path,
)
# Stores validated arguments for an instance of an action.
# See DOCUMENTATION string for argument-specific information.
HomebrewServiceArgs = NamedTuple("HomebrewServiceArgs", [("name", str), ("state", str), ("brew_path", str)])
# Stores the state of a Homebrew service.
HomebrewServiceState = NamedTuple("HomebrewServiceState", [("running", bool), ("pid", Optional[int])])
def _brew_service_state(args, module):
# type: (HomebrewServiceArgs, AnsibleModule) -> HomebrewServiceState
cmd = [args.brew_path, "services", "info", args.name, "--json"]
rc, stdout, stderr = module.run_command(cmd, check_rc=True)
try:
data = json.loads(stdout)[0]
except json.JSONDecodeError:
module.fail_json(msg=f"Failed to parse JSON output:\n{stdout}")
return HomebrewServiceState(running=data["status"] == "started", pid=data["pid"])
def _exit_with_state(args, module, changed=False, message=None):
# type: (HomebrewServiceArgs, AnsibleModule, bool, Optional[str]) -> None
state = _brew_service_state(args, module)
if message is None:
message = f"Running: {state.running}, Changed: {changed}, PID: {state.pid}"
module.exit_json(msg=message, pid=state.pid, running=state.running, changed=changed)
def validate_and_load_arguments(module):
# type: (AnsibleModule) -> HomebrewServiceArgs
"""Reuse the Homebrew module's validation logic to validate these arguments."""
package = module.params["name"] # type: ignore
if not HomebrewValidate.valid_package(package):
module.fail_json(msg=f"Invalid package name: {package}")
state = module.params["state"] # type: ignore
if state not in ["present", "absent", "restarted"]:
module.fail_json(msg=f"Invalid state: {state}")
brew_path = parse_brew_path(module)
return HomebrewServiceArgs(name=package, state=state, brew_path=brew_path)
def start_service(args, module):
# type: (HomebrewServiceArgs, AnsibleModule) -> None
"""Start the requested brew service if it is not already running."""
state = _brew_service_state(args, module)
if state.running:
# Nothing to do, return early.
_exit_with_state(args, module, changed=False, message="Service already running")
if module.check_mode:
_exit_with_state(args, module, changed=True, message="Service would be started")
start_cmd = [args.brew_path, "services", "start", args.name]
rc, stdout, stderr = module.run_command(start_cmd, check_rc=True)
_exit_with_state(args, module, changed=True)
def stop_service(args, module):
# type: (HomebrewServiceArgs, AnsibleModule) -> None
"""Stop the requested brew service if it is running."""
state = _brew_service_state(args, module)
if not state.running:
# Nothing to do, return early.
_exit_with_state(args, module, changed=False, message="Service already stopped")
if module.check_mode:
_exit_with_state(args, module, changed=True, message="Service would be stopped")
stop_cmd = [args.brew_path, "services", "stop", args.name]
rc, stdout, stderr = module.run_command(stop_cmd, check_rc=True)
_exit_with_state(args, module, changed=True)
def restart_service(args, module):
# type: (HomebrewServiceArgs, AnsibleModule) -> None
"""Restart the requested brew service. This always results in a change."""
if module.check_mode:
_exit_with_state(args, module, changed=True, message="Service would be restarted")
restart_cmd = [args.brew_path, "services", "restart", args.name]
rc, stdout, stderr = module.run_command(restart_cmd, check_rc=True)
_exit_with_state(args, module, changed=True)
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(
aliases=["formula"],
required=True,
type="str",
),
state=dict(
choices=["present", "absent", "restarted"],
default="present",
),
path=dict(
default="/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin",
type="path",
),
),
supports_check_mode=True,
)
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
# Pre-validate arguments.
service_args = validate_and_load_arguments(module)
# Choose logic based on the desired state.
if service_args.state == "present":
start_service(service_args, module)
elif service_args.state == "absent":
stop_service(service_args, module)
elif service_args.state == "restarted":
restart_service(service_args, module)
if __name__ == "__main__":
main()