#!/usr/bin/env python # Copyright: (c) 2024, Luca Bilke <luca@bil.ke> # MIT License (see LICENSE) # ruff: noqa: E402 from __future__ import annotations SERVICE_BASE_DOCS = """ type: dict suboptions: name: description: - Name of the service. type: str image: description: - Image to use for service. type: str defaults: description: - Service definition to be overwritten. type: dict overwrite: description: - Service definition to overwrite with. type: dict """ LABEL_BASE_DOCS = """ type: dict suboptions: """ DOCUMENTATION = f""" --- module: compose short_description: Simplify docker-compose deployments description: - Easily create docker-compose files using a single module author: - "Luca Bilke (@ssnailed)" 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 services: description: - Services to create in the project. type: list elements: dict suboptions: custom: description: - Custom service definition. {SERVICE_BASE_DOCS} internal_network: description: - If true, add internal network to service. type: bool default: false label_helpers: description: - Label helper configurations. type: dict suboptions: docker_volume_backupper: description: - Docker Volume Backupper label helper configuration. {LABEL_BASE_DOCS} stop: description: - If true, stop the container when backing up. type: bool default: true traefik_middleware: description: - Traefik Middleware label helper configuration. {LABEL_BASE_DOCS} proxy_type: description: - Traefik proxy type. type: str choices: [http, tcp, udp] default: http name: description: - Name of the middleware. - Default is generated dynamically like so: - [project_name]_[service_name]_[proxy_type]_[middleware] type: string middleware: description: - The traefik middleware to use. type: str required: true settings: description: - Middleware options. type: dict required: true traefik_router: description: - Traefik Router label helper configuration. {LABEL_BASE_DOCS} proxy_type: description: - Traefik proxy type. type: str choices: [http, tcp, udp] default: http name: description: - Name of the middleware. - Default is generated dynamically like so: - [project_name]_[service_name]_[proxy_type] type: string rule: description: - Routing rule to match. type: str required: true 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: - Traefik Service label helper configuration. {LABEL_BASE_DOCS} proxy_type: description: - Traefik proxy type. type: str choices: [http, tcp, udp] default: http name: description: - Name of the middleware. - Default is generated dynamically like so: - [project_name]_[service_name]_[proxy_type] type: string port: description: - Port to forward to. type: int docker_in_docker: description: - Docker-in-Docker service definition. {SERVICE_BASE_DOCS} docker_socket_proxy: description: - Docker Socket Proxy service definition. {SERVICE_BASE_DOCS} read_only: description: - If true, only allow read access to the docker socket. type: bool default: true docker_volume_backupper: description: - Docker Socket Proxy service definition. {SERVICE_BASE_DOCS} archive: description: - Directory to store backups in. type: path backup_volumes: description: - List of volume names of volumes to backup. type: list elements: str mariadb: description: - MariaDB service definition. {SERVICE_BASE_DOCS} backup: description: - If true, add labels for the docker volume backupper. type: bool 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 postgres: description: - PostgreSQL service definition. {SERVICE_BASE_DOCS} backup: description: - If true, add labels for the docker volume backupper. type: bool 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 redis: description: - Redis service definition. {SERVICE_BASE_DOCS} """ # noqa: E501 from typing import Any from ansible.module_utils.basic import AnsibleModule # type: ignore[reportMissingStubFile] from ansible_collections.ssnailed.ez_compose.plugins.module_utils import ( common, label, service, ) def label_argument_spec() -> dict[str, Any]: label_args: dict[str, Any] = { "type": "dict", "options": {}, } for module in label.__all__: if module == "common": continue options = { **label.common.BASE_ARGS, **getattr(label, module).EXTRA_ARGS, } label_args["options"][module] = { "type": "dict", "options": options, } return label_args def service_argument_spec() -> dict[str, Any]: service_args: dict[str, Any] = { "type": "dict", "options": {}, "required": True, } for module in service.__all__: if module == "common": continue options = { **service.common.BASE_ARGS, **getattr(service, module).EXTRA_ARGS, } if module == "custom": options["label_helpers"] = label_argument_spec() service_args["options"][module] = { "type": "list", "elements": "dict", "options": options, } return service_args def main() -> None: module = AnsibleModule( argument_spec={ "name": { "aliases": ["project"], "type": "str", "required": True, }, "project_dir": { "type": "path", "default": "/var/lib/ez_compose", }, "services": service_argument_spec(), }, ) state = common.get_state(module) for name, args in module.params["services"].items(): state = getattr(service, name).helper(state, args) if __name__ == "__main__": main()