1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-06-11 18:45:34 +00:00
community.general/plugins/module_utils/_kopia.py
patchback[bot] f7647b2131
[PR #11752/d4031f36 backport][stable-13] kopia: Add kopia_repository module (#12127)
kopia: Add kopia_repository module (#11752)

* Add kopia module util

* fix pipeline suggestions

* add kopia repository module

* apply code review changes

* remove kopia_runner instance unit test

* update botmeta with kopia

* refactor docs and redundant state

* add kopia_info module and fix kopia_repository check mode support

- Add kopia_info module for read-only repository information gathering
  (kopia repository status, kopia repository throttle get) following
  the pacemaker_info pattern with ModuleHelper and info_module fragment
- Add _fmt_throttle to _kopia.py and register throttle format in
  kopia_runner; remove throttle_operation get option from
  kopia_repository per Ansible best practices (info ops belong in
  _info modules)
- Add throttle suboption dict to kopia_repository with all seven
  kopia repository throttle set flags
- Fix check_mode: support from full to actually full by implementing
  _predict_value() in kopia_repository; previously check_mode_skip
  caused changed to always be false in check mode
- Add check mode test cases to test_kopia_repository.yaml covering
  created and disconnected states for both connected and disconnected
  initial conditions
- Add BOTMETA.yml entry and full test fixture for kopia_info

* apply code review suggestions

(cherry picked from commit d4031f36e4)

Co-authored-by: munchtoast <45038532+munchtoast@users.noreply.github.com>
2026-05-30 15:12:10 +02:00

162 lines
5.5 KiB
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
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
# Do not use this from other collections or standalone plugins/modules!
from __future__ import annotations
import typing as t
from ansible_collections.community.general.plugins.module_utils._cmd_runner import CmdRunner, cmd_runner_fmt
if t.TYPE_CHECKING:
from ansible.module_utils.basic import AnsibleModule
# Maps kopia_repository module state values to kopia CLI subcommands.
# Used with cmd_runner_fmt.as_map() for the 'state' arg format.
REPOSITORY_STATE_MAP = {
"created": "create",
"connected": "connect",
"disconnected": "disconnect",
"synced": "sync-to",
"throttled": "throttle",
}
# Maps backend provider names to their CLI flag names.
# Each provider emits its name as a positional sub-subcommand, followed by
# --flag value pairs for each non-None param.
# The "server" provider is intentionally absent: `kopia repository connect server`
# uses top-level flags (--url, --server-cert-fingerprint) rather than backend flags,
# so fmt_backend() returns [] for it and those flags are passed separately.
_PROVIDER_BACKEND_MAP = {
"azure": {
"container": "--container",
"storage_account": "--storage-account",
"storage_key": "--storage-key",
"sas_token": "--sas-token",
"storage_domain": "--storage-domain",
"prefix": "--prefix",
},
"b2": {
"bucket": "--bucket",
"access_key": "--key-id",
"secret_access_key": "--key",
"prefix": "--prefix",
},
"filesystem": {
"path": "--path",
},
"gcs": {
"bucket": "--bucket",
"credentials_file": "--credentials-file",
"prefix": "--prefix",
},
"gdrive": {
"folder_id": "--folder-id",
"credentials_file": "--credentials-file",
},
"rclone": {
"path": "--remote-path",
},
"s3": {
"bucket": "--bucket",
"access_key": "--access-key",
"secret_access_key": "--secret-access-key",
"endpoint": "--endpoint",
"region": "--region",
"prefix": "--prefix",
"session_token": "--session-token",
},
"sftp": {
"path": "--path",
"host": "--host",
"username": "--username",
"port": "--port",
"keyfile": "--keyfile",
"known_hosts": "--known-hosts",
},
"webdav": {
"url": "--url",
"webdav_username": "--webdav-username",
"webdav_password": "--webdav-password",
},
}
# Argument spec entries shared by all kopia modules.
# Include this in each module's argument_spec via dict unpacking.
KOPIA_COMMON_ARGUMENT_SPEC = dict(
password=dict(type="str", no_log=True),
config=dict(type="path"),
)
def fmt_backend(value):
"""Format the backend dict into positional + flag arguments for kopia CLI.
For most providers the output is:
[provider_name, --flag1, value1, --flag2, value2, ...]
For the "server" provider, returns [] because server connect uses top-level
flags (--url, --server-cert-fingerprint) passed separately.
"""
provider = value["provider"]
if provider == "server":
return []
result = [provider]
for param_name, flag in _PROVIDER_BACKEND_MAP[provider].items():
param_value = value.get(param_name)
if param_value is not None:
result.append(f"{flag}={param_value}")
return result
def _fmt_throttle(value):
"""Format the throttle dict into --flag value arguments for kopia repository throttle set."""
if not value:
return []
flag_map = {
"download_bytes_per_second": "--download-bytes-per-second",
"upload_bytes_per_second": "--upload-bytes-per-second",
"read_requests_per_second": "--read-requests-per-second",
"write_requests_per_second": "--write-requests-per-second",
"list_requests_per_second": "--list-requests-per-second",
"concurrent_reads": "--concurrent-reads",
"concurrent_writes": "--concurrent-writes",
}
result = []
for param, flag in flag_map.items():
v = value.get(param)
if v is not None:
result.extend([flag, str(v)])
return result
def kopia_runner(module: AnsibleModule, extra_formats: dict | None = None, **kwargs) -> CmdRunner:
"""Create a CmdRunner for the kopia CLI.
Provides arg formats for all params shared across kopia modules.
Pass extra_formats to add module-specific arg formats on top of the shared ones.
"""
formats = dict(
cli_action=cmd_runner_fmt.as_list(),
status=cmd_runner_fmt.as_fixed("repository", "status"),
get_throttle=cmd_runner_fmt.as_fixed("repository", "throttle", "get"),
state=cmd_runner_fmt.as_map(REPOSITORY_STATE_MAP),
backend=cmd_runner_fmt.as_func(fmt_backend),
password=cmd_runner_fmt.as_opt_eq_val("--password"),
fingerprint_tls=cmd_runner_fmt.as_opt_eq_val("--server-cert-fingerprint"),
url=cmd_runner_fmt.as_opt_eq_val("--url"),
config=cmd_runner_fmt.as_opt_eq_val("--config-file"),
throttle_operation=cmd_runner_fmt.as_list(),
throttle=cmd_runner_fmt.as_func(_fmt_throttle),
)
if extra_formats:
formats.update(extra_formats)
return CmdRunner(
module,
command=["kopia"],
arg_formats=formats,
**kwargs,
)