From b8fc8e24a00734c134faf1d70629ece1cb084cd6 Mon Sep 17 00:00:00 2001 From: "martin.fencl" Date: Mon, 29 Jun 2026 12:24:51 +0200 Subject: [PATCH] feat: update playbook for Homarr deployment --- update_bettershift.yml | 272 +++++++++++------------------------------ update_homarr.yml | 71 ++++------- 2 files changed, 92 insertions(+), 251 deletions(-) diff --git a/update_bettershift.yml b/update_bettershift.yml index e09ad08..e956961 100644 --- a/update_bettershift.yml +++ b/update_bettershift.yml @@ -1,223 +1,87 @@ # update_bettershift.yml -- name: Update BetterShift on VM via Proxmox - hosts: linux_servers +- name: Update BetterShift + hosts: pve2_vm gather_facts: false - become: true - become_user: root - become_method: sudo vars: - # VM connection (provided by Semaphore env vars) - vm_ip: "{{ lookup('env', 'VM_IP') }}" - vm_user: "{{ lookup('env', 'VM_USER') }}" - vm_pass: "{{ lookup('env', 'VM_PASS') }}" - use_sudo: false + # Compose sync (controller -> target) + compose_local_dir: "{{ playbook_dir }}/docker-compose" + compose_remote_base: "/home/{{ ansible_user }}/.ansible-compose" - # Debug mode (controlled via Semaphore variable) - DEBUG: "{{ lookup('env', 'DEBUG') | default(0) | int }}" - RETRIES: "{{ lookup('env', 'RETRIES') | default(25) | int }}" - - # BetterShift specifics - bettershift_project: "bettershift" - bettershift_compose_file: "/home/howard/.ansible-compose/docker-compose/docker-compose-bettershift.yml" - bettershift_service: "bettershift" - bettershift_image: "ghcr.io/pantelx/bettershift:v2.2.1" - bettershift_container_name: "bettershift" + # BetterShift settings + bettershift_project: bettershift + bettershift_compose_filename: "docker-compose-bettershift.yml" + bettershift_service: bettershift bettershift_port: 3067 bettershift_data_dir: "/data/compose/bettershift/data" - # Optional external URL for controller-side readiness check - # In Semaphore you can set: - # BETTERSHIFT_URL=https://bettershift.martinfencl.eu - bettershift_url: "{{ lookup('env', 'BETTERSHIFT_URL') | default('https://bettershift.martinfencl.eu', true) }}" - - # Retry policy - bettershift_retries: "{{ RETRIES }}" - bettershift_delay: 2 - - # Docker command prefix (consistent behavior) - docker_prefix: "unalias docker 2>/dev/null || true; DOCKER_CLI_HINTS=0; command docker" - - # Compose command - bettershift_compose_cmd: >- - {{ docker_prefix }} compose - -p {{ bettershift_project }} - -f {{ bettershift_compose_file }} - - # Commands to run on the target VM - bettershift_commands: - - "mkdir -p {{ bettershift_data_dir }}" - - "{{ docker_prefix }} pull -q {{ bettershift_image }} >/dev/null" - - "{{ bettershift_compose_cmd }} config >/dev/null" - - "{{ bettershift_compose_cmd }} pull {{ bettershift_service }} >/dev/null" - - "{{ bettershift_compose_cmd }} up -d --no-deps --force-recreate {{ bettershift_service }} >/dev/null" - tasks: - - name: Ensure sshpass is installed (for password-based SSH) - ansible.builtin.apt: - name: sshpass + - name: Ensure remote compose directory exists + ansible.builtin.file: + path: "{{ compose_remote_base }}" + state: directory + mode: "0755" + + - name: Ensure BetterShift data directory exists + ansible.builtin.file: + path: "{{ bettershift_data_dir }}" + state: directory + mode: "0755" + + - name: Upload BetterShift compose file to remote host + ansible.builtin.copy: + src: "{{ compose_local_dir }}/{{ bettershift_compose_filename }}" + dest: "{{ compose_remote_base }}/{{ bettershift_compose_filename }}" + mode: "0644" + + - name: Check BetterShift env file exists on remote host + ansible.builtin.stat: + path: "{{ compose_remote_base }}/.env.bettershift" + register: bettershift_env_file + + - name: Fail if BetterShift env file is missing + ansible.builtin.fail: + msg: >- + Missing {{ compose_remote_base }}/.env.bettershift on remote host. + Create it manually because it contains secrets. + when: not bettershift_env_file.stat.exists + + - name: Pull latest BetterShift image + community.docker.docker_compose_v2: + project_name: "{{ bettershift_project }}" + project_src: "{{ compose_remote_base }}" + files: + - "{{ bettershift_compose_filename }}" + pull: always + + - name: Recreate BetterShift service + community.docker.docker_compose_v2: + project_name: "{{ bettershift_project }}" + project_src: "{{ compose_remote_base }}" + files: + - "{{ bettershift_compose_filename }}" + services: + - "{{ bettershift_service }}" state: present - update_cache: yes + recreate: always - - name: Run BetterShift update commands on VM (via SSH) - ansible.builtin.command: - argv: - - sshpass - - -e - - ssh - - -o - - StrictHostKeyChecking=no - - -o - - ConnectTimeout=15 - - "{{ vm_user }}@{{ vm_ip }}" - - bash - - -lc - - "{{ ('sudo ' if use_sudo else '') + item }}" - environment: - SSHPASS: "{{ vm_pass }}" - loop: "{{ bettershift_commands }}" - loop_control: - index_var: idx - label: "cmd-{{ idx }}" - register: bettershift_cmds - changed_when: false - no_log: "{{ DEBUG == 0 }}" + - name: Wait for BetterShift port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: "{{ bettershift_port }}" + timeout: 60 - - name: Show outputs for each BetterShift command - ansible.builtin.debug: - msg: | - CMD: {{ item.item }} - RC: {{ item.rc }} - STDOUT: - {{ (item.stdout | default('')).strip() }} - STDERR: - {{ (item.stderr | default('')).strip() }} - loop: "{{ bettershift_cmds.results }}" - when: DEBUG == 1 - - - name: Fail play if any BetterShift command failed - ansible.builtin.assert: - that: "item.rc == 0" - fail_msg: "BetterShift update failed on VM: {{ item.item }} (rc={{ item.rc }})" - success_msg: "All BetterShift update commands succeeded." - loop: "{{ bettershift_cmds.results }}" - loop_control: - index_var: idx - label: "cmd-{{ idx }}" - - # ------------------------- - # Readiness checks (controller first, then VM fallback) - # ------------------------- - - - name: BetterShift | Wait for web app (controller first, with retries) + - name: Check BetterShift HTTP endpoint ansible.builtin.uri: - url: "{{ (bettershift_url | regex_replace('/$','')) + '/' }}" - method: GET - return_content: true - validate_certs: "{{ (bettershift_url | default('')) is match('^https://') }}" + url: "http://127.0.0.1:{{ bettershift_port }}/" status_code: - 200 - 307 - 308 - register: bettershift_controller - delegate_to: localhost - run_once: true - when: bettershift_url is defined and (bettershift_url | length) > 0 - retries: "{{ bettershift_retries }}" - delay: "{{ bettershift_delay }}" - until: bettershift_controller.status in [200, 307, 308] - failed_when: false + follow_redirects: none + register: bettershift_http + retries: 30 + delay: 3 + until: bettershift_http.status in [200, 307, 308] changed_when: false - - - name: BetterShift | VM-side fetch (HTML via Python, with retries) - ansible.builtin.command: - argv: - - sshpass - - -e - - ssh - - -o - - StrictHostKeyChecking=no - - -o - - ConnectTimeout=15 - - "{{ vm_user }}@{{ vm_ip }}" - - bash - - -lc - - | - python3 - <<'PY' - # Fetch BetterShift homepage from localhost and print a compact status line - import urllib.request - import urllib.error - import sys - - url = "http://127.0.0.1:{{ bettershift_port }}/" - - try: - req = urllib.request.Request(url, method="GET") - with urllib.request.urlopen(req, timeout=15) as r: - body = r.read().decode(errors="ignore") - sys.stdout.write(f"STATUS={r.status}\n") - sys.stdout.write(body[:1000]) - except urllib.error.HTTPError as e: - body = e.read().decode(errors="ignore") - sys.stdout.write(f"STATUS={e.code}\n") - sys.stdout.write(body[:1000]) - except Exception as e: - sys.stdout.write(f"ERROR={type(e).__name__}: {e}\n") - PY - environment: - SSHPASS: "{{ vm_pass }}" - register: bettershift_vm - changed_when: false - failed_when: false - when: bettershift_controller.status | default(0) not in [200, 307, 308] - retries: "{{ bettershift_retries }}" - delay: "{{ bettershift_delay }}" - until: > - ('STATUS=200' in (bettershift_vm.stdout | default(''))) - or ('STATUS=307' in (bettershift_vm.stdout | default(''))) - or ('STATUS=308' in (bettershift_vm.stdout | default(''))) - no_log: "{{ DEBUG == 0 }}" - - - name: BetterShift | Print concise summary - ansible.builtin.debug: - msg: >- - BetterShift web - {{ - 'OK' - if ( - (bettershift_controller.status | default(0)) in [200, 307, 308] - or ('STATUS=200' in (bettershift_vm.stdout | default(''))) - or ('STATUS=307' in (bettershift_vm.stdout | default(''))) - or ('STATUS=308' in (bettershift_vm.stdout | default(''))) - ) - else 'NOT OK' - }}. - Source={{ - 'controller' - if (bettershift_controller.status | default(0)) in [200, 307, 308] - else 'vm' - if (bettershift_vm.stdout | default('') | trim | length) > 0 - else 'n/a' - }}; - controller_status={{ bettershift_controller.status | default('n/a') }}; - local_port={{ bettershift_port }}. - when: DEBUG == 1 - - - name: BetterShift | Web unavailable (after retries) - ansible.builtin.debug: - msg: "BetterShift web nenĂ­ dostupnĂ˝ ani po pokusech." - when: - - DEBUG == 1 - - (bettershift_controller.status | default(0)) not in [200, 307, 308] - - "'STATUS=200' not in (bettershift_vm.stdout | default(''))" - - "'STATUS=307' not in (bettershift_vm.stdout | default(''))" - - "'STATUS=308' not in (bettershift_vm.stdout | default(''))" - - - name: BetterShift | VM response excerpt (debug) - ansible.builtin.debug: - msg: "{{ (bettershift_vm.stdout | default(''))[:500] }}" - when: - - DEBUG == 1 - - bettershift_vm is defined - - bettershift_vm.stdout is defined diff --git a/update_homarr.yml b/update_homarr.yml index e956961..562003c 100644 --- a/update_homarr.yml +++ b/update_homarr.yml @@ -1,6 +1,6 @@ -# update_bettershift.yml +# update_homarr.yml -- name: Update BetterShift +- name: Update Homarr hosts: pve2_vm gather_facts: false @@ -9,12 +9,11 @@ compose_local_dir: "{{ playbook_dir }}/docker-compose" compose_remote_base: "/home/{{ ansible_user }}/.ansible-compose" - # BetterShift settings - bettershift_project: bettershift - bettershift_compose_filename: "docker-compose-bettershift.yml" - bettershift_service: bettershift - bettershift_port: 3067 - bettershift_data_dir: "/data/compose/bettershift/data" + # Homarr settings + homarr_project: homarr + homarr_compose_filename: "docker-compose-homarr.yml" + homarr_service: homarr + homarr_port: 7575 tasks: - name: Ensure remote compose directory exists @@ -23,65 +22,43 @@ state: directory mode: "0755" - - name: Ensure BetterShift data directory exists - ansible.builtin.file: - path: "{{ bettershift_data_dir }}" - state: directory - mode: "0755" - - - name: Upload BetterShift compose file to remote host + - name: Upload Homarr compose file to remote host ansible.builtin.copy: - src: "{{ compose_local_dir }}/{{ bettershift_compose_filename }}" - dest: "{{ compose_remote_base }}/{{ bettershift_compose_filename }}" + src: "{{ compose_local_dir }}/{{ homarr_compose_filename }}" + dest: "{{ compose_remote_base }}/{{ homarr_compose_filename }}" mode: "0644" - - name: Check BetterShift env file exists on remote host - ansible.builtin.stat: - path: "{{ compose_remote_base }}/.env.bettershift" - register: bettershift_env_file - - - name: Fail if BetterShift env file is missing - ansible.builtin.fail: - msg: >- - Missing {{ compose_remote_base }}/.env.bettershift on remote host. - Create it manually because it contains secrets. - when: not bettershift_env_file.stat.exists - - - name: Pull latest BetterShift image + - name: Pull latest Homarr image community.docker.docker_compose_v2: - project_name: "{{ bettershift_project }}" + project_name: "{{ homarr_project }}" project_src: "{{ compose_remote_base }}" files: - - "{{ bettershift_compose_filename }}" + - "{{ homarr_compose_filename }}" pull: always - - name: Recreate BetterShift service + - name: Recreate Homarr service community.docker.docker_compose_v2: - project_name: "{{ bettershift_project }}" + project_name: "{{ homarr_project }}" project_src: "{{ compose_remote_base }}" files: - - "{{ bettershift_compose_filename }}" + - "{{ homarr_compose_filename }}" services: - - "{{ bettershift_service }}" + - "{{ homarr_service }}" state: present recreate: always - - name: Wait for BetterShift port + - name: Wait for Homarr port ansible.builtin.wait_for: host: 127.0.0.1 - port: "{{ bettershift_port }}" + port: "{{ homarr_port }}" timeout: 60 - - name: Check BetterShift HTTP endpoint + - name: Check Homarr HTTP endpoint ansible.builtin.uri: - url: "http://127.0.0.1:{{ bettershift_port }}/" - status_code: - - 200 - - 307 - - 308 - follow_redirects: none - register: bettershift_http + url: "http://127.0.0.1:{{ homarr_port }}/" + status_code: 200 + register: homarr_http retries: 30 delay: 3 - until: bettershift_http.status in [200, 307, 308] + until: homarr_http.status == 200 changed_when: false