Introduction
When restoring Ansible Tower or AWX from a backup, the restore process may fail or apply incorrect configuration because it references an outdated or wrong generation of the backup manifest file. The setup.sh restore process relies on a manifest.json file that contains metadata about backup contents, database schema versions, and Tower version information. If this manifest doesn't match the actual backup files or the target Tower version, the restore can fail silently, apply incomplete configuration, or corrupt the database schema.
This typically occurs when: - Multiple backup files exist in the same directory - The manifest file was manually copied from another backup - The backup was created with a different Tower version than the restore target - Incremental or differential backups were used incorrectly
Symptoms
During restore execution:
```bash $ ./setup.sh -r /backup/tower_backup_20240315/
TASK [restore: Check backup manifest] *********** fatal: [localhost]: FAILED! => {"changed": false, "msg": "Backup manifest not found or invalid"}
TASK [restore: Validate backup version] ********* fatal: [localhost]: FAILED! => {"changed": false, "msg": "Backup version 4.2.3 does not match installed version 4.3.0"}
TASK [restore: Check manifest checksum] ********* fatal: [localhost]: FAILED! => {"changed": false, "msg": "Manifest checksum mismatch: expected abc123, found def456"} ```
In Tower restore logs:
2024-03-15 14:23:45,123 ERROR awx.setup.restore Backup manifest indicates Tower version 4.2.3 but backup contains Tower 4.1.0 database schema
2024-03-15 14:24:12,456 WARNING awx.setup.restore Manifest references missing file: tower_db_backup.sql.gz
2024-03-15 14:25:01,789 ERROR awx.setup.restore Database schema migration failed: version mismatch between manifest and actual backupWhen examining the manifest:
```bash $ cat /backup/tower_backup_20240315/manifest.json { "version": "4.2.3", "backup_date": "2024-03-10T08:00:00Z", "tower_version": "4.2.3", "database_version": "46", "files": [ {"name": "tower_db_backup.sql.gz", "checksum": "abc123", "size": 5242880}, {"name": "tower_settings.json", "checksum": "def456", "size": 8192} ] }
# But actual files in backup $ ls -la /backup/tower_backup_20240315/ total 5220 -rw-r--r-- 1 root root 5242880 Mar 15 14:00 tower_db_backup.sql.gz -rw-r--r-- 1 root root 8192 Mar 15 14:00 tower_settings.json
# Checksum mismatch $ sha256sum /backup/tower_backup_20240315/tower_db_backup.sql.gz def789... tower_db_backup.sql.gz # Different from manifest's abc123
# Database schema version in actual backup $ zcat /backup/tower_backup_20240315/tower_db_backup.sql.gz | head -100 | grep schema_version -- Schema version: 44 (manifest says 46!) ```
After a failed restore, Tower may be in an inconsistent state:
``` # Tower service fails to start $ sudo journalctl -u tower.service Mar 15 14:30:45 tower01 python[12345]: django.db.migrations.exceptions.InconsistentMigrationHistory: Migration main.0046_configuration is applied before its dependency main.0044_license
# API returns errors $ curl -k -u admin:password https://localhost/api/v2/ping/ {"detail": "Service unavailable. Database schema mismatch."} ```
Common Causes
The manifest mismatch occurs due to several root causes:
- 1.Manual backup copying: When administrators manually copy backup files between servers or directories, the manifest file may not be updated to reflect the actual files copied.
- 2.Multiple backup generations in same directory: Tower's default backup naming uses timestamps, but if multiple backups are manually organized into the same folder,
manifest.jsonfrom one backup may reference files from another. - 3.Version mismatch between backup source and restore target: The backup was taken on Tower 4.2.3, but the restore is attempted on Tower 4.3.0. Tower restore requires version matching or migration scripts.
- 4.Interrupted backup process: If a backup was interrupted mid-process, the manifest may indicate files that weren't fully written or have partial checksums.
- 5.Differential backups without proper tracking: Using rsync or similar tools to create incremental backups can result in a manifest that doesn't match the actual accumulated files.
- 6.Database schema version embedded in manifest: The manifest contains the database migration version (
database_version), and this must match the actual SQL dump's schema version.
Step-by-Step Fix
Step 1: Inspect the Current Backup State
Identify what files exist and compare to manifest:
```bash # List all backup files with checksums cd /backup/tower_backup_20240315/ sha256sum * > /tmp/actual_checksums.txt cat /tmp/actual_checksums.txt
# Parse and display manifest python3 -c " import json with open('manifest.json') as f: manifest = json.load(f) print('Tower Version:', manifest.get('tower_version')) print('Database Version:', manifest.get('database_version')) print('Backup Date:', manifest.get('backup_date')) print('Files in manifest:') for f in manifest.get('files', []): print(f' {f[\"name\"]}: {f[\"checksum\"]} ({f[\"size\"]} bytes)') "
# Compare manifest files to actual files python3 << 'EOF' import json import hashlib import os
with open('manifest.json') as f: manifest = json.load(f)
print("File verification:") for expected in manifest.get('files', []): filename = expected['name'] expected_checksum = expected['checksum'] expected_size = expected['size']
if not os.path.exists(filename): print(f"MISSING: {filename}") continue
actual_size = os.path.getsize(filename) with open(filename, 'rb') as f: actual_checksum = hashlib.sha256(f.read()).hexdigest()[:16]
if actual_size != expected_size: print(f"SIZE MISMATCH: {filename} (expected {expected_size}, got {actual_size})") elif actual_checksum != expected_checksum: print(f"CHECKSUM MISMATCH: {filename}") print(f" Expected: {expected_checksum}") print(f" Actual: {actual_checksum}") else: print(f"OK: {filename}") EOF ```
Step 2: Regenerate the Manifest
Create a correct manifest for your backup files:
```bash #!/bin/bash # regenerate_manifest.sh
BACKUP_DIR="/backup/tower_backup_20240315" cd "$BACKUP_DIR"
# Get Tower version from installed package or RPM TOWER_VERSION=$(rpm -q ansible-tower --queryformat '%{VERSION}' 2>/dev/null || echo "unknown")
# Get database schema version from SQL dump DB_VERSION=$(zcat tower_db_backup.sql.gz 2>/dev/null | grep -oP "Schema version: \K[0-9]+" | head -1) if [ -z "$DB_VERSION" ]; then # Try alternative method DB_VERSION=$(zcat tower_db_backup.sql.gz 2>/dev/null | grep -oP "INSERT.*south_migrationhistory.*VALUES\('\w+', '(\d+)'" | tail -1 | grep -oP '\d+$') fi
# Generate file list with checksums FILES_JSON="[]" for file in *; do if [ "$file" = "manifest.json" ]; then continue; fi if [ -f "$file" ]; then checksum=$(sha256sum "$file" | awk '{print $1}') size=$(stat -c%s "$file") FILES_JSON=$(echo "$FILES_JSON" | python3 -c " import sys, json files = json.load(sys.stdin) files.append({'name': '$file', 'checksum': '${checksum:0:16}', 'size': $size}) print(json.dumps(files, indent=2)) ") fi done
# Create new manifest python3 << EOF import json from datetime import datetime
manifest = { "version": "$TOWER_VERSION", "backup_date": datetime.now().isoformat() + "Z", "tower_version": "$TOWER_VERSION", "database_version": "${DB_VERSION:-unknown}", "files": $FILES_JSON }
with open('manifest.json', 'w') as f: json.dump(manifest, f, indent=2)
print("Generated new manifest.json") print(json.dumps(manifest, indent=2)) EOF ```
Step 3: Verify Database Schema Version
Ensure the database dump has correct schema markers:
```bash # Extract and check database version cd /backup/tower_backup_20240315/ zcat tower_db_backup.sql.gz | head -200 > /tmp/backup_header.sql
# Look for version markers grep -i "version|schema" /tmp/backup_header.sql
# Check for migration history zcat tower_db_backup.sql.gz | grep -A5 "django_migrations" | head -30
# If using AWX, check for alembic version zcat tower_db_backup.sql.gz | grep -i "alembic_version"
# Query actual migration state in backup zcat tower_db_backup.sql.gz | grep "INSERT INTO.*django_migrations" | tail -5
# Expected output shows latest applied migrations: -- INSERT INTO django_migrations (app, name, applied) VALUES ('main', '0046_configuration', '2024-03-10 08:00:00'); ```
Step 4: Handle Version Mismatch
If the backup was created with a different Tower version:
```bash # Check installed Tower version rpm -qa | grep ansible-tower # ansible-tower-4.3.0-1.el8.x86_64
# Check backup Tower version grep tower_version /backup/tower_backup_20240315/manifest.json # "tower_version": "4.2.3"
# Option 1: Install matching Tower version before restore # Download specific version wget https://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-4.2.3.tar.gz tar xvf ansible-tower-setup-4.2.3.tar.gz cd ansible-tower-setup-4.2.3 ./setup.sh
# Then perform restore ./setup.sh -r /backup/tower_backup_20240315/
# Option 2: Upgrade backup before restore (advanced) # This requires migrating the database schema # 1. Restore to matching version # 2. Upgrade Tower with migration # 3. Create new backup # 4. Restore to target version ```
Step 5: Fix Corrupted Backup Files
If backup files are corrupted or incomplete:
```bash # Verify SQL dump integrity zcat tower_db_backup.sql.gz | tail -20 # Should end with: -- PostgreSQL database dump complete --
# Check for errors in SQL dump zcat tower_db_backup.sql.gz | grep -i "error|failed|corrupt"
# If SQL dump is truncated or corrupted, you may need to: # 1. Find an earlier backup ls -la /backup/ # 2. Use Point-In-Time-Recovery if WAL archiving was enabled # 3. Repair specific tables if partial data is available
# Test database restore to temporary database sudo -u postgres createdb tower_test zcat tower_db_backup.sql.gz | sudo -u postgres psql tower_test 2>&1 | grep -i error sudo -u postgres dropdb tower_test ```
Step 6: Perform Clean Restore
Once manifest is corrected, perform the restore:
```bash # Verify manifest is now correct cat /backup/tower_backup_20240315/manifest.json
# Stop Tower services sudo ansible-tower-service stop
# Backup current state (in case restore fails) sudo -u postgres pg_dump awx > /tmp/pre_restore_backup.sql cp -r /etc/tower /tmp/tower_etc_backup
# Perform restore cd /path/to/ansible-tower-setup-*/ ./setup.sh -r /backup/tower_backup_20240315/
# Monitor restore progress tail -f /var/log/tower/setup-*.log
# Start Tower and verify sudo ansible-tower-service start curl -k -u admin:password https://localhost/api/v2/ping/ ```
Verification
Confirm the restore was successful:
```bash # Check Tower health curl -k -u admin:password https://localhost/api/v2/ping/ | jq
# Expected output: { "ha": false, "version": "4.3.0", "active_node": "localhost", "instance_groups": [...] }
# Verify database migrations sudo -u postgres psql -d awx -c "SELECT * FROM django_migrations ORDER BY id DESC LIMIT 5;"
# Check inventory count matches expectations curl -k -u admin:password https://localhost/api/v2/inventories/ | jq '.count'
# Verify job templates exist curl -k -u admin:password https://localhost/api/v2/job_templates/ | jq '.count'
# Check credentials curl -k -u admin:password https://localhost/api/v2/credentials/ | jq '.count'
# Verify organizations and teams curl -k -u admin:password https://localhost/api/v2/organizations/ | jq '.count'
# Run a test job to verify functionality curl -X POST -k -u admin:password \ https://localhost/api/v2/job_templates/1/launch/ | jq ```
Related Issues
- [ansible-tower-backup-restore-fails-database-lock](/articles/ansible-tower-backup-restore-fails-database-lock)
- [ansible-tower-version-migration-failures](/articles/ansible-tower-version-migration-failures)
- [ansible-database-schema-mismatch-after-upgrade](/articles/ansible-database-schema-mismatch-after-upgrade)
Related Articles
- [WordPress troubleshooting: Ansible Artifact Download Uses an Old Mi](ansible-artifact-download-uses-an-old-mirror-after-proxy-change)
- [WordPress troubleshooting: Ansible Audit Trail Misses Events Under ](ansible-audit-trail-misses-events-under-burst-load)
- [WordPress troubleshooting: Ansible Background Worker Gets Stuck in ](ansible-background-worker-stuck-in-a-retry-loop)
- [WordPress troubleshooting: Ansible Backup Completes but Restore Fai](ansible-backup-completes-but-restore-fails-checksum-validation)
- [WordPress troubleshooting: Ansible Batch Importer Duplicates Rows A](ansible-batch-importer-duplicates-rows-after-a-retry)
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "WordPress troubleshooting: Ansible Restore Process Uses the Wrong G", "description": "Learn how to fix Ansible Restore Process Uses the Wrong Generation of Backup Manifest. Professional WordPress troubleshooting solutions with step-by-step guidance. WP error fix, WordPress optimization, WP security, WordPress performance.", "url": "https://www.fixwikihub.com/ansible-restore-process-uses-the-wrong-generation-of-backup-manifest", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-03-07T23:01:06.823Z", "dateModified": "2026-03-07T23:01:06.823Z" } </script>