This commit is contained in:
Luca Bilke 2024-12-11 18:42:59 +01:00
parent 2006d16b30
commit dd82a95cf1
Signed by: luca
GPG Key ID: F6E11C9BAA7C82F5
21 changed files with 325 additions and 456 deletions

4
plugins/__init__.py Normal file
View File

@ -0,0 +1,4 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""A collection to ease the creation of docker compose files using ansible."""

View File

@ -0,0 +1,4 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Module utilities for ez_compose modules."""

View File

@ -1,17 +1,21 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Common module utilities."""
from __future__ import annotations
import copy
from dataclasses import asdict, dataclass, field, replace
from pathlib import Path
from typing import Any, Callable
import yaml
from ansible.module_utils.basic import AnsibleModule
PROJECTS_DIR = "/var/lib/ez_compose"
BASE_SERVICE_ARGS = {
BASE_ARGS = {
"project_name": {
"type": "str",
"required": True,
@ -20,59 +24,41 @@ BASE_SERVICE_ARGS = {
"type": "str",
"required": True,
},
"image": {
"type": "str",
},
"state": {
"type": "str",
"default": "present",
"choices": ["present", "absent"],
},
"defaults": {
"type": "dict",
},
}
BASE_LABEL_ARGS = {
"project_name": {
"type": "str",
"required": True,
},
"name": {
"type": "str",
"required": True,
},
"state": {
"type": "str",
"default": "present",
"choices": ["present", "absent"],
},
}
@dataclass(frozen=True)
class Result:
"""Module result object."""
changed: bool = False
diff: dict[str, Any] = field(default_factory=dict)
@dataclass(frozen=True)
class Settings:
projects_dir: str = "/usr/local/share/ez_compose/"
# @dataclass(frozen=True)
# class Settings:
# projects_dir: str = "/usr/local/share/ez_compose/"
@dataclass(frozen=True)
class State:
module: Any # Replace Any with the actual type of AnsibleModule if available
"""Execution state object."""
module: AnsibleModule
result: Result
compose_filepath: str
before: dict[str, Any]
after: dict[str, Any]
def _recursive_update(default: dict[Any, Any], update: dict[Any, Any]) -> dict[Any, Any]:
for key in update:
def recursive_update(
default: dict[Any, Any],
update: dict[Any, Any],
) -> dict[Any, Any]:
"""Recursively update a dictionary."""
for key in update: # noqa: PLC0206
if isinstance(update[key], dict) and isinstance(default.get(key), dict):
default[key] = _recursive_update(default[key], update[key])
default[key] = recursive_update(default[key], update[key])
elif isinstance(update[key], list) and isinstance(default.get(key), list):
default_set = set(default[key])
@ -86,10 +72,13 @@ def _recursive_update(default: dict[Any, Any], update: dict[Any, Any]) -> dict[A
def get_state(module: AnsibleModule) -> State:
compose_filepath = f"{PROJECTS_DIR}/{module.params['project_name']}/docker-compose.yml"
"""Create a new state object, loading the compose file into "before" if it exists."""
compose_filepath = (
f"{PROJECTS_DIR}/{module.params['project_name']}/docker-compose.yml"
)
try:
with open(compose_filepath, "r") as fp:
with Path(compose_filepath).open("r") as fp:
before = yaml.safe_load(fp)
except FileNotFoundError:
@ -100,92 +89,11 @@ def get_state(module: AnsibleModule) -> State:
result=Result(),
compose_filepath=compose_filepath,
before=before,
after=before,
after={},
)
def apply_service_base(state: State) -> State:
service_name = state.module.params["name"]
project_name = state.module.params["project_name"]
image = state.module.params["image"]
update: dict[str, Any] = {
"service_name": f"{project_name}_{service_name}",
"hostname": f"{project_name}_{service_name}",
"image": image,
"restart": "unless-stopped",
"environment": {},
"labels": {},
"volumes": [],
"networks": {
f"{project_name}_internal": None,
},
}
return update_service(state, update)
def set_service_defaults(state: State) -> State:
container_name = state.module.params["name"]
defaults = state.module.params["defaults"]
project = copy.deepcopy(state.after)
services = project["services"]
service = services[container_name]
_ = _recursive_update(service, defaults)
services.update({container_name: service})
return replace(state, after=project)
def update_service(state: State, update: dict[str, Any]) -> State:
project = copy.deepcopy(state.after)
service_name = state.module.params["name"]
_ = _recursive_update(project["services"][service_name], update)
return replace(state, after=project)
def remove_service(state: State) -> State:
project = copy.deepcopy(state.after)
service_name = state.module.params["name"]
del project["services"][service_name]
return replace(state, after=project)
def remove_labels(state: State, label_names: list[str]) -> State:
project = copy.deepcopy(state.after)
service_name = state.module.params["name"]
service = project["services"].get(service_name, {})
labels = service.get("labels", {})
if labels:
for label in labels:
if label in label_names:
try:
del service["labels"][label]
except KeyError:
pass
service["labels"] = labels
else:
try:
del service["labels"]
except KeyError:
pass
project["services"][service_name] = service
return replace(state, after=project)
def update_project(state: State) -> State:
"""Ensure that networks/volumes that exist in services also exist in the project."""
project = copy.deepcopy(state.after)
project_services = project.get("services", {})
@ -200,7 +108,7 @@ def update_project(state: State) -> State:
service_volume_name: None
for service_volume_name in service_volume_names
if service_volume_name not in project_volumes
}
},
)
if service_network_names := service.get("networks").keys():
@ -209,67 +117,37 @@ def update_project(state: State) -> State:
service_network_name: None
for service_network_name in service_network_names
if service_network_name not in project_networks
}
},
)
return replace(state, after=project)
def write_compose(state: State) -> State:
"""Write the compose file to disk."""
file = state.compose_filepath
with open(file, mode="w") as stream:
with Path(file).open(mode="w") as stream:
yaml.dump(state.after, stream)
return state
def run_service(
extra_args: dict[str, Any] = {},
helper: Callable[[State], State] = lambda _: _,
def run_module(
args: dict[str, Any] | None = None,
execute: Callable[[State], State] = lambda _: _,
) -> None:
"""Handle module setup and teardown."""
module = AnsibleModule(
argument_spec={**BASE_SERVICE_ARGS, **extra_args},
argument_spec={**BASE_ARGS, **(args or {})},
supports_check_mode=True,
)
state = get_state(module)
if module.params["state"] == "absent":
state = remove_service(state)
state = execute(state)
else:
for f in [apply_service_base, set_service_defaults, helper, update_project]:
state = f(state)
exit(state)
def run_label(
extra_args: dict[str, Any], helper: Callable[[State], State], label_names: list[str]
) -> None:
module = AnsibleModule(
argument_spec={**BASE_LABEL_ARGS, **extra_args},
supports_check_mode=True,
)
state = get_state(module)
if module.params["state"] == "absent":
state = remove_labels(state, label_names)
else:
state = helper(state)
exit(state)
def exit(state: State) -> None:
# TODO: Check diff and set changed variable
if state.module.check_mode:
state.module.exit_json(**asdict(state.result)) # type: ignore[reportUnkownMemberType]
_ = write_compose(state)
if not state.module.check_mode:
write_compose(state)
state.module.exit_json(**asdict(state.result)) # type: ignore[reportUnkownMemberType]

View File

@ -0,0 +1,4 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Module utilities for ez_compose label modules."""

