Merry Christmas & Happy 2027! Less downtime. More good times. Celebrating 13 years of sorlavit.com
Skip to content
Sorlavit KimIT Support, Network & Infrastructure Services Let’s talk

ปุ่มแปลไทยจะเปิดบทความผ่าน Google Translate เพื่อแปลอัตโนมัติ โดยคงโค้ดและคำสั่งไว้ตามต้นฉบับ

System Security / Foundations

A backup needs a recovery test

Perform a real file backup and isolated restore, then detect both a missing file and corrupted content with a SHA-256 manifest.

Start hands-on practice · เริ่มภาคปฏิบัติ ↓

Compiled for Sorlavit Kim · Published · Updated · 3 min read

Practical guide · คู่มือลงมือทำ

Download worksheet · ดาวน์โหลดขั้นตอน

Detailed practical guide

Prepare your workspace and inputs

Save the program as restore_check.py and run python3 restore_check.py. It creates three folders inside a new temporary workspace and never accepts a user-supplied deletion path. The source data is synthetic.

Platform context: Python 3.10+; local temporary directories and standard library. This is a file-level recovery test, not a database-consistent backup.

Scenario to reproduce or investigate

A backup job reports success but nobody has checked whether the restored files are complete and unchanged. The test must validate a restore, not just the existence of a backup directory.

Evidence to record in your worksheet
  • Actual target and platform release
  • Exact inputs or substituted values
  • Baseline result
  • Per-step expected and observed output
  • Failure encountered and corrective action
  • Final acceptance and recovery state
  1. Define the recovery boundary and file inventory

    The backup boundary contains three small UTF-8 files. Record filenames and SHA-256 digests before copying. A file written after this manifest belongs to a later recovery point and must not silently enter the expected result.

    Command, configuration or input

    Expected files: customers.txt, settings.txt, readme.txt
    Expected recovery point: the source state immediately before copytree
    Expected result · ผลที่ควรเห็น

    The recovery checklist names exact files and their hashes rather than relying on the folder size.

    If it fails · เมื่อไม่ผ่าน

    For a database or live application, replace a plain file copy with that product’s supported consistent backup method; this exercise does not freeze live writes.

  2. Create, restore and deliberately corrupt the copy

    Run the complete script. It verifies a successful restore, changes one restored file, removes another and confirms that each failure is detected. The assertions exercise real filesystem operations in a disposable directory.

    Save and run this example

    from pathlib import Path
    from tempfile import TemporaryDirectory
    from hashlib import sha256
    from time import perf_counter
    import shutil
    
    def manifest(root):
        records = {}
        for path in sorted(root.rglob("*")):
            if path.is_file():
                digest = sha256()
                with path.open("rb") as handle:
                    for chunk in iter(lambda: handle.read(1024 * 1024), b""):
                        digest.update(chunk)
                records[str(path.relative_to(root))] = digest.hexdigest()
        return records
    
    with TemporaryDirectory(prefix="sorlavit-restore-") as directory:
        workspace = Path(directory)
        source = workspace / "source"
        source.mkdir()
        for name, value in {"customers.txt": "customer-001\n", "settings.txt": "region=lab\n", "readme.txt": "synthetic backup\n"}.items():
            (source / name).write_text(value, encoding="utf-8")
        expected = manifest(source)
        backup = workspace / "backup"
        restored = workspace / "restored"
        shutil.copytree(source, backup)
        (source / "settings.txt").write_text("region=changed-after-backup\n", encoding="utf-8")
        started = perf_counter()
        shutil.copytree(backup, restored)
        assert manifest(restored) == expected
        duration = perf_counter() - started
        (restored / "settings.txt").write_text("corrupt\n", encoding="utf-8")
        assert manifest(restored) != expected
        shutil.copy2(backup / "settings.txt", restored / "settings.txt")
        (restored / "readme.txt").unlink()
        assert manifest(restored) != expected
        shutil.copy2(backup / "readme.txt", restored / "readme.txt")
        assert manifest(restored) == expected
        print("PASS: 3 files restored; corruption and missing-file checks detected")
        print("Observed restore seconds:", round(duration, 6))
    
    Expected result · ผลที่ควรเห็น

    The script prints PASS: 3 files restored; corruption and missing-file checks detected, followed by the measured restore duration.

    If it fails · เมื่อไม่ผ่าน

    A permission or space error means the restore did not pass. Keep the backup and record the failing operation before retrying on a destination with sufficient capacity.

  3. Run the same verification against an approved backup copy

    For a real drill, choose an existing recovery point and restore it to an isolated destination through the supported backup product. Compare the restored file manifest with the inventory recorded at that recovery point, open representative documents and check permissions. Record restore start, ready-for-use time, missing files and the person accepting the result. Measure application recovery separately from copying bytes.

    Command, configuration or input

    Recovery point | expected files | restored files | hash mismatches | permission result | usable-at time
    Expected result · ผลที่ควรเห็น

    A recovery record identifies the actual restore point and has evidence that a user can use the restored data.

    If it fails · เมื่อไม่ผ่าน

    If no historical manifest exists, record that limitation and verify known application records or document samples. Do not call the current source folder the historical truth.

