338 lines
12 KiB
Python
Executable file
338 lines
12 KiB
Python
Executable file
#!/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()
|