View File

@ -0,0 +1,21 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Label module utilities."""
from __future__ import annotations
from typing import Any, Callable
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_module,
)
def run(
extra_args: dict[str, Any] | None = None,
helper: Callable[[State], State] = lambda _: _,
) -> None:
"""Wrap module execution function for label helpers."""
run_module(extra_args or {}, helper)

View File

@ -0,0 +1,37 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Docker Volume Backup label helper."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import ansible_collections.snailed.ez_compose.plugins.module_utils.label.common as label
import ansible_collections.snailed.ez_compose.plugins.module_utils.service.common as service
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
"""Add labels to the service to stop it during backup."""
stop = state.module.params.get("stop", True)
project_name = state.module.params["project_name"]
update: dict[str, Any] = {}
if stop:
update["labels"] = {
"docker-volume-backup.stop-during-backup": project_name,
}
return service.update(state, update)
def run() -> None:
"""Run the backupper label helper."""
extra_args = {
"stop": {"type": "bool"},
}
label.run(extra_args, helper)

View File

@ -1,27 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
import ansible_collections.snailed.ez_compose.plugins.module_utils.label.common as label
import ansible_collections.snailed.ez_compose.plugins.module_utils.service.common as service
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_label,
update_service,
)
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
@ -43,7 +31,7 @@ def helper(state: State) -> State:
"labels": labels,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -53,7 +41,7 @@ def main():
"middleware": {"type": "str", "required": True},
"settings": {"type": "list", "required": True},
}
run_label(extra_args, helper)
label.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,34 +1,22 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
import ansible_collections.snailed.ez_compose.plugins.module_utils.label.common as label
import ansible_collections.snailed.ez_compose.plugins.module_utils.service.common as service
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_label,
update_service,
)
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
service_name = state.module.params["name"]
project_name = state.module.params["project_name"]
rule = state.module.params["rule"]
service = state.module.params.get("service")
traefik_service = state.module.params.get("service")
entrypoints = state.module.params.get("entrypoints")
middlewares = state.module.params.get("middlewares")
certresolver = state.module.params.get("certresolver")
@ -51,8 +39,8 @@ def helper(state: State) -> State:
if entrypoints:
labels[f"{prefix}.entrypoints"] = ",".join(entrypoints)
if service:
labels[f"{prefix}.service"] = service
if traefik_service:
labels[f"{prefix}.service"] = traefik_service
if middlewares:
labels[f"{prefix}.middlewares"] = ",".join(middlewares)
@ -61,7 +49,7 @@ def helper(state: State) -> State:
"labels": labels,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -76,7 +64,7 @@ def main():
"entrypoints": {"type": "list"},
"middlewares": {"type": "list"},
}
run_label(extra_args, helper)
label.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,27 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
import ansible_collections.snailed.ez_compose.plugins.module_utils.label.common as label
import ansible_collections.snailed.ez_compose.plugins.module_utils.service.common as service
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_label,
update_service,
)
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
from typing import Any
@ -48,7 +36,7 @@ def helper(state: State) -> State:
"labels": labels,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -57,7 +45,7 @@ def main():
"service_name": {"type": "string"},
"port": {"type": "int"},
}
run_label(extra_args, helper)
label.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -0,0 +1,4 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Module utilities for ez_compose service modules."""

