Compare commits
4 commits
dfcbfe013f
...
7b8f646293
Author | SHA1 | Date | |
---|---|---|---|
7b8f646293 | |||
c78e240884 | |||
77e32d4543 | |||
c2ceb239a3 |
22 changed files with 271 additions and 212 deletions
.lazy.luaLICENSEpyproject.toml
plugins
module_utils
common.py
label
__init__.pycommon.pydocker_volume_backupper.pytraefik_middleware.pytraefik_router.pytraefik_service.py
models.pyservice
__init__.pycommon.pycustom.pydocker_in_docker.pydocker_socket_proxy.pydocker_volume_backupper.pymariadb.pypostgres.pyredis.py
spec.pymodules
31
.lazy.lua
Normal file
31
.lazy.lua
Normal file
|
@ -0,0 +1,31 @@
|
|||
local function find_table_with_value(tables, search_value)
|
||||
for _, tbl in ipairs(tables) do
|
||||
for _, value in pairs(tbl) do
|
||||
if value == search_value then
|
||||
return tbl
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
{
|
||||
"mfussenegger/nvim-dap",
|
||||
optional = true,
|
||||
config = function()
|
||||
local root = vim.lsp.get_clients()[1].root_dir
|
||||
table.insert(require("dap").configurations.python, {
|
||||
type = "python",
|
||||
request = "launch",
|
||||
name = "custom",
|
||||
program = root .. "/plugins/modules/compose.py",
|
||||
console = "integratedTerminal",
|
||||
pythonPath = os.getenv("VIRTUAL_ENV") .. "/bin/python",
|
||||
args = { root .. "/test.json" },
|
||||
justMyCode = false,
|
||||
})
|
||||
find_table_with_value(require("lazyvim.plugins.extras.dap.core"), "mfussenegger/nvim-dap").config()
|
||||
end,
|
||||
},
|
||||
}
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright 2024 Luca Bilke
|
||||
Copyright 2025 Luca Bilke
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
|||
import copy
|
||||
from dataclasses import replace
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
|
||||
import yaml
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import Result, State
|
||||
|
@ -15,23 +15,32 @@ if TYPE_CHECKING:
|
|||
from ansible.module_utils.basic import AnsibleModule # pyright: ignore[reportMissingTypeStubs]
|
||||
|
||||
|
||||
def clean_none(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
obj = copy.deepcopy(obj)
|
||||
for k in copy.deepcopy(obj):
|
||||
if obj.get(k, "sentinel") is None:
|
||||
del obj[k]
|
||||
return obj
|
||||
|
||||
def recursive_update(
|
||||
default: dict[Any, Any],
|
||||
update: dict[Any, Any],
|
||||
) -> dict[Any, Any]:
|
||||
default: dict[str, Any],
|
||||
update: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
default = copy.deepcopy(default)
|
||||
|
||||
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])
|
||||
for k, v in update.items():
|
||||
if isinstance(v, dict):
|
||||
v = cast(dict[str, Any], v)
|
||||
default[k] = recursive_update(default.get(k) or {}, v)
|
||||
|
||||
elif isinstance(update[key], list) and isinstance(default.get(key), list):
|
||||
default_set = set(default[key])
|
||||
custom_set = set(update[key])
|
||||
default[key] = list(default_set.union(custom_set))
|
||||
elif isinstance(v, list):
|
||||
v = cast(list[Any], v)
|
||||
new = cast(list[Any], (default.get(k) or []))
|
||||
new.extend(v)
|
||||
default[k] = new
|
||||
|
||||
else:
|
||||
default[key] = update[key]
|
||||
default[k] = v
|
||||
|
||||
return default
|
||||
|
||||
|
@ -91,6 +100,49 @@ def update_project(state: State) -> State:
|
|||
return replace(state, after=project)
|
||||
|
||||
|
||||
def set_result(state: State) -> State: # noqa: C901
|
||||
def _changed(before: Any, after: Any) -> bool: # noqa: ANN401, C901, PLR0911
|
||||
if type(before) is not type(after):
|
||||
return True
|
||||
|
||||
if isinstance(before, dict):
|
||||
before = cast(dict[str, Any], before)
|
||||
|
||||
if len(before) != len(after):
|
||||
return True
|
||||
|
||||
for key in before:
|
||||
if key not in after:
|
||||
return True
|
||||
if _changed(before[key], after[key]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
if isinstance(before, list):
|
||||
before = sorted(cast(list[Any], before))
|
||||
after = sorted(after)
|
||||
|
||||
if len(before) != len(after):
|
||||
return True
|
||||
|
||||
for index in before.enumerate():
|
||||
if _changed(before[index], after[index]):
|
||||
return True
|
||||
|
||||
return before != after
|
||||
|
||||
result = Result(
|
||||
_changed(state.before, state.after),
|
||||
{
|
||||
"before": state.before,
|
||||
"after": state.after,
|
||||
},
|
||||
)
|
||||
|
||||
return replace(state, result=result)
|
||||
|
||||
|
||||
def write_compose(state: State) -> State:
|
||||
file = state.compose_filepath
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -1,23 +1,42 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
|
||||
clean_none,
|
||||
recursive_update,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
|
||||
BASE_ARGS: dict[str, Any] = {}
|
||||
|
||||
|
||||
def apply_update(
|
||||
service: dict[str, Any],
|
||||
update: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
return recursive_update(service, update)
|
||||
|
||||
|
||||
def get_default_args(state: State, helper_name: str) -> dict[str, Any]:
|
||||
settings: dict[str, Any] = state.module.params.get("settings") or {}
|
||||
label_default_args: dict[str, Any] = settings.get("label_default_args") or {}
|
||||
default_args: dict[str, Any] = label_default_args.get(helper_name) or {}
|
||||
return clean_none(default_args)
|
||||
|
||||
|
||||
def run_helper(
|
||||
state: State,
|
||||
service_name: str,
|
||||
service: dict[str, Any],
|
||||
params: dict[str, Any],
|
||||
helper: Callable[[State, str, dict[str, Any]], State] = lambda a, _b, _c: a,
|
||||
) -> State:
|
||||
return helper(state, service_name, params)
|
||||
helper: Callable[[State, str, dict[str, Any]], dict[str, Any]] = lambda _a, _b, _c: {},
|
||||
) -> dict[str, Any]:
|
||||
update = helper(state, service_name, params)
|
||||
return apply_update(service, update)
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"stop": {"type": "bool", "default": True},
|
||||
}
|
||||
|
||||
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, _service_name: str, params: dict[str, Any]) -> dict[str, Any]:
|
||||
stop: bool = params["stop"]
|
||||
project_name: str = state.module.params["name"]
|
||||
|
||||
|
@ -28,4 +24,4 @@ def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
|||
"docker-volume-backup.stop-during-backup": project_name,
|
||||
}
|
||||
|
||||
return service.common.update(state, {"name": service_name}, update)
|
||||
return update
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"proxy_type": {"type": "str", "default": "http"},
|
||||
|
@ -20,22 +16,19 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
middleware: str = params["middleware"]
|
||||
settings: dict[str, str] = params["settings"]
|
||||
proxy_type: str = state.module.params["proxy_type"]
|
||||
proxy_type: str = params["proxy_type"]
|
||||
name: str = (
|
||||
params.get("name")
|
||||
or f"{project_name}_{service_name}_{proxy_type}_{middleware.lower()}"
|
||||
params.get("name") or f"{project_name}_{service_name}_{proxy_type}_{middleware.lower()}"
|
||||
)
|
||||
|
||||
prefix = f"traefik.{proxy_type}.middlewares.{name}"
|
||||
|
||||
labels = {f"{prefix}.{middleware}.{key}": var for key, var in settings.items()}
|
||||
|
||||
update = {
|
||||
return {
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
return service.common.update(state, {"name": service_name}, update)
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"name": {"type": "str"},
|
||||
|
@ -23,7 +19,7 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
rule: str = params["rule"]
|
||||
traefik_service: str | None = params.get("service")
|
||||
|
@ -52,8 +48,6 @@ def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
|||
if middlewares:
|
||||
labels[f"{prefix}.middlewares"] = ",".join(middlewares)
|
||||
|
||||
update = {
|
||||
return {
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
return service.common.update(state, {"name": service_name}, update)
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"proxy_type": {"type": "str", "default": "http"},
|
||||
|
@ -19,7 +15,7 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, service_name: str, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
port: int | None = params.get("port")
|
||||
proxy_type: str = params["proxy_type"]
|
||||
|
@ -32,8 +28,6 @@ def helper(state: State, service_name: str, params: dict[str, Any]) -> State:
|
|||
if port:
|
||||
labels[f"{prefix}.loadbalancer.server.port"] = str(port)
|
||||
|
||||
update = {
|
||||
return {
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
return service.common.update(state, {"name": service_name}, update)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
|||
@dataclass(frozen=True)
|
||||
class Result:
|
||||
changed: bool = False
|
||||
diff: dict[str, Any] = field(default_factory=dict)
|
||||
diff: dict[str, Any] | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
@ -8,14 +8,12 @@ from dataclasses import replace
|
|||
from typing import TYPE_CHECKING, Any, Callable
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
|
||||
clean_none,
|
||||
recursive_update,
|
||||
update_project,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
BASE_ARGS: dict[str, Any] = {
|
||||
"name": {"type": "str"},
|
||||
|
@ -23,85 +21,70 @@ BASE_ARGS: dict[str, Any] = {
|
|||
}
|
||||
|
||||
|
||||
def apply_base(state: State, params: dict[str, Any]) -> State:
|
||||
def get_base_definition(state: State, service_name: str) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
|
||||
new: dict[str, Any] = {
|
||||
"container_name": f"{project_name}_{params['name']}",
|
||||
"hostname": f"{project_name}_{params['name']}",
|
||||
return {
|
||||
"container_name": f"{project_name}_{service_name}",
|
||||
"hostname": f"{project_name}_{service_name}",
|
||||
"restart": "unless-stopped",
|
||||
"environment": {},
|
||||
"labels": {},
|
||||
"volumes": [],
|
||||
"networks": {
|
||||
"internal": None,
|
||||
},
|
||||
} | (
|
||||
state.module.params.get("settings", {})
|
||||
.get("default_definition", {})
|
||||
.get(params["name"], {})
|
||||
)
|
||||
|
||||
return update(state, params, new)
|
||||
# TODO: this should be set per service helper
|
||||
# "networks": {
|
||||
# "internal": None,
|
||||
# },
|
||||
}
|
||||
|
||||
|
||||
def apply_definition(state: State, params: dict[str, Any], definition: dict[str, Any]) -> State:
|
||||
service_name: str = params["name"]
|
||||
def get_default_definition(state: State, service_name: str) -> dict[str, Any]:
|
||||
settings: dict[str, Any] = state.module.params.get("settings") or {}
|
||||
default_definition: dict[str, Any] = settings.get("default_definition") or {}
|
||||
service_default_definitions: dict[str, Any] = settings.get("service_default_definitions") or {}
|
||||
service_default_definition: dict[str, Any] = service_default_definitions.get(service_name) or {}
|
||||
|
||||
return default_definition | service_default_definition
|
||||
|
||||
|
||||
def get_default_args(state: State, helper_name: str) -> dict[str, Any]:
|
||||
settings: dict[str, Any] = state.module.params.get("settings") or {}
|
||||
service_default_args: dict[str, Any] = settings.get("service_default_args") or {}
|
||||
default_args: dict[str, Any] = service_default_args.get(helper_name) or {}
|
||||
return clean_none(default_args)
|
||||
|
||||
|
||||
def apply_update(state: State, service_name: str, update: dict[str, Any]) -> State:
|
||||
project = copy.deepcopy(state.after)
|
||||
services: dict[str, Any] = project["services"]
|
||||
service: dict[str, Any] = services[service_name]
|
||||
service = project["services"].get(service_name, {})
|
||||
service = recursive_update(service, update)
|
||||
|
||||
_ = recursive_update(service, definition)
|
||||
volumes: list[dict[str, Any]] = service.get("volumes") or []
|
||||
unique_volumes = list({vol["source"]: vol for vol in volumes if "target" in vol}.values())
|
||||
service["volumes"] = unique_volumes
|
||||
|
||||
services.update({service_name: service})
|
||||
project["services"][service_name] = service
|
||||
|
||||
return replace(state, after=project)
|
||||
|
||||
|
||||
def apply_settings(state: State, params: dict[str, Any]) -> State:
|
||||
settings = state.module.params.get("settings", {})
|
||||
params = settings.get("service_default_args", {}).get(params["name"], {}) | params
|
||||
|
||||
return update(
|
||||
state,
|
||||
params,
|
||||
settings.get("service_default_definitions", {}).get(params["name"], {}),
|
||||
)
|
||||
|
||||
|
||||
def update(state: State, params: dict[str, Any], update: dict[str, Any]) -> State:
|
||||
service_name: str = params["name"]
|
||||
project = copy.deepcopy(state.after)
|
||||
|
||||
project["services"][service_name] = project["services"].get(service_name, {})
|
||||
_ = recursive_update(project["services"][service_name], update)
|
||||
|
||||
# FIX: this silently throws out misconfigured volumes
|
||||
unique_volumes = dict(
|
||||
{
|
||||
vol["target"]: vol
|
||||
for vol in project["services"][service_name].get("volumes", [])
|
||||
if "target" in vol
|
||||
}.values(),
|
||||
)
|
||||
|
||||
project["services"][service_name]["volumes"] = unique_volumes
|
||||
return replace(state, after=project)
|
||||
|
||||
|
||||
def run_helper(
|
||||
state: State,
|
||||
params: dict[str, Any],
|
||||
helper: Callable[[State, dict[str, Any]], State] = lambda x, _: x,
|
||||
helper: Callable[[State, dict[str, Any]], dict[str, Any]] = lambda _a, _b: {},
|
||||
) -> State:
|
||||
if not params.get("name"):
|
||||
params["name"] = str.split(helper.__module__, ".")[-1]
|
||||
|
||||
if not params.get("overwrite"):
|
||||
params["overwrite"] = params.get("definition", {})
|
||||
base_definition = get_base_definition(state, params["name"])
|
||||
state = apply_update(state, params["name"], base_definition)
|
||||
|
||||
state = apply_base(state, params)
|
||||
state = apply_settings(state, params)
|
||||
state = helper(state, params)
|
||||
state = apply_definition(state, params, params["overwrite"])
|
||||
return update_project(state)
|
||||
default_definition = get_default_definition(state, params["name"])
|
||||
state = apply_update(state, params["name"], default_definition)
|
||||
|
||||
helper_update = helper(state, params)
|
||||
state = apply_update(state, params["name"], helper_update)
|
||||
|
||||
if not (overwrite := params.get("overwrite")):
|
||||
overwrite = params.get("definition", {})
|
||||
|
||||
return apply_update(state, params["name"], overwrite)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import label, service, spec
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import label, spec
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import clean_none
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
|
@ -20,20 +21,19 @@ FORCE_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, params: dict[str, Any]) -> dict[str, Any]:
|
||||
internal_network: bool = params["internal_network"]
|
||||
|
||||
update: dict[str, Any] = {}
|
||||
|
||||
networks = update.get("networks", {})
|
||||
|
||||
if internal_network:
|
||||
networks = update.get("networks", {})
|
||||
networks["internal"] = None
|
||||
|
||||
update["networks"] = networks
|
||||
update["networks"] = networks
|
||||
|
||||
for name, args in [(x, y) for x, y in params.get("label_helpers", {}).items() if y]:
|
||||
label_params = label.common.get_default_args(state, name) | clean_none(args)
|
||||
helper = getattr(label, name).helper
|
||||
state = label.common.run_helper(state, params["name"], args, helper)
|
||||
update = label.common.run_helper(state, params["name"], update, label_params, helper)
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
return update
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
update = {
|
||||
def helper(_state: State, _params: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"privileged": True,
|
||||
}
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"read_only": {"type": "bool", "default": True},
|
||||
}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
def helper(_state: State, params: dict[str, Any]) -> dict[str, Any]:
|
||||
read_only = params["read_only"]
|
||||
|
||||
volumes = [
|
||||
|
@ -29,8 +25,6 @@ def helper(state: State, params: dict[str, Any]) -> State:
|
|||
},
|
||||
]
|
||||
|
||||
update = {
|
||||
return {
|
||||
"volumes": volumes,
|
||||
}
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"archive": {"type": "path"},
|
||||
|
@ -18,7 +14,7 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
archive: str | None = params.get("archive")
|
||||
backup_volumes: list[str] | None = params["backup_volumes"]
|
||||
|
@ -53,9 +49,7 @@ def helper(state: State, params: dict[str, Any]) -> State:
|
|||
},
|
||||
)
|
||||
|
||||
update = {
|
||||
return {
|
||||
"environment": environment,
|
||||
"volumes": volumes,
|
||||
}
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
@ -6,12 +6,8 @@ from __future__ import annotations
|
|||
import shlex
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"backup": {"type": "bool", "default": True},
|
||||
|
@ -22,7 +18,7 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
backup: bool = params["backup"]
|
||||
database: str = params["database"]
|
||||
|
@ -76,10 +72,8 @@ def helper(state: State, params: dict[str, Any]) -> State:
|
|||
},
|
||||
)
|
||||
|
||||
update = {
|
||||
return {
|
||||
"environment": environment,
|
||||
"volumes": volumes,
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
@ -6,12 +6,8 @@ from __future__ import annotations
|
|||
import shlex
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils import service
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {
|
||||
"backup": {"type": "bool", "default": True},
|
||||
|
@ -21,7 +17,7 @@ EXTRA_ARGS = {
|
|||
}
|
||||
|
||||
|
||||
def helper(state: State, params: dict[str, Any]) -> State:
|
||||
def helper(state: State, params: dict[str, Any]) -> dict[str, Any]:
|
||||
project_name: str = state.module.params["name"]
|
||||
backup: bool = params["backup"]
|
||||
database: str = params["database"]
|
||||
|
@ -67,10 +63,8 @@ def helper(state: State, params: dict[str, Any]) -> State:
|
|||
},
|
||||
)
|
||||
|
||||
update = {
|
||||
return {
|
||||
"environment": environment,
|
||||
"volumes": volumes,
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
return service.common.update(state, params, update)
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
|
||||
State,
|
||||
)
|
||||
from ansible_collections.snailed.ez_compose.plugins.module_utils.models import State
|
||||
|
||||
EXTRA_ARGS = {}
|
||||
|
||||
|
||||
def helper(state: State) -> State:
|
||||
return state
|
||||
def helper(_state: State, _params: dict[str, Any]) -> dict[str, Any]:
|
||||
return {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
|
||||
from __future__ import annotations
|
||||
|
@ -92,6 +92,7 @@ def settings_spec() -> dict[str, Any]:
|
|||
|
||||
for arg in service_args.values():
|
||||
arg.pop("required", None)
|
||||
arg.pop("default", None)
|
||||
|
||||
settings["options"]["service_default_args"]["options"][module_name] = {
|
||||
"type": "dict",
|
||||
|
@ -103,6 +104,7 @@ def settings_spec() -> dict[str, Any]:
|
|||
|
||||
for arg in label_args.values():
|
||||
arg.pop("required", None)
|
||||
arg.pop("default", None)
|
||||
|
||||
settings["options"]["label_default_args"]["options"][module_name] = {
|
||||
"type": "dict",
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
|
||||
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
|
||||
# MIT License (see LICENSE)
|
||||
# ruff: noqa: E402
|
||||
|
||||
from __future__ import annotations
|
||||
from pprint import pp
|
||||
|
||||
from dataclasses import asdict
|
||||
|
||||
# TODO: break this down per module
|
||||
# TODO: generate this by reassembling
|
||||
|
@ -477,18 +478,40 @@ def main() -> None:
|
|||
"settings": spec.settings_spec(),
|
||||
"services": spec.service_argument_spec(),
|
||||
},
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
if not find_spec("yaml"):
|
||||
module.fail_json("PyYAML seems to be missing on host") # pyright: ignore[reportUnknownMemberType]
|
||||
module.fail_json("PyYAML needs to be installed on the host to use this plugin") # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
state = common.get_state(module)
|
||||
try:
|
||||
state = common.get_state(module)
|
||||
except Exception as e: # noqa: BLE001
|
||||
module.fail_json(f"Error while reading existing compose file: {e}") # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
for name, services_params in [(x, y) for x, y in module.params["services"].items() if y]:
|
||||
for service_params in services_params:
|
||||
for index, service_params in enumerate(services_params):
|
||||
params = service.common.get_default_args(state, name) | common.clean_none(
|
||||
service_params
|
||||
)
|
||||
params["_index"] = index
|
||||
helper = getattr(service, name).helper
|
||||
state = service.common.run_helper(state, service_params, helper)
|
||||
pp(state.after)
|
||||
state = service.common.run_helper(state, params, helper)
|
||||
|
||||
state = common.update_project(state)
|
||||
state = common.set_result(state)
|
||||
|
||||
if state.result.changed and not module.check_mode:
|
||||
try:
|
||||
state = common.write_compose(state)
|
||||
except Exception as e: # noqa: BLE001
|
||||
module.fail_json(f"Error while writing new compose file: {e}") # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
ret = asdict(state.result)
|
||||
if not module._diff: # noqa: SLF001
|
||||
del ret["diff"]
|
||||
|
||||
module.exit_json(**ret) # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -11,25 +11,29 @@ ignore = [
|
|||
"TD002",
|
||||
"TD003",
|
||||
"INP001",
|
||||
"COM812",
|
||||
"D100",
|
||||
"D101",
|
||||
"D103",
|
||||
"D104",
|
||||
"D203",
|
||||
"D213",
|
||||
]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/units/**" = [
|
||||
"S101",
|
||||
"PT009",
|
||||
]
|
||||
|
||||
[tool.ruff.format]
|
||||
line-ending = "lf"
|
||||
|
||||
[tool.ruff.lint.mccabe]
|
||||
max-complexity = 10
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "numpy"
|
||||
|
||||
[tool.basedpyright]
|
||||
typeCheckingMode = "strict"
|
||||
|
||||
# Handled by ruff
|
||||
reportPrivateUsage = false
|
||||
reportIgnoreCommentWithoutRule = false
|
||||
reportUnusedImport = false
|
||||
reportUnusedClass = false
|
Loading…
Add table
Reference in a new issue