# update_bettershift.yml --- - name: Update BetterShift hosts: pve2_vm gather_facts: false become: true vars: compose_local_dir: "{{ playbook_dir }}/docker-compose" compose_remote_base: "/home/{{ ansible_user }}/.ansible-compose/docker-compose" bettershift_project: bettershift bettershift_compose_filename: docker-compose-bettershift.yml bettershift_service: bettershift bettershift_port: 3067 bettershift_data_dir: /data/compose/bettershift/data bettershift_version: v3.3.0 environment: BETTERSHIFT_VERSION: "{{ bettershift_version }}" tasks: - name: Check existing database and env file ansible.builtin.stat: path: "{{ item }}" loop: - "{{ bettershift_data_dir }}/sqlite.db" - "{{ compose_remote_base }}/.env.bettershift" register: bettershift_files - name: Refuse missing or empty files ansible.builtin.assert: that: - item.stat.isreg | default(false) - item.stat.size | default(0) > 0 fail_msg: "Missing or empty file: {{ item.item }}" loop: "{{ bettershift_files.results }}" loop_control: label: "{{ item.item }}" - name: Check database before changing deployment ansible.builtin.command: argv: - python3 - -c - | import pathlib, sqlite3, sys path = pathlib.Path(sys.argv[1]) with sqlite3.connect(path.as_uri() + '?mode=ro', uri=True) as src: with sqlite3.connect(':memory:') as db: src.backup(db) integrity = db.execute('PRAGMA integrity_check').fetchall() errors = db.execute('PRAGMA foreign_key_check').fetchall() print('Integrity:', integrity, 'Foreign key violations:', errors) sys.exit(0 if integrity == [('ok',)] and not errors else 1) - "{{ bettershift_data_dir }}/sqlite.db" changed_when: false - name: Upload BetterShift compose file ansible.builtin.copy: src: "{{ compose_local_dir }}/{{ bettershift_compose_filename }}" dest: "{{ compose_remote_base }}/{{ bettershift_compose_filename }}" mode: '0644' backup: true - name: Pull image without starting it community.docker.docker_compose_v2_pull: project_name: "{{ bettershift_project }}" project_src: "{{ compose_remote_base }}" files: ["{{ bettershift_compose_filename }}"] - name: Create private backup directory ansible.builtin.tempfile: state: directory path: /data/compose/bettershift prefix: backup-before-upgrade- register: bettershift_backup - name: Show backup location ansible.builtin.debug: msg: "Backup: {{ bettershift_backup.path }}" - name: Stop service and create a verified backup block: - name: Stop BetterShift ansible.builtin.command: argv: [docker, stop, --timeout, '60', bettershift] changed_when: true - name: Copy data and compare files ansible.builtin.shell: | set -eu test "$(docker inspect --format '{% raw %}{{.State.Running}}{% endraw %}' bettershift)" = false cp -a -- "$DATA_DIR" "$BACKUP_DIR/data" diff -qr -- "$DATA_DIR" "$BACKUP_DIR/data" environment: DATA_DIR: "{{ bettershift_data_dir }}" BACKUP_DIR: "{{ bettershift_backup.path }}" changed_when: true rescue: - name: Restart original container if backup fails ansible.builtin.command: argv: [docker, start, bettershift] changed_when: true - name: Abort update ansible.builtin.fail: msg: Backup failed. Original container restarted; update aborted. - name: Recreate BetterShift once community.docker.docker_compose_v2: project_name: "{{ bettershift_project }}" project_src: "{{ compose_remote_base }}" files: ["{{ bettershift_compose_filename }}"] services: ["{{ bettershift_service }}"] state: present pull: never recreate: always - name: Check BetterShift HTTP endpoint ansible.builtin.uri: url: "http://127.0.0.1:{{ bettershift_port }}/" status_code: [200, 307, 308] follow_redirects: none register: bettershift_http retries: 30 delay: 3 until: bettershift_http.status | default(0) in [200, 307, 308] changed_when: false