View File

@ -0,0 +1,94 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
"""Service module utilities."""
from __future__ import annotations
import copy
from dataclasses import replace
from typing import Any, Callable
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
recursive_update,
run_module,
update_project,
)
BASE_SERVICE_ARGS = {
"project_name": {
"type": "str",
"required": True,
},
"name": {
"type": "str",
"required": True,
},
"image": {
"type": "str",
},
"defaults": {
"type": "dict",
},
}
def apply_base(state: State) -> State:
"""Apply base service configuration."""
service_name = state.module.params["name"]
project_name = state.module.params["project_name"]
image = state.module.params["image"]
new: dict[str, Any] = {
"service_name": f"{project_name}_{service_name}",
"hostname": f"{project_name}_{service_name}",
"image": image,
"restart": "unless-stopped",
"environment": {},
"labels": {},
"volumes": [],
"networks": {
f"{project_name}_internal": None,
},
}
return update(state, new)
def set_defaults(state: State) -> State:
"""Set default values for a service."""
container_name = state.module.params["name"]
defaults = state.module.params["defaults"]
project = copy.deepcopy(state.after)
services = project["services"]
service = services[container_name]
_ = recursive_update(service, defaults)
services.update({container_name: service})
return replace(state, after=project)
def update(state: State, update: dict[str, Any]) -> State:
"""Update a service with the given dictionary."""
project = copy.deepcopy(state.after)
service_name = state.module.params["name"]
_ = recursive_update(project["services"][service_name], update)
return replace(state, after=project)
def run(
extra_args: dict[str, Any] | None = None,
helper: Callable[[State], State] = lambda _: _,
) -> None:
"""Wrap module execution function for service helpers."""
def execute(state: State) -> State:
for f in [apply_base, set_defaults, helper, update_project]:
state = f(state)
return state
run_module({**BASE_SERVICE_ARGS, **(extra_args or {})}, execute)

View File

@ -1,34 +1,21 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
DOCUMENTATION = r"""
"""
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from __future__ import annotations
import copy
from typing import TYPE_CHECKING
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
exit,
finish,
get_state,
remove_service,
update_project,
update_service,
)
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
project_name = state.module.params["project_name"]
@ -44,7 +31,7 @@ def helper(state: State) -> State:
update["networks"] = networks
return update_service(state, update)
return service.update(state, update)
def main():
@ -76,14 +63,10 @@ def main():
state = get_state(module)
if module.params["state"] == "absent":
state = remove_service(state)
for f in [helper, update_project]:
state = f(state)
else:
for f in [helper, update_project]:
state = f(state)
exit(state)
finish(state)
if __name__ == "__main__":

View File

