518 lines
20 KiB
Python
Executable file
518 lines
20 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
|
|
|
|
from dataclasses import asdict
|
|
|
|
# TODO: break this down per module
|
|
# TODO: generate this by reassembling
|
|
DOCUMENTATION = """
|
|
---
|
|
module: compose
|
|
version_added: 1.0.0
|
|
short_description: Simplify docker-compose deployments
|
|
seealso:
|
|
- name: Compose file reference
|
|
description: Complete reference of the compose file spec.
|
|
link: https://docs.docker.com/reference/compose-file/
|
|
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
|
|
settings:
|
|
description:
|
|
- Settings/Defaults for the module.
|
|
type: dict
|
|
suboptions:
|
|
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 PostgreSQL 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:
|
|
- Default args for custom services.
|
|
type: dict
|
|
docker_in_docker:
|
|
description:
|
|
- Default args for docker in docker services.
|
|
type: dict
|
|
docker_socket_proxy:
|
|
description:
|
|
- Default args for docker socket proxy services.
|
|
type: dict
|
|
docker_volume_backupper:
|
|
description:
|
|
- Default args for docker volume backupper services.
|
|
type: dict
|
|
mariadb:
|
|
description:
|
|
- Default args for MariaDB services.
|
|
type: dict
|
|
postgres:
|
|
description:
|
|
- Default args for PostgreSQL services.
|
|
type: dict
|
|
redis:
|
|
description:
|
|
- Default args for Redis services.
|
|
type: dict
|
|
label_default_args:
|
|
description:
|
|
- Default arguments for each label helper.
|
|
type: dict
|
|
suboptions:
|
|
docker_volume_backupper:
|
|
description:
|
|
- Docker Volume Backupper label helper configuration.
|
|
type: dict
|
|
traefik_middleware:
|
|
description:
|
|
- Traefik Middleware label helper configuration.
|
|
type: dict
|
|
traefik_router:
|
|
description:
|
|
- Traefik Router label helper configuration.
|
|
type: dict
|
|
traefik_service:
|
|
description:
|
|
- Traefik Service label helper configuration.
|
|
type: dict
|
|
services:
|
|
description:
|
|
- Services to create in the project.
|
|
type: dict
|
|
suboptions:
|
|
custom:
|
|
description:
|
|
- Custom service definition.
|
|
type: list
|
|
elements: 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
|
|
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.
|
|
type: dict
|
|
suboptions:
|
|
stop:
|
|
description:
|
|
- If true, stop the container when backing up.
|
|
type: bool
|
|
default: true
|
|
traefik_middleware:
|
|
description:
|
|
- Traefik Middleware label helper configuration.
|
|
type: dict
|
|
suboptions:
|
|
proxy_type:
|
|
description:
|
|
- Traefik proxy type.
|
|
type: str
|
|
choices: [http, tcp, udp]
|
|
default: http
|
|
name:
|
|
description:
|
|
- Name of the 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.
|
|
type: dict
|
|
suboptions:
|
|
proxy_type:
|
|
description:
|
|
- Traefik proxy type.
|
|
type: str
|
|
choices: [http, tcp, udp]
|
|
default: http
|
|
name:
|
|
description:
|
|
- Name of the middleware.
|
|
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.
|
|
type: dict
|
|
suboptions:
|
|
proxy_type:
|
|
description:
|
|
- Traefik proxy type.
|
|
type: str
|
|
choices: [http, tcp, udp]
|
|
default: http
|
|
name:
|
|
description:
|
|
- Name of the middleware.
|
|
type: string
|
|
port:
|
|
description:
|
|
- Port to forward to.
|
|
type: int
|
|
docker_in_docker:
|
|
description:
|
|
- Docker-in-Docker service definition.
|
|
type: list
|
|
elements: 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
|
|
docker_socket_proxy:
|
|
description:
|
|
- Docker Socket Proxy service definition.
|
|
type: list
|
|
elements: 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
|
|
read_only:
|
|
description:
|
|
- If true, only allow read access to the docker socket.
|
|
type: bool
|
|
default: true
|
|
docker_volume_backupper:
|
|
description:
|
|
- Docker Volume Backupper service definition.
|
|
type: list
|
|
elements: 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
|
|
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.
|
|
type: list
|
|
elements: 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
|
|
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.
|
|
type: list
|
|
elements: 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
|
|
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.
|
|
type: list
|
|
elements: 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
|
|
"""
|
|
|
|
from importlib.util import find_spec
|
|
|
|
from ansible.module_utils.basic import AnsibleModule # pyright: ignore[reportMissingTypeStubs]
|
|
from ansible_collections.snailed.ez_compose.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_compose",
|
|
},
|
|
"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 [(x, y) for x, y in module.params["services"].items() if y]:
|
|
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, 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__":
|
|
main()
|