Check the result before marking this passed

All three restored files match the pre-copy manifest, and the intentionally corrupted and missing-file cases are detected. The real drill additionally needs permission and application-use checks appropriate to its backup type.

Record the observed result and evidence location in the downloaded worksheet. Mark unresolved or untested conditions explicitly.

Recovery and cleanup

The script removes only its own TemporaryDirectory. For a real drill, obtain acceptance before removing the isolated restore; keep the original backup untouched and record any changes to recovery permissions.

Apply to actual work and known limits

Use this manifest approach to supplement, not replace, a supported backup product. Add encryption-key recovery, identity dependencies and measured application recovery time to the production runbook.

The included self-contained Python fixture was executed successfully in this Linux environment. External products and production infrastructure were not exercised.

Observed local fixture output · ผลรันตัวอย่าง

Create, restore and deliberately corrupt the copy

PASS: 3 files restored; corruption and missing-file checks detected
Observed restore seconds: 0.000788
Background, explanations and original notes

Prepare the exact environment

Save the program as restore_check.py and run python3 restore_check.py. It creates three folders inside a new temporary workspace and never accepts a user-supplied deletion path. The source data is synthetic.

Define the recovery boundary and file inventory

The backup boundary contains three small UTF-8 files. Record filenames and SHA-256 digests before copying. A file written after this manifest belongs to a later recovery point and must not silently enter the expected result.

Expected files: customers.txt, settings.txt, readme.txt
Expected recovery point: the source state immediately before copytree

Create, restore and deliberately corrupt the copy

Run the complete script. It verifies a successful restore, changes one restored file, removes another and confirms that each failure is detected. The assertions exercise real filesystem operations in a disposable directory.

from pathlib import Path
from tempfile import TemporaryDirectory
from hashlib import sha256
from time import perf_counter
import shutil

def manifest(root):
    records = {}
    for path in sorted(root.rglob("*")):
        if path.is_file():
            digest = sha256()
            with path.open("rb") as handle:
                for chunk in iter(lambda: handle.read(1024 * 1024), b""):
                    digest.update(chunk)
            records[str(path.relative_to(root))] = digest.hexdigest()
    return records

with TemporaryDirectory(prefix="sorlavit-restore-") as directory:
    workspace = Path(directory)
    source = workspace / "source"
    source.mkdir()
    for name, value in {"customers.txt": "customer-001\n", "settings.txt": "region=lab\n", "readme.txt": "synthetic backup\n"}.items():
        (source / name).write_text(value, encoding="utf-8")
    expected = manifest(source)
    backup = workspace / "backup"
    restored = workspace / "restored"
    shutil.copytree(source, backup)
    (source / "settings.txt").write_text("region=changed-after-backup\n", encoding="utf-8")
    started = perf_counter()
    shutil.copytree(backup, restored)
    assert manifest(restored) == expected
    duration = perf_counter() - started
    (restored / "settings.txt").write_text("corrupt\n", encoding="utf-8")
    assert manifest(restored) != expected
    shutil.copy2(backup / "settings.txt", restored / "settings.txt")
    (restored / "readme.txt").unlink()
    assert manifest(restored) != expected
    shutil.copy2(backup / "readme.txt", restored / "readme.txt")
    assert manifest(restored) == expected
    print("PASS: 3 files restored; corruption and missing-file checks detected")
    print("Observed restore seconds:", round(duration, 6))

Run the same verification against an approved backup copy

For a real drill, choose an existing recovery point and restore it to an isolated destination through the supported backup product. Compare the restored file manifest with the inventory recorded at that recovery point, open representative documents and check permissions. Record restore start, ready-for-use time, missing files and the person accepting the result. Measure application recovery separately from copying bytes.

Recovery point | expected files | restored files | hash mismatches | permission result | usable-at time

Acceptance check

All three restored files match the pre-copy manifest, and the intentionally corrupted and missing-file cases are detected. The real drill additionally needs permission and application-use checks appropriate to its backup type.

Recovery and cleanup

The script removes only its own TemporaryDirectory. For a real drill, obtain acceptance before removing the isolated restore; keep the original backup untouched and record any changes to recovery permissions.

Apply to actual work and known limits

Use this manifest approach to supplement, not replace, a supported backup product. Add encryption-key recovery, identity dependencies and measured application recovery time to the production runbook.

Share this article

Back to results