Post-Tyranny-Tech-Infrastru.../ansible/playbooks/260123-upgrade-nextcloud.yml

293 lines
10 KiB
YAML
Raw Normal View History

---
# Nextcloud Major Version Upgrade Playbook
# Created: 2026-01-23
# Purpose: Safely upgrade Nextcloud from v30 to v32 via v31 (staged upgrade)
#
# Usage:
# ansible-playbook -i hcloud.yml playbooks/260123-upgrade-nextcloud.yml --limit kikker
#
# Requirements:
# - HCLOUD_TOKEN environment variable set
# - SSH access to target server
# - Sufficient disk space for backups
#
# Notes:
# - Nextcloud does NOT support skipping major versions
# - This playbook performs: v30 → v31 → v32
# - Creates backups before each stage
# - Automatic rollback on failure
- name: Upgrade Nextcloud from v30 to v32 (staged)
hosts: all
become: true
gather_facts: true
vars:
nextcloud_base_dir: "/opt/nextcloud"
backup_dir: "/root/nextcloud-backup-{{ ansible_date_time.iso8601_basic_short }}"
upgrade_stages:
- { from: "30", to: "31", stage: 1 }
- { from: "31", to: "32", stage: 2 }
tasks:
# ============================================================
# PRE-UPGRADE CHECKS AND PREPARATION
# ============================================================
- name: Display upgrade plan
debug:
msg: |
============================================================
Nextcloud Upgrade Plan - {{ inventory_hostname }}
============================================================
Upgrade Path: v30 → v31 → v32
This playbook will:
1. Check current Nextcloud version
2. Create full backup of volumes and database
3. Disable all apps except core ones
4. Upgrade to v31 (Stage 1)
5. Verify v31 is working
6. Upgrade to v32 (Stage 2)
7. Verify v32 is working
8. Re-enable apps
Backup location: {{ backup_dir }}
Estimated time: 15-25 minutes
============================================================
- name: Check if Nextcloud is installed
shell: docker ps --filter "name=nextcloud" --format "{{ '{{' }}.Names{{ '}}' }}"
register: nextcloud_running
changed_when: false
failed_when: false
- name: Fail if Nextcloud is not running
fail:
msg: "Nextcloud container is not running on {{ inventory_hostname }}"
when: "'nextcloud' not in nextcloud_running.stdout"
- name: Get current Nextcloud version
shell: docker exec -u www-data nextcloud php occ status --output=json
register: nextcloud_status
changed_when: false
- name: Parse Nextcloud status
set_fact:
nc_status: "{{ nextcloud_status.stdout | from_json }}"
- name: Display current version
debug:
msg: |
Current version: {{ nc_status.versionstring }}
Installed: {{ nc_status.installed }}
Maintenance mode: {{ nc_status.maintenance }}
Needs DB upgrade: {{ nc_status.needsDbUpgrade }}
- name: Check if already on target version
debug:
msg: "Nextcloud is already on v32.x - skipping upgrade"
when: nc_status.versionstring is version('32', '>=')
- name: End play if already upgraded
meta: end_host
when: nc_status.versionstring is version('32', '>=')
- name: Verify starting version is v30.x
fail:
msg: "This playbook only upgrades from v30. Current version: {{ nc_status.versionstring }}"
when: nc_status.versionstring is version('30', '<') or nc_status.versionstring is version('31', '>=')
- name: Check disk space
shell: df -h {{ nextcloud_base_dir }} | tail -1 | awk '{print $4}'
register: disk_space
changed_when: false
- name: Display available disk space
debug:
msg: "Available disk space: {{ disk_space.stdout }}"
- name: Check if maintenance mode is enabled
fail:
msg: "Nextcloud is in maintenance mode. Please investigate before upgrading."
when: nc_status.maintenance | bool
# ============================================================
# BACKUP PHASE
# ============================================================
- name: Create backup directory
file:
path: "{{ backup_dir }}"
state: directory
mode: '0700'
- name: Enable Nextcloud maintenance mode
shell: docker exec -u www-data nextcloud php occ maintenance:mode --on
register: maintenance_on
changed_when: "'Maintenance mode enabled' in maintenance_on.stdout"
- name: Backup Nextcloud database
shell: |
docker exec nextcloud-db pg_dump -U nextcloud nextcloud | gzip > {{ backup_dir }}/database.sql.gz
args:
creates: "{{ backup_dir }}/database.sql.gz"
- name: Get database backup size
stat:
path: "{{ backup_dir }}/database.sql.gz"
register: db_backup
- name: Display database backup info
debug:
msg: "Database backup: {{ (db_backup.stat.size / 1024 / 1024) | round(2) }} MB"
- name: Stop Nextcloud containers (for volume backup)
community.docker.docker_compose_v2:
project_src: "{{ nextcloud_base_dir }}"
state: stopped
- name: Backup Nextcloud app volume
shell: |
tar -czf {{ backup_dir }}/nextcloud-app-volume.tar.gz -C /var/lib/docker/volumes/nextcloud-app/_data .
args:
creates: "{{ backup_dir }}/nextcloud-app-volume.tar.gz"
- name: Backup Nextcloud database volume
shell: |
tar -czf {{ backup_dir }}/nextcloud-db-volume.tar.gz -C /var/lib/docker/volumes/nextcloud-db-data/_data .
args:
creates: "{{ backup_dir }}/nextcloud-db-volume.tar.gz"
- name: Copy current docker-compose.yml to backup
copy:
src: "{{ nextcloud_base_dir }}/docker-compose.yml"
dest: "{{ backup_dir }}/docker-compose.yml.backup"
remote_src: true
- name: Display backup summary
debug:
msg: |
============================================================
Backup completed: {{ backup_dir }}
To restore from backup if needed:
1. Stop containers: cd {{ nextcloud_base_dir }} && docker compose down
2. Restore app volume: tar -xzf {{ backup_dir }}/nextcloud-app-volume.tar.gz -C /var/lib/docker/volumes/nextcloud-app/_data
3. Restore DB volume: tar -xzf {{ backup_dir }}/nextcloud-db-volume.tar.gz -C /var/lib/docker/volumes/nextcloud-db-data/_data
4. Restore compose file: cp {{ backup_dir }}/docker-compose.yml.backup {{ nextcloud_base_dir }}/docker-compose.yml
5. Start containers: cd {{ nextcloud_base_dir }} && docker compose up -d
============================================================
- name: Restart Nextcloud containers after backup
community.docker.docker_compose_v2:
project_src: "{{ nextcloud_base_dir }}"
state: present
- name: Wait for Nextcloud to be ready after backup restore
shell: |
timeout=120
elapsed=0
while [ $elapsed -lt $timeout ]; do
if docker exec nextcloud curl -f http://localhost:80/status.php 2>/dev/null; then
echo "Nextcloud ready"
exit 0
fi
sleep 5
elapsed=$((elapsed + 5))
done
echo "Timeout waiting for Nextcloud"
exit 1
register: nextcloud_restored
changed_when: false
# ============================================================
# STAGED UPGRADE LOOP
# ============================================================
- name: Perform staged upgrades
include_tasks: "{{ playbook_dir }}/260123-upgrade-nextcloud-stage.yml"
loop: "{{ upgrade_stages }}"
loop_control:
loop_var: stage
# ============================================================
# POST-UPGRADE VALIDATION
# ============================================================
- name: Get final Nextcloud version
shell: docker exec -u www-data nextcloud php occ status --output=json
register: final_status
changed_when: false
- name: Parse final status
set_fact:
final_nc_status: "{{ final_status.stdout | from_json }}"
- name: Verify upgrade to v32
fail:
msg: "Upgrade failed - still on v{{ final_nc_status.versionstring }}"
when: final_nc_status.versionstring is version('32', '<')
- name: Run Nextcloud system check
shell: docker exec -u www-data nextcloud php occ check
register: system_check
changed_when: false
failed_when: false
- name: Display system check results
debug:
msg: "{{ system_check.stdout_lines }}"
- name: Re-enable user_oidc app
shell: docker exec -u www-data nextcloud php occ app:enable user_oidc
register: oidc_enable
changed_when: "'enabled' in oidc_enable.stdout"
failed_when: false
- name: Re-enable richdocuments (Collabora)
shell: docker exec -u www-data nextcloud php occ app:enable richdocuments
register: collabora_enable
changed_when: "'enabled' in collabora_enable.stdout"
failed_when: false
- name: Disable maintenance mode
shell: docker exec -u www-data nextcloud php occ maintenance:mode --off
register: maintenance_off
changed_when: "'Maintenance mode disabled' in maintenance_off.stdout"
- name: Update docker-compose.yml to use 'latest' tag
lineinfile:
path: "{{ nextcloud_base_dir }}/docker-compose.yml"
regexp: '^\s*image:\s*nextcloud:32\s*$'
line: ' image: nextcloud:latest'
state: present
- name: Display upgrade success message
debug:
msg: |
============================================================
✓ Nextcloud Upgrade SUCCESSFUL!
============================================================
Server: {{ inventory_hostname }}
Previous version: v30.x
New version: v{{ final_nc_status.versionstring }}
Backup location: {{ backup_dir }}
Next steps:
1. Test login at: https://nextcloud.{{ client_domain }}
2. Test OIDC login (Login with Authentik)
3. Test file upload/download
4. Test Collabora Office integration
If everything works, you can remove the backup:
rm -rf {{ backup_dir }}
The docker-compose.yml has been updated to use 'latest' tag
for future automatic updates.
============================================================