ez_docker/plugins/modules/compose.py

862 lines
39 KiB
Python
Executable file

#!/usr/bin/python
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# ruff: noqa: E402
from __future__ import annotations
DOCUMENTATION = """
---
module: compose
version_added: 1.0.0
short_description: Simplify docker-compose deployments.
description: Easily create docker-compose files using a single module
seealso:
- name: Compose file reference
description: Complete reference of the compose file spec.
link: https://docs.docker.com/reference/compose-file/
attributes:
check_mode:
support: full
diff_mode:
support: full
options:
name:
description:
- Name of the compose project to create or modify.
aliases: [project]
type: str
project_dir:
description:
- Path to store project directory under.
type: path
settings:
description:
- Settings/Defaults for the module.
type: dict
suboptions:
external_networks:
description:
- Networks to mark as external.
type: list
elements: str
external_volumes:
description:
- Volumes to mark as external.
type: list
elements: str
default_definition:
description:
- Default definition for all containers.
- Overwritten by per-service defaults.
type: dict
service_default_definitions:
description:
- Default definitions for each service
type: dict
suboptions:
custom:
description:
- Default definitions for custom services.
type: dict
docker_in_docker:
description:
- Default definitions for docker_in_docker services.
type: dict
docker_socket_proxy:
description:
- Default definitions for docker_socket_proxy services.
type: dict
docker_volume_backupper:
description:
- Default definitions for docker_volume_backupper services.
type: dict
mariadb:
description:
- Default definitions for mariadb services.
type: dict
postgres:
description:
- Default definitions for postgres services.
type: dict
redis:
description:
- Default definitions for redis services.
type: dict
service_default_args:
description:
- Default arguments for each service helper.
type: dict
suboptions:
custom:
description:
- Configuration for custom service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service
type: str
definition:
description:
- Service definition
type: dict
label_helpers:
description:
- Label helper configurations
type: dict
suboptions:
docker_volume_backupper:
description:
- Configuration for docker_volume_backupper labels.
type: list
elements: dict
suboptions:
stop:
description:
- If true, stop the container when backing up.
type: bool
homepage:
description:
- Configuration for homepage labels.
type: list
elements: dict
suboptions:
name:
description:
- Name to set on dashboard.
- Defaults to name of service.
type: str
href:
description:
- HREF to set on dashboard.
type: str
icon:
description:
- URL to an image to use as icon.
type: str
description:
description:
- Description text to set on dashboard.
type: str
group:
description:
- Group to place service under on dashboard.
type: str
widget:
description:
- Widget configuration.
- See U(https://gethomepage.dev/configs/services/) for more info.
type: dict
traefik_middleware:
description:
- Configuration for traefik_middleware labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
middleware:
description:
- The name of the traefik middleware to use.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
settings:
description:
- Middleware options.
type: dict
traefik_router:
description:
- Configuration for traefik_router labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
rule:
description:
- Routing rule to match.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
service:
description:
- Traefik service to point at.
type: str
certresolver:
description:
- Certresolver to use.
type: str
entrypoints:
description:
- Entrypoints to listen on.
type: list
elements: str
middlewares:
description:
- Middlewares to use.
type: list
elements: str
traefik_service:
description:
- Configuration for traefik_service labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
port:
description:
- Port to forward to.
type: int
protocol_version:
description:
- Proxy protocol version to use (TCP only).
type: int
docker_in_docker:
description:
- Configuration for docker_in_docker service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
docker_socket_proxy:
description:
- Configuration for docker_socket_proxy service.
type: list
elements: dict
suboptions:
read_only:
description:
- If true, only allow read access to the docker socket.
type: bool
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
docker_volume_backupper:
description:
- Configuration for docker_volume_backupper service.
type: list
elements: dict
suboptions:
archive:
description:
- Directory to store backups in.
type: path
backup_volumes:
description:
- List of volume names of volumes to backup.
type: list
elements: str
docker_socket_proxy:
description:
- Hostname of a docker socket proxy to use.
type: str
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
mariadb:
description:
- Configuration for mariadb service.
type: list
elements: dict
suboptions:
backup:
description:
- If true, add labels for the docker volume backupper.
type: bool
database:
description:
- Name of database.
type: str
username:
description:
- Username for database.
type: str
password:
description:
- Password for database.
type: str
root_password:
description:
- Root password for database.
type: str
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
postgres:
description:
- Configuration for postgres service.
type: list
elements: dict
suboptions:
backup:
description:
- If true, add labels for the docker volume backupper.
type: bool
database:
description:
- Name of database.
type: str
username:
description:
- Username for database.
type: str
password:
description:
- Password for database.
type: str
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
redis:
description:
- Configuration for redis service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
label_default_args:
description:
- Default arguments for each label helper.
type: dict
suboptions:
docker_volume_backupper:
description:
- Configuration for docker_volume_backupper labels.
type: list
elements: dict
suboptions:
stop:
description:
- If true, stop the container when backing up.
type: bool
homepage:
description:
- Configuration for homepage labels.
type: list
elements: dict
suboptions:
name:
description:
- Name to set on dashboard.
- Defaults to name of service.
type: str
href:
description:
- HREF to set on dashboard.
type: str
icon:
description:
- URL to an image to use as icon.
type: str
description:
description:
- Description text to set on dashboard.
type: str
group:
description:
- Group to place service under on dashboard.
type: str
widget:
description:
- Widget configuration.
- See U(https://gethomepage.dev/configs/services/) for more info.
type: dict
traefik_middleware:
description:
- Configuration for traefik_middleware labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
middleware:
description:
- The name of the traefik middleware to use.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
settings:
description:
- Middleware options.
type: dict
traefik_router:
description:
- Configuration for traefik_router labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
rule:
description:
- Routing rule to match.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
service:
description:
- Traefik service to point at.
type: str
certresolver:
description:
- Certresolver to use.
type: str
entrypoints:
description:
- Entrypoints to listen on.
type: list
elements: str
middlewares:
description:
- Middlewares to use.
type: list
elements: str
traefik_service:
description:
- Configuration for traefik_service labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
port:
description:
- Port to forward to.
type: int
protocol_version:
description:
- Proxy protocol version to use (TCP only).
type: int
services:
description:
- Services to create in the project.
type: dict
suboptions:
custom:
description:
- Configuration for custom service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service
type: str
required: true
definition:
description:
- Service definition
type: dict
required: true
label_helpers:
description:
- Label helper configurations
type: dict
suboptions:
docker_volume_backupper:
description:
- Configuration for docker_volume_backupper labels.
type: list
elements: dict
suboptions:
stop:
description:
- If true, stop the container when backing up.
type: bool
homepage:
description:
- Configuration for homepage labels.
type: list
elements: dict
suboptions:
name:
description:
- Name to set on dashboard.
- Defaults to name of service.
type: str
href:
description:
- HREF to set on dashboard.
type: str
icon:
description:
- URL to an image to use as icon.
type: str
description:
description:
- Description text to set on dashboard.
type: str
group:
description:
- Group to place service under on dashboard.
type: str
widget:
description:
- Widget configuration.
- See U(https://gethomepage.dev/configs/services/) for more info.
type: dict
traefik_middleware:
description:
- Configuration for traefik_middleware labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
middleware:
description:
- The name of the traefik middleware to use.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
settings:
description:
- Middleware options.
type: dict
traefik_router:
description:
- Configuration for traefik_router labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
rule:
description:
- Routing rule to match.
type: str
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
service:
description:
- Traefik service to point at.
type: str
certresolver:
description:
- Certresolver to use.
type: str
entrypoints:
description:
- Entrypoints to listen on.
type: list
elements: str
middlewares:
description:
- Middlewares to use.
type: list
elements: str
traefik_service:
description:
- Configuration for traefik_service labels.
type: list
elements: dict
suboptions:
name:
description:
- Name of the middleware.
type: string
proxy_type:
description:
- Traefik proxy type.
type: str
choices: [http, tcp, udp]
port:
description:
- Port to forward to.
type: int
protocol_version:
description:
- Proxy protocol version to use (TCP only).
type: int
docker_in_docker:
description:
- Configuration for docker_in_docker service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
docker_socket_proxy:
description:
- Configuration for docker_socket_proxy service.
type: list
elements: dict
suboptions:
read_only:
description:
- If true, only allow read access to the docker socket.
type: bool
required: true
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
docker_volume_backupper:
description:
- Configuration for docker_volume_backupper service.
type: list
elements: dict
suboptions:
archive:
description:
- Directory to store backups in.
type: path
backup_volumes:
description:
- List of volume names of volumes to backup.
type: list
elements: str
required: true
docker_socket_proxy:
description:
- Hostname of a docker socket proxy to use.
type: str
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
mariadb:
description:
- Configuration for mariadb service.
type: list
elements: dict
suboptions:
backup:
description:
- If true, add labels for the docker volume backupper.
type: bool
default: true
database:
description:
- Name of database.
type: str
required: true
username:
description:
- Username for database.
type: str
required: true
password:
description:
- Password for database.
type: str
required: true
root_password:
description:
- Root password for database.
type: str
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
postgres:
description:
- Configuration for postgres service.
type: list
elements: dict
suboptions:
backup:
description:
- If true, add labels for the docker volume backupper.
type: bool
default: true
database:
description:
- Name of database.
type: str
required: true
username:
description:
- Username for database.
type: str
required: true
password:
description:
- Password for database.
type: str
required: true
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
redis:
description:
- Configuration for redis service.
type: list
elements: dict
suboptions:
name:
description:
- Name of the service.
type: str
overwrite:
description:
- Definition to force.
type: dict
""" # noqa: E501
from dataclasses import asdict
from importlib.util import find_spec
from ansible.module_utils.basic import AnsibleModule # pyright: ignore[reportMissingTypeStubs]
from ansible_collections.snailed.ez_docker.plugins.module_utils import (
common,
service,
spec,
)
def main() -> None:
module = AnsibleModule(
argument_spec={
"name": {
"aliases": ["project"],
"type": "str",
"required": True,
},
"project_dir": {
"type": "path",
"default": "/var/lib/ez_docker",
},
"settings": spec.settings_spec(),
"services": spec.service_argument_spec(),
},
supports_check_mode=True,
)
if not find_spec("yaml"):
module.fail_json("PyYAML needs to be installed on the host to use this plugin") # pyright: ignore[reportUnknownMemberType]
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 state.params.get("services", {}).items():
for index, service_params in enumerate(services_params):
default_params = service.common.get_default_args(state, name)
params = common.recursive_update(default_params, service_params)
params["_index"] = index
helper = getattr(service, name).helper
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)
module.exit_json(**ret) # pyright: ignore[reportUnknownMemberType]
if __name__ == "__main__":
main()