@ -1,28 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_service,
update_service,
)
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
command = state.module.params.get("command")
@ -34,14 +20,14 @@ def helper(state: State) -> State:
if command:
update["command"] = command
return update_service(state, update)
return service.update(state, update)
def main():
extra_args = {
"command": {"type": "list"},
}
run_service(extra_args, helper)
service.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,27 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_service,
update_service,
)
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
@ -40,14 +27,14 @@ def helper(state: State) -> State:
"volumes": volumes,
}
return update_service(state, update)
return service.update(state, update)
def main():
extra_args = {
"read_only": {"type": "bool"},
}
run_service(extra_args, helper)
service.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,27 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
from __future__ import annotations
DOCUMENTATION = r"""
"""
from typing import TYPE_CHECKING
EXAMPLES = r"""
"""
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_service,
update_service,
)
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
@ -64,7 +51,7 @@ def helper(state: State) -> State:
"volumes": volumes,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -72,7 +59,7 @@ def main():
"archive": {"type": "str"},
"backup_volumes": {"type": "list"},
}
run_service(extra_args, helper)
service.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,29 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
DOCUMENTATION = r"""
"""
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from __future__ import annotations
import shlex
from typing import TYPE_CHECKING
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_service,
update_service,
)
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
@ -40,7 +26,7 @@ def helper(state: State) -> State:
"source": service_name,
"target": "/var/lib/mysql",
"type": "volume",
}
},
]
environment = {
@ -55,7 +41,7 @@ def helper(state: State) -> State:
environment.update(
{
"MARIADB_ROOT_PASSWORD": root_password,
}
},
)
if backup:
@ -68,8 +54,8 @@ def helper(state: State) -> State:
f"-p {shlex.quote(password)} "
f">/backup/{shlex.quote(project_name)}.sql"
"'"
)
}
),
},
)
# mysqldump -psecret --all-databases > /tmp/dumps/dump.sql
volumes.append(
@ -77,7 +63,7 @@ def helper(state: State) -> State:
"type": "volume",
"source": f"{service_name}_backup",
"target": "/backup",
}
},
)
update = {
@ -86,7 +72,7 @@ def helper(state: State) -> State:
"labels": labels,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -97,7 +83,7 @@ def main():
"password": {"type": "str", "required": True},
"root_password": {"type": "str"},
}
run_service(extra_args, helper)
service.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -1,29 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
DOCUMENTATION = r"""
"""
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from __future__ import annotations
import shlex
from typing import TYPE_CHECKING
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_service,
update_service,
)
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
if TYPE_CHECKING:
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import State
def helper(state: State) -> State:
@ -39,7 +25,7 @@ def helper(state: State) -> State:
"source": service_name,
"target": "/var/lib/postgresql/data",
"type": "volume",
}
},
]
environment = {
@ -60,8 +46,8 @@ def helper(state: State) -> State:
f"-U {shlex.quote(username)} "
f"-f /backup/{shlex.quote(project_name)}.sql"
"'"
)
}
),
},
)
volumes.append(
@ -69,7 +55,7 @@ def helper(state: State) -> State:
"type": "volume",
"source": f"{service_name}_backup",
"target": "/backup",
}
},
)
update = {
@ -78,7 +64,7 @@ def helper(state: State) -> State:
"labels": labels,
}
return update_service(state, update)
return service.update(state, update)
def main():
@ -88,7 +74,7 @@ def main():
"username": {"type": "str", "required": True},
"password": {"type": "str", "required": True},
}
run_service(extra_args, helper)
service.run(extra_args, helper)
if __name__ == "__main__":

View File

@ -0,0 +1,14 @@
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
from __future__ import annotations
from ansible_collections.snailed.ez_compose.plugins.module_utils.service import common as service
def main():
service.run()
if __name__ == "__main__":
main()

View File

@ -1,51 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
DOCUMENTATION = r"""
"""
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from typing import Any
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
State,
run_label,
update_service,
)
def helper(state: State) -> State:
stop = state.module.params.get("stop", True)
project_name = state.module.params["project_name"]
update: dict[str, Any] = {}
if stop:
update["labels"] = {
"docker-volume-backup.stop-during-backup": project_name,
}
return update_service(state, update)
def main():
extra_args = {
"stop": {"type": "bool"},
}
run_label(extra_args, helper)
if __name__ == "__main__":
main()

View File

@ -1,28 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# TODO: write ansible sections
DOCUMENTATION = r"""
"""
EXAMPLES = r"""
"""
RETURN = r"""
"""
from __future__ import annotations # pyright: ignore[reportGeneralTypeIssues]
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import run_service
def main():
run_service()
if __name__ == "__main__":
main()

View File

@ -1,18 +1,27 @@
[tool.black]
[tool.ruff]
line-length = 100
show-fixes = true
output-format = "grouped"
[tool.ruff.lint]
select = ["ALL"]
ignore = ["ERA001", "TD002", "TD003"]
[tool.ruff.format]
line-ending = "lf"
[tool.ruff.lint.mccabe]
max-complexity = 10
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.basedpyright]
typeCheckingMode = "strict"
reportIgnoreCommentWithoutRule = true
reportUnusedCallResult = true
reportMissingTypeStubs = false
# handled by ruff
reportUnusedVariable = false
# Handled by ruff
reportIgnoreCommentWithoutRule = false
reportUnusedImport = false
reportUndefinedVariable = false
[tool.ruff.lint]
# Irrelevant for ansible
ignore = ["E402", "F404"]
reportUnusedClass = false
reportUnusedFunction = false
reportUnusedVariable = false