diff --git a/docker-compose/docker-compose-collabora.yml b/docker-compose/docker-compose-collabora.yml new file mode 100644 index 0000000..9a77b20 --- /dev/null +++ b/docker-compose/docker-compose-collabora.yml @@ -0,0 +1,23 @@ +version: '3' + +services: + collabora: + image: collabora/code:latest + container_name: collabora + restart: unless-stopped + networks: + - cloud + environment: + - TZ=Europe/Prague + - password=password + - username=nextcloud + - domain=cloud.martinfencl.eu + - extra_params=--o:ssl.enable=false --o:ssl.termination=true + - aliasgroup1=https://cloud.martinfencl.eu:443,https://collabora.martinfencl.eu:443 + - dictionaries=de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru cs_CZ + ports: + - 9980:9980 + +networks: + cloud: + driver: bridge \ No newline at end of file diff --git a/nextcloud/update_collabora.yml b/nextcloud/update_collabora.yml index d20cf12..e7f5d49 100644 --- a/nextcloud/update_collabora.yml +++ b/nextcloud/update_collabora.yml @@ -1,174 +1,92 @@ -# nextcloud/update_collabora.yml +# update_collabora.yml -- name: Update Collabora CODE on VM via Proxmox - hosts: linux_servers +- name: Update Collabora + hosts: pve2_vm gather_facts: false - become: true - become_user: root - become_method: sudo vars: - # --- Connection to VM (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" + compose_remote_dir: "{{ compose_remote_base }}/docker-compose" + compose_remote_archive: "{{ compose_remote_base }}/docker-compose.tar.gz" - # --- Debug mode (controlled via Semaphore variable) --- - DEBUG: "{{ lookup('env', 'DEBUG') | default(0) | int }}" - RETRIES: "{{ lookup('env', 'RETRIES') | default(25) | int }}" - - # --- Collabora specifics --- - collabora_debug_caps: true - collabora_caps_url: "https://collabora.martinfencl.eu/hosting/capabilities" - - # Use the FULL Nextcloud stack compose file; only target the 'collabora' service inside it - collabora_project: "nextcloud-collabora" - collabora_compose_file: "/data/compose/nextcloud/nextcloud-collabora.yml" - collabora_service: "collabora" - - # Docker command prefix (consistent behavior and quiet hints) - docker_prefix: "unalias docker 2>/dev/null || true; DOCKER_CLI_HINTS=0; command docker" - - # Commands to run on the target VM (quiet outputs) - collabora_commands: - - "{{ docker_prefix }} pull -q collabora/code:latest >/dev/null" - - "{{ docker_prefix }} compose -p {{ collabora_project }} -f {{ collabora_compose_file }} pull {{ collabora_service }} >/dev/null" - - "{{ docker_prefix }} compose -p {{ collabora_project }} -f {{ collabora_compose_file }} up -d --no-deps --force-recreate {{ collabora_service }} >/dev/null" + # Collabora settings + collabora_project: collabora + collabora_compose_filename: "docker-compose-collabora.yml" + collabora_service: collabora + collabora_port: 9980 tasks: - - name: Ensure sshpass is installed (for password-based SSH) # English comments - ansible.builtin.apt: - name: sshpass - state: present - update_cache: yes + - name: Ensure remote base directory exists + ansible.builtin.file: + path: "{{ compose_remote_base }}" + state: directory + mode: "0755" - - name: Run Collabora update commands on VM (via SSH) # use SSHPASS env, hide item value - 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: "{{ collabora_commands }}" - loop_control: - index_var: idx # <-- capture loop index here - label: "cmd-{{ idx }}" # <-- use idx instead of loop.index - register: collab_cmds - changed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Show outputs for each Collabora command - ansible.builtin.debug: - msg: | - CMD: {{ item.item }} - RC: {{ item.rc }} - STDOUT: - {{ (item.stdout | default('')).strip() }} - STDERR: - {{ (item.stderr | default('')).strip() }} - loop: "{{ collab_cmds.results }}" - when: DEBUG == 1 - - - name: Fail play if any Collabora command failed # also hide item label - ansible.builtin.assert: - that: "item.rc == 0" - fail_msg: "Collabora update failed on VM: {{ item.item }} (rc={{ item.rc }})" - success_msg: "All Collabora update commands succeeded." - loop: "{{ collab_cmds.results }}" - loop_control: - index_var: idx - label: "cmd-{{ idx }}" - - # ------------------------- - # Readiness checks (controller first, then VM fallback) - # ------------------------- - - - name: Collabora | Wait for capabilities (controller first) - ansible.builtin.uri: - url: "{{ collabora_caps_url }}" - method: GET - return_content: true - validate_certs: true - status_code: 200 - register: caps_controller + - name: Create local archive of docker-compose directory (controller) + ansible.builtin.archive: + path: "{{ compose_local_dir }}/" + dest: "/tmp/docker-compose.tar.gz" + format: gz delegate_to: localhost run_once: true - retries: "{{ RETRIES }}" - delay: 2 - until: caps_controller.status == 200 - failed_when: false + + - name: Upload archive to remote host + ansible.builtin.copy: + src: "/tmp/docker-compose.tar.gz" + dest: "{{ compose_remote_archive }}" + mode: "0644" + + - name: Recreate remote compose directory + ansible.builtin.file: + path: "{{ compose_remote_dir }}" + state: absent + + - name: Ensure remote compose directory exists + ansible.builtin.file: + path: "{{ compose_remote_dir }}" + state: directory + mode: "0755" + + - name: Extract archive on remote host + ansible.builtin.unarchive: + src: "{{ compose_remote_archive }}" + dest: "{{ compose_remote_dir }}" + remote_src: true + + - name: Pull latest Collabora image + community.docker.docker_compose_v2: + project_name: "{{ collabora_project }}" + project_src: "{{ compose_remote_dir }}" + files: + - "{{ collabora_compose_filename }}" + pull: always + + - name: Recreate Collabora service + community.docker.docker_compose_v2: + project_name: "{{ collabora_project }}" + project_src: "{{ compose_remote_dir }}" + files: + - "{{ collabora_compose_filename }}" + services: + - "{{ collabora_service }}" + state: present + recreate: always + + - name: Wait for Collabora port + ansible.builtin.wait_for: + host: 127.0.0.1 + port: "{{ collabora_port }}" + timeout: 120 + + - name: Check Collabora discovery endpoint (retry until ready) + ansible.builtin.uri: + url: "http://127.0.0.1:{{ collabora_port }}/hosting/discovery" + status_code: 200 + return_content: true + register: collabora_http + retries: 40 + delay: 3 + until: collabora_http.status == 200 and ('- - {{ - (caps_controller.json - if (caps_controller.status|default(0))==200 and (caps_controller.json is defined) - else ( - (caps_vm.stdout | default('') | trim | length > 0) - | ternary((caps_vm.stdout | trim | from_json), omit) - ) - ) - }} - failed_when: false - - - name: Collabora | Print concise summary - ansible.builtin.debug: - msg: >- - Collabora {{ collab_caps_json.productVersion | default('?') }} - ({{ collab_caps_json.productName | default('?') }}), - convert-to.available={{ collab_caps_json['convert-to']['available'] | default('n/a') }}, - serverId={{ collab_caps_json.serverId | default('n/a') }} - when: collab_caps_json is defined and DEBUG == 1 - - - name: Collabora | Capabilities unavailable (after retries) - ansible.builtin.debug: - msg: "Capabilities endpoint není dostupný ani po pokusech." - when: collab_caps_json is not defined and DEBUG == 1 - - # Optional full JSON (debug) - - name: Collabora | Full JSON (debug) - ansible.builtin.debug: - var: collab_caps_json - when: collabora_debug_caps and (collab_caps_json is defined) and DEBUG == 1 diff --git a/old/update_collabora.yml b/old/update_collabora.yml new file mode 100644 index 0000000..d20cf12 --- /dev/null +++ b/old/update_collabora.yml @@ -0,0 +1,174 @@ +# nextcloud/update_collabora.yml + +- name: Update Collabora CODE on VM via Proxmox + hosts: linux_servers + gather_facts: false + become: true + become_user: root + become_method: sudo + + vars: + # --- Connection to VM (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 + + # --- Debug mode (controlled via Semaphore variable) --- + DEBUG: "{{ lookup('env', 'DEBUG') | default(0) | int }}" + RETRIES: "{{ lookup('env', 'RETRIES') | default(25) | int }}" + + # --- Collabora specifics --- + collabora_debug_caps: true + collabora_caps_url: "https://collabora.martinfencl.eu/hosting/capabilities" + + # Use the FULL Nextcloud stack compose file; only target the 'collabora' service inside it + collabora_project: "nextcloud-collabora" + collabora_compose_file: "/data/compose/nextcloud/nextcloud-collabora.yml" + collabora_service: "collabora" + + # Docker command prefix (consistent behavior and quiet hints) + docker_prefix: "unalias docker 2>/dev/null || true; DOCKER_CLI_HINTS=0; command docker" + + # Commands to run on the target VM (quiet outputs) + collabora_commands: + - "{{ docker_prefix }} pull -q collabora/code:latest >/dev/null" + - "{{ docker_prefix }} compose -p {{ collabora_project }} -f {{ collabora_compose_file }} pull {{ collabora_service }} >/dev/null" + - "{{ docker_prefix }} compose -p {{ collabora_project }} -f {{ collabora_compose_file }} up -d --no-deps --force-recreate {{ collabora_service }} >/dev/null" + + tasks: + - name: Ensure sshpass is installed (for password-based SSH) # English comments + ansible.builtin.apt: + name: sshpass + state: present + update_cache: yes + + - name: Run Collabora update commands on VM (via SSH) # use SSHPASS env, hide item value + 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: "{{ collabora_commands }}" + loop_control: + index_var: idx # <-- capture loop index here + label: "cmd-{{ idx }}" # <-- use idx instead of loop.index + register: collab_cmds + changed_when: false + no_log: "{{ DEBUG == 0 }}" + + - name: Show outputs for each Collabora command + ansible.builtin.debug: + msg: | + CMD: {{ item.item }} + RC: {{ item.rc }} + STDOUT: + {{ (item.stdout | default('')).strip() }} + STDERR: + {{ (item.stderr | default('')).strip() }} + loop: "{{ collab_cmds.results }}" + when: DEBUG == 1 + + - name: Fail play if any Collabora command failed # also hide item label + ansible.builtin.assert: + that: "item.rc == 0" + fail_msg: "Collabora update failed on VM: {{ item.item }} (rc={{ item.rc }})" + success_msg: "All Collabora update commands succeeded." + loop: "{{ collab_cmds.results }}" + loop_control: + index_var: idx + label: "cmd-{{ idx }}" + + # ------------------------- + # Readiness checks (controller first, then VM fallback) + # ------------------------- + + - name: Collabora | Wait for capabilities (controller first) + ansible.builtin.uri: + url: "{{ collabora_caps_url }}" + method: GET + return_content: true + validate_certs: true + status_code: 200 + register: caps_controller + delegate_to: localhost + run_once: true + retries: "{{ RETRIES }}" + delay: 2 + until: caps_controller.status == 200 + failed_when: false + changed_when: false + + - name: Collabora | VM-side fetch (pure JSON via Python) # use SSHPASS env here too + ansible.builtin.command: + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - bash + - -lc + - | + python3 - <<'PY' + import json, urllib.request, sys + try: + with urllib.request.urlopen("{{ collabora_caps_url }}", timeout=15) as r: + sys.stdout.write(r.read().decode()) + except Exception: + pass + PY + environment: + SSHPASS: "{{ vm_pass }}" + register: caps_vm + changed_when: false + failed_when: false + when: caps_controller.status | default(0) != 200 or caps_controller.json is not defined + no_log: "{{ DEBUG == 0 }}" + + - name: Collabora | Choose JSON (controller wins, else VM) + ansible.builtin.set_fact: + collab_caps_json: >- + {{ + (caps_controller.json + if (caps_controller.status|default(0))==200 and (caps_controller.json is defined) + else ( + (caps_vm.stdout | default('') | trim | length > 0) + | ternary((caps_vm.stdout | trim | from_json), omit) + ) + ) + }} + failed_when: false + + - name: Collabora | Print concise summary + ansible.builtin.debug: + msg: >- + Collabora {{ collab_caps_json.productVersion | default('?') }} + ({{ collab_caps_json.productName | default('?') }}), + convert-to.available={{ collab_caps_json['convert-to']['available'] | default('n/a') }}, + serverId={{ collab_caps_json.serverId | default('n/a') }} + when: collab_caps_json is defined and DEBUG == 1 + + - name: Collabora | Capabilities unavailable (after retries) + ansible.builtin.debug: + msg: "Capabilities endpoint není dostupný ani po pokusech." + when: collab_caps_json is not defined and DEBUG == 1 + + # Optional full JSON (debug) + - name: Collabora | Full JSON (debug) + ansible.builtin.debug: + var: collab_caps_json + when: collabora_debug_caps and (collab_caps_json is defined) and DEBUG == 1 diff --git a/nextcloud/update_nextcloud_mariadb_redis.yml b/old/update_nextcloud_mariadb_redis.yml similarity index 100% rename from nextcloud/update_nextcloud_mariadb_redis.yml rename to old/update_nextcloud_mariadb_redis.yml