forked from jakub/ansible
165 lines
6.0 KiB
YAML
165 lines
6.0 KiB
YAML
# update_bettershift.yml
|
|
|
|
---
|
|
- name: Update BetterShift
|
|
hosts: pve2_vm
|
|
gather_facts: false
|
|
become: true
|
|
become_user: root
|
|
|
|
vars:
|
|
compose_local_dir: "{{ playbook_dir }}/docker-compose"
|
|
compose_remote_base: "/home/howard/.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)
|
|
known_errors = {
|
|
('audit_logs', 1, 'user', 0),
|
|
('audit_logs', 2, 'user', 0),
|
|
('audit_logs', 3, 'user', 0),
|
|
('audit_logs', 4, 'user', 0),
|
|
('audit_logs', 5, 'user', 0),
|
|
('calendars', 1, 'user', 0),
|
|
}
|
|
missing_user = 'RnqG0DGnnCOVgL3iWRRUAvHlMhLcdm6Y'
|
|
unexpected = []
|
|
|
|
for error in errors:
|
|
if error not in known_errors:
|
|
unexpected.append(error)
|
|
continue
|
|
|
|
table, rowid, _, _ = error
|
|
column = 'owner_id' if table == 'calendars' else 'user_id'
|
|
value = db.execute(
|
|
f'SELECT "{column}" FROM "{table}" WHERE rowid = ?',
|
|
(rowid,)
|
|
).fetchone()
|
|
|
|
if value != (missing_user,):
|
|
unexpected.append(error)
|
|
elif table == 'calendars':
|
|
calendar = db.execute(
|
|
'SELECT id FROM calendars WHERE rowid = ?', (rowid,)
|
|
).fetchone()
|
|
if calendar != ('60a3f0e7-c8f6-4f53-92f9-7088dff4656a',):
|
|
unexpected.append(error)
|
|
|
|
print('Unexpected foreign key violations:', unexpected)
|
|
sys.exit(0 if integrity == [('ok',)] and not unexpected 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
|