From 28c28c64939aae698c4dc32dceb474c65b623cb9 Mon Sep 17 00:00:00 2001 From: Menno van Leeuwen Date: Tue, 11 Mar 2025 18:44:06 +0100 Subject: [PATCH] feat: add Docker service management script and Golink service deployment configuration --- bin/actions/docker.py | 144 ++++++++++++++++++ bin/dotf | 7 +- .../services/golink/docker-compose.yml.j2 | 11 ++ .../tasks/servers/services/golink/golink.yml | 38 ++--- 4 files changed, 180 insertions(+), 20 deletions(-) create mode 100755 bin/actions/docker.py create mode 100644 config/ansible/tasks/servers/services/golink/docker-compose.yml.j2 diff --git a/bin/actions/docker.py b/bin/actions/docker.py new file mode 100755 index 0000000..5c335fb --- /dev/null +++ b/bin/actions/docker.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 + +import os +import sys +import subprocess +import argparse + +# Import helper functions +sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) +from helpers.functions import printfe, println, logo + +# Base directory for Docker services +SERVICES_DIR = "/mnt/storage-box/services" + +def get_service_path(service_name): + """Return the path to a service's docker-compose file""" + service_dir = os.path.join(SERVICES_DIR, service_name) + compose_file = os.path.join(service_dir, "docker-compose.yml") + + if not os.path.exists(compose_file): + printfe("red", f"Error: Service '{service_name}' not found at {compose_file}") + return None + + return compose_file + +def run_docker_compose(args, service_name=None, compose_file=None): + """Run docker compose command with provided args""" + if service_name and not compose_file: + compose_file = get_service_path(service_name) + if not compose_file: + return 1 + + cmd = ["docker", "compose"] + + if compose_file: + cmd.extend(["-f", compose_file]) + + cmd.extend(args) + + printfe("blue", f"Running: {' '.join(cmd)}") + result = subprocess.run(cmd) + return result.returncode + +def cmd_start(args): + """Start a Docker service""" + return run_docker_compose(["up", "-d"], service_name=args.service) + +def cmd_stop(args): + """Stop a Docker service""" + return run_docker_compose(["down"], service_name=args.service) + +def cmd_restart(args): + """Restart a Docker service""" + return run_docker_compose(["restart"], service_name=args.service) + +def cmd_ps(args): + """Show Docker service status""" + if args.service: + return run_docker_compose(["ps"], service_name=args.service) + else: + return run_docker_compose(["ps"]) + +def cmd_logs(args): + """Show Docker service logs""" + cmd = ["logs"] + + if args.follow: + cmd.append("-f") + + if args.tail: + cmd.extend(["--tail", args.tail]) + + return run_docker_compose(cmd, service_name=args.service) + +def cmd_list(args): + """List available Docker services""" + if not os.path.exists(SERVICES_DIR): + printfe("red", f"Error: Services directory not found at {SERVICES_DIR}") + return 1 + + services = [d for d in os.listdir(SERVICES_DIR) + if os.path.isdir(os.path.join(SERVICES_DIR, d)) and + os.path.exists(os.path.join(SERVICES_DIR, d, "docker-compose.yml"))] + + if not services: + printfe("yellow", "No Docker services found") + return 0 + + println("Available Docker services:") + for service in sorted(services): + println(f" - {service}") + + return 0 + +def main(): + parser = argparse.ArgumentParser(description="Manage Docker services") + subparsers = parser.add_subparsers(dest="command", help="Command to run") + + # Start command + start_parser = subparsers.add_parser("start", help="Start a Docker service") + start_parser.add_argument("service", help="Service to start") + + # Stop command + stop_parser = subparsers.add_parser("stop", help="Stop a Docker service") + stop_parser.add_argument("service", help="Service to stop") + + # Restart command + restart_parser = subparsers.add_parser("restart", help="Restart a Docker service") + restart_parser.add_argument("service", help="Service to restart") + + # PS command + ps_parser = subparsers.add_parser("ps", help="Show Docker service status") + ps_parser.add_argument("service", nargs="?", help="Service to check") + + # Logs command + logs_parser = subparsers.add_parser("logs", help="Show Docker service logs") + logs_parser.add_argument("service", help="Service to show logs for") + logs_parser.add_argument("-f", "--follow", action="store_true", help="Follow log output") + logs_parser.add_argument("--tail", help="Number of lines to show from the end of logs") + + # List command + subparsers.add_parser("list", help="List available Docker services") + + # Parse arguments + args = parser.parse_args() + + if not args.command: + parser.print_help() + return 1 + + # Execute the appropriate command + commands = { + "start": cmd_start, + "stop": cmd_stop, + "restart": cmd_restart, + "ps": cmd_ps, + "logs": cmd_logs, + "list": cmd_list + } + + return commands[args.command](args) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/bin/dotf b/bin/dotf index c4f6d9a..8962e3d 100755 --- a/bin/dotf +++ b/bin/dotf @@ -45,6 +45,10 @@ def auto_start(args): """Run the auto-start action""" return run_script(f"{DOTFILES_BIN}/actions/auto-start.py", args) +def docker(args): + """Run the docker action""" + return run_script(f"{DOTFILES_BIN}/actions/docker.py", args) + def ensure_git_hooks(): """Ensure git hooks are correctly set up""" hooks_dir = os.path.join(DOTFILES_ROOT, ".git/hooks") @@ -98,7 +102,8 @@ def main(): "help": help, "hello": hello, "secrets": secrets, - "auto-start": auto_start + "auto-start": auto_start, + "docker": docker } if command in commands: diff --git a/config/ansible/tasks/servers/services/golink/docker-compose.yml.j2 b/config/ansible/tasks/servers/services/golink/docker-compose.yml.j2 new file mode 100644 index 0000000..ab3e09e --- /dev/null +++ b/config/ansible/tasks/servers/services/golink/docker-compose.yml.j2 @@ -0,0 +1,11 @@ +name: golink +services: + server: + image: ghcr.io/tailscale/golink:main + environment: + - PUID=1000 + - PGID=1000 + - TS_AUTHKEY={{ lookup('onepassword', '4gsgavajnxfpcrjvbkqhoc4drm', vault='j7nmhqlsjmp2r6umly5t75hzb4') }} + volumes: + - /mnt/services/golink:/home/nonroot + restart: "unless-stopped" diff --git a/config/ansible/tasks/servers/services/golink/golink.yml b/config/ansible/tasks/servers/services/golink/golink.yml index e6c5bcf..94ff1f4 100644 --- a/config/ansible/tasks/servers/services/golink/golink.yml +++ b/config/ansible/tasks/servers/services/golink/golink.yml @@ -1,20 +1,20 @@ ---- -- name: Ensure golink data directory exists - ansible.builtin.file: - path: /mnt/storage-box/golink/data - state: directory - mode: '0755' - owner: '1000' - group: '100' +- name: Deploy GoLink service + block: + - name: Create GoLink directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: "0755" + loop: + - /mnt/storage-box/services/golink -- name: Deploy golink docker container - community.docker.docker_container: - name: golink - image: ghcr.io/tailscale/golink:main - restart_policy: unless-stopped - env: - PUID: '1000' - PGID: '100' - TS_AUTHKEY: "{{ lookup('onepassword', '4gsgavajnxfpcrjvbkqhoc4drm', vault='j7nmhqlsjmp2r6umly5t75hzb4') }}" - volumes: - - /mnt/storage-box/golink/data:/home/nonroot + - name: Deploy GoLink docker-compose.yml + ansible.builtin.template: + src: docker-compose.yml.j2 + dest: /mnt/storage-box/services/golink/docker-compose.yml + mode: "0644" + register: golink_compose + + - name: Start GoLink service + ansible.builtin.command: docker-compose -f /mnt/storage-box/services/golink/docker-compose.yml up -d + when: golink_compose.changed