1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-06-11 10:35:34 +00:00
community.general/plugins/modules/kopia_notification.py
munchtoast 1e20d1f490 feat: Add kopia_notification module
- Manage Kopia notification profiles (email, Pushover, webhook) and
  message templates via the Kopia CLI.
- Extends community.general._kopia doc fragment for shared password
  and config options.
- Uses fixed args for read-only _get() list_profiles method.
2026-06-04 10:40:29 -04:00

502 lines
18 KiB
Python

#!/usr/bin/python
# Copyright (c) 2026, Dexter Le <dextersydney2001@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: kopia_notification
short_description: Manage Kopia notification profiles and templates
author:
- Dexter Le (@munchtoast)
version_added: "13.1.0"
description:
- Manage Kopia notification profiles and message templates using the Kopia CLI.
- Supports configuring email, Pushover, and webhook notification profiles,
as well as listing, showing, deleting, and testing profiles.
- Supports listing, showing, setting, and removing notification message templates.
extends_documentation_fragment:
- community.general._attributes
- community.general._kopia
attributes:
check_mode:
support: full
diff_mode:
support: none
options:
state:
description:
- Desired state of the notification resource.
- V(profile_email) creates or updates an email notification profile.
Requires O(profile_name), O(smtp_server), O(mail_to), and O(mail_from).
- V(profile_pushover) creates or updates a Pushover notification profile.
Requires O(profile_name), O(pushover_app_token), and O(pushover_user_key).
- V(profile_webhook) creates or updates a webhook notification profile.
Requires O(profile_name) and O(webhook_endpoint).
- V(profile_deleted) removes a notification profile. Requires O(profile_name).
- V(profile_tested) sends a test notification via the named profile.
Requires O(profile_name).
- V(profiles_listed) lists all configured notification profiles.
- V(profile_shown) displays a specific notification profile. Requires O(profile_name).
- V(template_set) sets a notification message template.
Requires O(template_name) and O(template_file).
- V(template_removed) removes a notification message template. Requires O(template_name).
- V(templates_listed) lists all notification message templates.
- V(template_shown) displays a specific notification message template.
Requires O(template_name).
type: str
choices:
- profile_email
- profile_pushover
- profile_webhook
- profile_deleted
- profile_tested
- profiles_listed
- profile_shown
- template_set
- template_removed
- templates_listed
- template_shown
default: profiles_listed
profile_name:
description:
- Name of the notification profile to create, update, delete, test, or show.
- Required if O(state=profile_email), O(state=profile_pushover),
O(state=profile_webhook), O(state=profile_deleted), O(state=profile_tested),
or O(state=profile_shown).
type: str
min_severity:
description:
- Minimum notification severity level that triggers this profile.
- Optional for O(state=profile_email), O(state=profile_pushover),
or O(state=profile_webhook).
type: str
choices: [verbose, info, warning, error]
format:
description:
- Message format for notifications.
- Optional for O(state=profile_email), O(state=profile_pushover),
or O(state=profile_webhook).
type: str
choices: [html, md, txt]
send_test:
description:
- When V(true), send a test notification immediately after configuring the profile.
- Optional for O(state=profile_email), O(state=profile_pushover),
or O(state=profile_webhook).
type: bool
default: false
smtp_server:
description:
- SMTP server hostname or IP address.
- Required if O(state=profile_email).
type: str
smtp_port:
description:
- SMTP server port.
- Optional if O(state=profile_email).
type: int
smtp_username:
description:
- SMTP authentication username.
- Optional if O(state=profile_email).
type: str
smtp_password:
description:
- SMTP authentication password.
- Optional if O(state=profile_email).
type: str
smtp_identity:
description:
- SMTP SASL identity string.
- Optional if O(state=profile_email).
type: str
mail_from:
description:
- Sender email address.
- Required if O(state=profile_email).
type: str
mail_to:
description:
- Recipient email address.
- Required if O(state=profile_email).
type: str
mail_cc:
description:
- CC email address.
- Optional if O(state=profile_email).
type: str
pushover_app_token:
description:
- Pushover application token.
- Required if O(state=profile_pushover).
type: str
pushover_user_key:
description:
- Pushover user key.
- Required if O(state=profile_pushover).
type: str
webhook_endpoint:
description:
- Webhook destination URL.
- Required if O(state=profile_webhook).
type: str
webhook_method:
description:
- HTTP method to use when calling the webhook.
- Optional if O(state=profile_webhook).
type: str
choices: [GET, POST, PUT, PATCH]
webhook_headers:
description:
- List of HTTP headers to include with webhook requests, each in C(key:value) format.
- Optional if O(state=profile_webhook).
type: list
elements: str
template_name:
description:
- Name of the notification template to set, remove, or show.
- Required if O(state=template_set), O(state=template_removed),
or O(state=template_shown).
type: str
template_file:
description:
- Path to a file containing the template body to set.
- Required if O(state=template_set).
type: path
"""
EXAMPLES = r"""
- name: Configure an email notification profile
community.general.kopia_notification:
state: profile_email
profile_name: ops-email
smtp_server: smtp.example.com
smtp_port: 587
smtp_username: notify@example.com
smtp_password: smtpsecret
mail_from: notify@example.com
mail_to: ops@example.com
min_severity: warning
config: /etc/kopia/root.config
- name: Configure a Pushover notification profile
community.general.kopia_notification:
state: profile_pushover
profile_name: ops-pushover
pushover_app_token: "aToken123"
pushover_user_key: "uKey456"
min_severity: error
config: /etc/kopia/root.config
- name: Configure a webhook notification profile
community.general.kopia_notification:
state: profile_webhook
profile_name: ops-webhook
webhook_endpoint: https://hooks.example.com/kopia
webhook_method: POST
webhook_headers:
- "Authorization:Bearer mytoken"
format: html
config: /etc/kopia/root.config
- name: Send a test notification
community.general.kopia_notification:
state: profile_tested
profile_name: ops-email
config: /etc/kopia/root.config
- name: Show a notification profile
community.general.kopia_notification:
state: profile_shown
profile_name: ops-email
config: /etc/kopia/root.config
- name: List all notification profiles
community.general.kopia_notification:
state: profiles_listed
config: /etc/kopia/root.config
- name: Delete a notification profile
community.general.kopia_notification:
state: profile_deleted
profile_name: ops-email
config: /etc/kopia/root.config
- name: Set a notification template from a file
community.general.kopia_notification:
state: template_set
template_name: snapshot-complete
template_file: /etc/kopia/templates/snapshot-complete.html
config: /etc/kopia/root.config
- name: List all notification templates
community.general.kopia_notification:
state: templates_listed
config: /etc/kopia/root.config
- name: Show a notification template
community.general.kopia_notification:
state: template_shown
template_name: snapshot-complete
config: /etc/kopia/root.config
- name: Remove a notification template
community.general.kopia_notification:
state: template_removed
template_name: snapshot-complete
config: /etc/kopia/root.config
"""
RETURN = r"""
kopia_notification:
description: Output from the Kopia notification command.
type: str
sample: ""
returned: always
"""
from ansible_collections.community.general.plugins.module_utils._cmd_runner import cmd_runner_fmt
from ansible_collections.community.general.plugins.module_utils._kopia import (
KOPIA_COMMON_ARGUMENT_SPEC,
kopia_runner,
)
from ansible_collections.community.general.plugins.module_utils._module_helper import StateModuleHelper
# Maps each module state to the kopia CLI words that follow `kopia notification`.
# profile configure email → ("profile", "configure", "email")
# profile delete → ("profile", "delete")
# template set → ("template", "set")
# etc.
_STATE_CLI_MAP = {
"profile_email": ("profile", "configure", "email"),
"profile_pushover": ("profile", "configure", "pushover"),
"profile_webhook": ("profile", "configure", "webhook"),
"profile_deleted": ("profile", "delete"),
"profile_tested": ("profile", "test"),
"profiles_listed": ("profile", "list"),
"profile_shown": ("profile", "show"),
"template_set": ("template", "set"),
"template_removed": ("template", "remove"),
"templates_listed": ("template", "list"),
"template_shown": ("template", "show"),
}
# Read-only states that must not be skipped in check mode.
_READONLY_STATES = frozenset(["profiles_listed", "profile_shown", "templates_listed", "template_shown"])
def _fmt_webhook_headers(value):
"""Expand a list of key:value strings into repeated --http-header flags."""
if not value:
return []
result = []
for header in value:
result.extend(["--http-header", header])
return result
class KopiaNotification(StateModuleHelper):
module = dict(
supports_check_mode=True,
argument_spec=dict(
**KOPIA_COMMON_ARGUMENT_SPEC,
state=dict(
type="str",
default="profiles_listed",
choices=[
"profile_email",
"profile_pushover",
"profile_webhook",
"profile_deleted",
"profile_tested",
"profiles_listed",
"profile_shown",
"template_set",
"template_removed",
"templates_listed",
"template_shown",
],
),
profile_name=dict(type="str"),
min_severity=dict(type="str", choices=["verbose", "info", "warning", "error"]),
format=dict(type="str", choices=["html", "md", "txt"]),
send_test=dict(type="bool", default=False),
# email
smtp_server=dict(type="str"),
smtp_port=dict(type="int"),
smtp_username=dict(type="str"),
smtp_password=dict(type="str", no_log=True),
smtp_identity=dict(type="str"),
mail_from=dict(type="str"),
mail_to=dict(type="str"),
mail_cc=dict(type="str"),
# pushover
pushover_app_token=dict(type="str", no_log=True),
pushover_user_key=dict(type="str", no_log=True),
# webhook
webhook_endpoint=dict(type="str"),
webhook_method=dict(type="str", choices=["GET", "POST", "PUT", "PATCH"]),
webhook_headers=dict(type="list", elements="str"),
# template
template_name=dict(type="str"),
template_file=dict(type="path"),
),
required_if=[
("state", "profile_email", ["profile_name", "smtp_server", "mail_from", "mail_to"]),
("state", "profile_pushover", ["profile_name", "pushover_app_token", "pushover_user_key"]),
("state", "profile_webhook", ["profile_name", "webhook_endpoint"]),
("state", "profile_deleted", ["profile_name"]),
("state", "profile_tested", ["profile_name"]),
("state", "profile_shown", ["profile_name"]),
("state", "template_set", ["template_name", "template_file"]),
("state", "template_removed", ["template_name"]),
("state", "template_shown", ["template_name"]),
],
)
def __init_module__(self):
self.runner = kopia_runner(
self.module,
extra_formats=dict(
list_profiles=cmd_runner_fmt.as_fixed("notification", "profile", "list"),
notif_group=cmd_runner_fmt.as_list(),
notif_subcommand=cmd_runner_fmt.as_list(),
notif_provider=cmd_runner_fmt.as_list(),
profile_name=cmd_runner_fmt.as_opt_val("--profile-name"),
min_severity=cmd_runner_fmt.as_opt_val("--min-severity"),
format=cmd_runner_fmt.as_opt_val("--format"),
send_test=cmd_runner_fmt.as_bool("--send-test-notification"),
smtp_server=cmd_runner_fmt.as_opt_val("--smtp-server"),
smtp_port=cmd_runner_fmt.as_opt_val("--smtp-port"),
smtp_username=cmd_runner_fmt.as_opt_val("--smtp-username"),
smtp_password=cmd_runner_fmt.as_opt_val("--smtp-password"),
smtp_identity=cmd_runner_fmt.as_opt_val("--smtp-identity"),
mail_from=cmd_runner_fmt.as_opt_val("--mail-from"),
mail_to=cmd_runner_fmt.as_opt_val("--mail-to"),
mail_cc=cmd_runner_fmt.as_opt_val("--mail-cc"),
pushover_app_token=cmd_runner_fmt.as_opt_val("--app-token"),
pushover_user_key=cmd_runner_fmt.as_opt_val("--user-key"),
webhook_endpoint=cmd_runner_fmt.as_opt_val("--endpoint"),
webhook_method=cmd_runner_fmt.as_opt_val("--method"),
webhook_headers=cmd_runner_fmt.as_func(_fmt_webhook_headers),
template_name=cmd_runner_fmt.as_list(),
template_file=cmd_runner_fmt.as_list(),
),
)
self.vars.set("previous_value", self._get()["out"])
self.vars.set("value", self.vars.previous_value, change=True, diff=True)
def __quit_module__(self):
self.vars.set("value", self._get()["out"])
def _get(self):
with self.runner("list_profiles config") as ctx:
result = ctx.run()
return dict(
rc=result[0],
out=(result[1].rstrip() if result[1] else None),
err=result[2],
)
def _process_command_output(self, fail_on_err, ignore_err_msg=""):
def process(rc, out, err):
if fail_on_err and rc != 0 and err and ignore_err_msg not in err:
self.do_raise(f"kopia failed with error (rc={rc}): {err}")
out = out.rstrip() if out else ""
return None if out == "" else out
return process
def _run_notif_cmd(self, args_order, ignore_err_msg="", **run_kwargs):
cli_words = _STATE_CLI_MAP[self.vars.state]
notif_group = cli_words[0]
notif_subcommand = cli_words[1]
notif_provider = cli_words[2] if len(cli_words) == 3 else None
check_mode_skip = self.vars.state not in _READONLY_STATES
with self.runner(
args_order,
output_process=self._process_command_output(True, ignore_err_msg),
check_mode_skip=check_mode_skip,
) as ctx:
ctx.run(
cli_action="notification",
notif_group=notif_group,
notif_subcommand=notif_subcommand,
notif_provider=notif_provider,
**run_kwargs,
)
def state_profile_email(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand notif_provider"
" profile_name smtp_server smtp_port smtp_username smtp_password"
" smtp_identity mail_from mail_to mail_cc"
" min_severity format send_test config",
)
def state_profile_pushover(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand notif_provider"
" profile_name pushover_app_token pushover_user_key"
" min_severity format send_test config",
)
def state_profile_webhook(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand notif_provider"
" profile_name webhook_endpoint webhook_method webhook_headers"
" min_severity format send_test config",
)
def state_profile_deleted(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand profile_name config",
ignore_err_msg="no such profile",
)
def state_profile_tested(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand profile_name config",
)
def state_profiles_listed(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand config",
)
def state_profile_shown(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand profile_name config",
)
def state_template_set(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand template_name template_file config",
)
def state_template_removed(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand template_name config",
ignore_err_msg="no such template",
)
def state_templates_listed(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand config",
)
def state_template_shown(self):
self._run_notif_cmd(
"cli_action notif_group notif_subcommand template_name config",
)
def main():
KopiaNotification.execute()
if __name__ == "__main__":
main()