Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Application-Consistent Snapshots for Oracle on GCNV (ONTAP mode) — Setup & Runbook

Execution guide to snapshot, verify, and restore an Oracle single-instance database on Google Cloud NetApp Volumes (GCNV) in ONTAP mode, using NetApp Consistency Groups. Standalone scripts live in scripts/ — only bash, curl, jq, gcloud, and SQL*Plus are required. Use this sample scripts to test in non-production environment first for adoption.

  • Scope: Oracle single-instance (CDB/PDB or non-CDB) on ASM (+DATA/+FRA) over iSCSI or NVMe/TCP, Linux hosts.
  • Out of scope: RAC / Data Guard failover orchestration, GCNV DEFAULT-mode pools (CGs need ONTAP mode), RMAN/streaming backups.

1. Prerequisites

Database

  • ARCHIVELOG mode enabled — SELECT log_mode FROM v$database; → ARCHIVELOG.
  • TR-4700 layout: datafiles + tempfiles only on +DATA; control files, online redo, archive, flashback, SPFILE on +FRA. Both disk groups CG-backed. (Existing non-compliant DB? See Appendix A.)
  • SYSDBA via OS authentication on the host.

Host / OS

  • bash, curl, jq installed.
  • gcloud installed and ADC configured (gcloud auth application-default login).
  • SQL*Plus on PATH for the SID (resolved from /etc/oratab).

GCNV / ONTAP

  • Flex pool in ONTAP mode.
  • You know project, location (pool zone), pool, the SVM, and the volume names for +DATA and +FRA.

Run everything as the oracle software owner

Copy the bundle to a dir oracle owns (e.g. /opt/oracle/toolkit, chown -R oracle:oinstall). Copy whole files (scp/rsync) — do not paste-edit on the host. One identity must satisfy all three privilege levels:

Operation Needs Who
Snapshot (30/32/35) SYSDBA + ONTAP token Oracle owner / dba-group user with gcloud token
Restore (50) / proof (91) Grid/ASM admin (crsctl/srvctl, OLR, ADR) + SYSDBA + ONTAP token Grid/Oracle software owner only
Verify (20/40) ONTAP token only any user with a valid token

A dba-group user can run SQL as SYSDBA but cannot manage Oracle Restart — a restore run as that user fails at crsctl stop has (PROCL-00042/DIA-49802) after shutdown abort, leaving a half-reverted DB. 50/91 call assert_storage_privileges and abort before any change. Always run 50/91 as oracle.

Sanity check (as oracle):

sudo -iu oracle
gcloud auth print-access-token >/dev/null && echo "token OK"               # ONTAP
sqlplus -s / as sysdba <<< 'select open_mode, log_mode from v$database;'    # SYSDBA
/u01/app/26.0.0/grid/bin/crsctl check has                                   # Grid/ASM (no PROCL-00042)

2. Architecture (quick reference)

Volume → ASM → Consistency Group mapping

Oracle component ASM disk group ONTAP volume (example) Class In CG?
Datafiles + tempfiles ONLY +DATA orasi_primary_data1 DATA ✅
Control files, online/archived redo, flashback, SPFILE +FRA orasi_primary_fra1 LOG ✅
Oracle binaries (/u01) n/a (XFS) u01 — ❌

Golden rule (TR-4700 isolation): datafiles live alone on the DATA volume; control/redo/archive/SPFILE on the LOG volume. This is what makes a datafile-only SnapRestore + roll-forward possible. The CG spans both volumes for whole-DB atomic snapshots. The scripts enforce this and abort on violation.

Snapshot models & matching restore scopes

The snapshot model you choose dictates the restore scope you can use later.

Model Script What it captures Restore scope(s) Use when
Whole-CG (app-consistent) 30 one atomic CG snapshot (DATA + LOG) whole full point-in-time: gold image, clone, DR
Volume-split (app-consistent) 32 separate per-volume DATA & LOG snapshots datafiles (roll-forward) · split (point-in-time) datafile corruption / logical error with intact logs
Crash-consistent 35 one CG snapshot, no Oracle quiesce whole non-prod clones / DR drills
50-restore-from-snapshot.sh  [name|latest]  [scope]
Scope Reverts Recovery Data loss From
whole CG (DATA + LOG) media recovery to snapshot point back to snapshot 30/35
datafiles DATA volume only roll forward on current control/redo/archive ~0 (normal conditions *) 32
split DATA + LOG volume snaps media recovery to snapshot point back to snapshot 32

* RPO under normal conditions is effectively zero. datafiles reverts only the datafile volume and rolls forward using the current archive + online redo (still live on the intact LOG volume) to the last commit — no committed transaction lost, independent of snapshot frequency. Cadence only bounds RPO in the degraded case where the logs themselves are lost (then you fall back to the latest snapshot).

Application-consistent vs crash-consistent: app-consistent (BEGIN BACKUP → snapshot → END BACKUP) requires ARCHIVELOG and is the default for any production-SLA image; crash-consistent skips the quiesce and is for non-prod/drills.

Non-ASM (iSCSI/NVMe + filesystem): set ORACLE_STORAGE=fs and list mount points in ORACLE_DATA_PATHS / ORACLE_LOG_PATHS. Restore unmounts → SnapRestores → fsck → remounts → recovers. Block + local FS only (no NFS).

Access model (no LIF, no passwords)

Every ONTAP REST call is proxied through the Google control plane and authenticated with ADC — no ONTAP hostname/user/password:

https://netapp.googleapis.com/v1/projects/PROJECT/locations/LOCATION/storagePools/POOL/ontap/api/<PATH>
Authorization: Bearer $(gcloud auth print-access-token)

Proxy conventions used by the scripts: field selection uses ontap_fields= (not fields=); request/response bodies are wrapped in { "body": { ... } }, so list records live under .body.records.


3. Workflow at a glance

 one-time  ┌──────────────────────────────────────────────────────────┐
           │ 00-env.sh        set GCP/SVM/CG identifiers (edit once)  │
           │ 10-ensure-cg.sh  create the Consistency Group (DATA+FRA) │
           └──────────────────────────────────────────────────────────┘
                                     │
 backup    ┌──────────────────────────────────────────────────────────┐
 CHOOSE    │ 30 whole-CG (atomic)   │ 32 volume-split   │ 35 crash    │
 A MODEL   └──────────────────────────────────────────────────────────┘
                                     │
           ┌──────────────────────────────────────────────────────────┐
 verify    │ 20-verify-cg.sh   /   40-list-snapshots.sh               │
           └──────────────────────────────────────────────────────────┘
                                     │
 recover   ┌──────────────────────────────────────────────────────────┐
 SCOPE =   │ 50-restore-from-snapshot.sh [name|latest] [scope]        │
 MODEL     │   30/35 → whole      32 → datafiles | split              │
           └──────────────────────────────────────────────────────────┘

4. Step-by-step execution

Step 0 — Configure (00-env.sh)

Edit the identifiers at the top of scripts/00-env.sh once; every other script sources it. This is the only file you normally edit.

# GCNV (ONTAP-mode) target
export GCNV_PROJECT_ID="..."        # GCP project owning the pool
export GCNV_LOCATION="us-west1-a"   # storage pool zone
export GCNV_STORAGE_POOL="..."      # Flex pool (ONTAP mode)
export ONTAP_SVM="..."              # SVM that owns the volumes

# Consistency Group + volume mapping (datafiles isolated on DATA)
export ONTAP_CG_NAME="cg_orcl_single"
ONTAP_DATA_VOLUMES=( "orasi_primary_data1" )   # datafiles ONLY
ONTAP_LOG_VOLUMES=(  "orasi_primary_fra1"  )   # control/redo/arch/spfile

# Oracle (used by quiesce / recover)
export ORACLE_SID="ORCL"
export DB_UNIQUE_NAME="ORCL"
export GRID_HOME="/u01/app/26.0.0/grid"
export ASM_DISKGROUPS="DATA FRA"

Then confirm connectivity:

gcloud auth application-default login
chmod +x ./*.sh
source ./00-env.sh
ontap_get "/cluster?ontap_fields=name,version" | jq .     # must return cluster JSON

Step 1 — Create the Consistency Group (one-time)

Idempotent — a no-op once the CG exists.

./10-ensure-consistency-group.sh

Expect: Consistency group 'cg_orcl_single' is ready (uuid=…) (or already exists).

Step 2 — Verify the CG

Read-only health check (membership, SVM, latest snapshot). Add VERIFY_LAYOUT=true to also assert TR-4700 compliance.

./20-verify-consistency-group.sh
VERIFY_LAYOUT=true ./20-verify-consistency-group.sh   # also checks datafile isolation

Expect: Membership check : OK and (with the flag) Layout compliant: OK.

Step 3 — Take a snapshot (choose your model)

Pick the model that matches the recovery you want (see §2). The restore scope must match the snapshot you took — a 30 snapshot restores whole only; only a 32 snapshot unlocks datafiles/split.

Option A — Whole-CG (30): one atomic snapshot of DATA + FRA. trap-protected so the DB is never left in backup mode.

SNAP_ENV=prod SNAP_DB_NAME=ORCL SNAP_CHANGE_ID=chg1234 ./30-app-consistent-snapshot.sh
# → restore later with: ./50-restore-from-snapshot.sh latest whole

Sequence: BEGIN BACKUP → CG snapshot (consistency_type=application) → END BACKUP → ARCHIVE LOG CURRENT + capture SCN.

Option B — Volume-split (32): two per-volume snapshots for the datafile-only roll-forward (zero RPO under normal conditions). Requires the TR-4700 layout.

SNAP_ENV=prod SNAP_DB_NAME=ORCL SNAP_CHANGE_ID=chg1234 ./32-volume-split-snapshot.sh
# → restore later with: ./50-restore-from-snapshot.sh latest datafiles   (roll-forward, ~0 RPO)
#                or:    ./50-restore-from-snapshot.sh latest split        (point-in-time)

Sequence (END BACKUP precedes ARCHIVE LOG CURRENT, so the LOG snapshot is independently recoverable):

1. ALTER DATABASE BEGIN BACKUP        4. ALTER SYSTEM ARCHIVE LOG CURRENT
2. snapshot DATA volume(s)            5. BACKUP CONTROLFILE (binary+trace) → LOG volume
3. ALTER DATABASE END BACKUP          6. snapshot LOG volume(s)

Produces one <ENV>_<DB>_split_<timestamp>_<CHANGE_ID> name shared by both volumes (shown per-volume in 40, not as a CG snapshot).

Option C — Crash-consistent (35): non-prod / drills, no quiesce.

SNAP_ENV=test ./35-crash-consistent-snapshot.sh
# → restore later with: ./50-restore-from-snapshot.sh latest whole

Naming convention: <ENV>_<DB>_<type>_<YYYYMMDD_HHMMSS>_<CHANGE_ID> (e.g. prod_ORCL_appcons_20260619_142530_chg1234) — self-describing and audit-friendly. Keep the backup window to seconds (only the snapshot REST call sits between BEGIN/END BACKUP).

Step 4 — List & confirm

./40-list-snapshots.sh

Shows CG (whole) snapshots and per-volume snapshots. Confirm DB state any time:

SELECT open_mode, log_mode FROM v$database;          -- READ WRITE, ARCHIVELOG
SELECT COUNT(*) FROM v$backup WHERE status='ACTIVE';  -- 0 (never left in backup mode)

Step 5 — Restore & recover

Destructive — test in non-production first. Run as oracle. Match the scope to the snapshot (§2).

# Whole point-in-time (from a 30/35 snapshot):
./50-restore-from-snapshot.sh latest whole
./50-restore-from-snapshot.sh prod_ORCL_appcons_20260619_142530_chg1234 whole

# Datafile-only roll-forward (~0 RPO) from a 32 snapshot, with RMAN block check:
VALIDATE=true ./50-restore-from-snapshot.sh latest datafiles

# Volume-level point-in-time (both volumes) from a 32 snapshot:
./50-restore-from-snapshot.sh latest split

What it does: pre-flight guard (abort if a DB file is outside the CG/layout) → quiesce (shutdown abort → srvctl stop → crsctl stop has -f) → revert (CG restore_to, or volume SnapRestore) → restart storage (crsctl start has, wait for disk groups) → recover & open (MOUNT → END BACKUP → RECOVER AUTOMATIC DATABASE → OPEN + PDBs) → validate (v$recover_file=0, no backup-mode files, and with VALIDATE=true zero corrupt blocks via RMAN).

Success line:

SUCCESS: database restored (scope=…) from '<snapshot>', recovered, and OPEN.

Expected during a datafiles roll-forward: because only the DATA volume is reverted, STARTUP MOUNT/END BACKUP report ORA-01208/ORA-01235 for the reverted datafiles. This is normal — RECOVER AUTOMATIC DATABASE rolls them forward to the current SCN and opens (no resetlogs).

On SCNs: the printed REFERENCE_SCN is for the audit trail only; the global SCN always advances past the snapshot during recovery, so a pre/post comparison is meaningless. The deterministic gates are v$recover_file=0, no backup-mode files, and (with VALIDATE=true) zero corrupt blocks.


5. Validate the datafile-only RPO claim (91) — test only

⚠️ Validation / test harness — NOT an operational step. Production recovery uses 50. Run 91 once on a throwaway/test DB to prove the datafile-only roll-forward works in your environment (re-run after a patch/upgrade/layout change). It must never run against production, and it adds no extra DB bounce — internally it just calls 50 … datafiles and wraps it with assertions.

./91-prove-datafile-rpo.sh --yes        # VALIDATE=true by default

It seeds a baseline row, takes a 32 snapshot, commits post-snapshot "RPO-window" rows, runs a datafiles restore, then asserts and ends in OVERALL: PASS:

  • [RPO] every post-snapshot committed row survived (rolled forward);
  • [CONSISTENCY] DB OPEN, v$recover_file=0, zero corrupt blocks (RMAN);
  • [SELECTIVE] the LOG volume(s) were not reverted.

Cleanup afterward: DROP TABLE system.rpo_proof PURGE;


Appendix A — Layout relocation (existing databases)

The split model requires datafiles isolated on +DATA. A default DBCA install multiplexes control/redo across +DATA++FRA and puts the SPFILE on +DATA — non-compliant. New databases built by this toolkit are already compliant.

Automated (recommended) — idempotent; moves redo online, control files + SPFILE in one srvctl bounce (no OPEN RESETLOGS), takes a safety CG snapshot, asserts compliance:

ansible-playbook -i inventories/single playbooks/19_relocate_db_files_to_fra.yml --check        # dry run
ansible-playbook -i inventories/single playbooks/19_relocate_db_files_to_fra.yml -e relocate_confirm=true

Manual equivalent (online where possible):

-- 1) Add a +FRA redo member per group, switch/checkpoint until INACTIVE, drop the +DATA member.
ALTER DATABASE ADD LOGFILE MEMBER '+FRA' TO GROUP 1;            -- repeat per group
ALTER SYSTEM SWITCH LOGFILE;  ALTER SYSTEM CHECKPOINT;
ALTER DATABASE DROP LOGFILE MEMBER '+DATA/<db>/onlinelog/...';
-- 2) Control file → +FRA (needs a bounce): set control_files to +FRA, copy via ASM, restart.
ALTER SYSTEM SET control_files='+FRA/<db>/controlfile/current.ctl' SCOPE=SPFILE;
-- 3) SPFILE → +FRA and re-point Oracle Restart:
CREATE SPFILE='+FRA/<db_unique>/spfile<SID>.ora' FROM SPFILE;
!srvctl modify database -d <db_unique> -spfile +FRA/<db_unique>/spfile<SID>.ora

Verify any time: VERIFY_LAYOUT=true ./20-verify-consistency-group.sh. Snapshot/restore scripts run this automatically and abort on violation (override PREFLIGHT_SKIP=true at your own risk).


Appendix B — Troubleshooting & pitfalls

Symptom / pitfall Cause / fix
ORA-01031/ORA-01017 at SYSDBA Not the Oracle owner / not in dba group. Run as oracle.
PROCL-00042 / DIA-49802 on restore Restore run as a non-Grid user. Run 50/91 as the Grid/Oracle owner.
ORA-01208/ORA-01235 during datafiles restore Expected — recovery rolls the reverted datafiles forward.
ORA-00204/stale ASM after revert Storage reverted under a live ASM. The script stops HAS first — don't skip it.
DB file outside +DATA/+FRA Pre-flight aborts. Relocate (Appendix A) so all DB state is CG-backed.
Snapshots at slightly different times Always go through the CG (30) or same-named volume set (32) — never ad-hoc per-volume.
Interactive auth prompt in scheduled runs Pre-stage ADC via a service account with the NetApp Volumes admin role.
Not in ARCHIVELOG Required for app-consistent recovery. Enable before relying on these snapshots.

Appendix C — Script reference

Script Purpose
00-env.sh Shared config + ONTAP REST / SQL helpers (edit once)
10-ensure-consistency-group.sh Create the CG over +DATA++FRA (idempotent)
20-verify-consistency-group.sh Verify CG membership + latest snapshot (VERIFY_LAYOUT=true adds layout check)
30-app-consistent-snapshot.sh Whole-CG application-consistent snapshot
32-volume-split-snapshot.sh Volume-split 6-step snapshot (DATA + LOG separately)
35-crash-consistent-snapshot.sh Crash-consistent snapshot (non-prod / drills)
40-list-snapshots.sh List CG and per-volume snapshots
50-restore-from-snapshot.sh Restore + recover + validate (whole/datafiles/split); VALIDATE=true adds RMAN block check
91-prove-datafile-rpo.sh Test/validation only — proof harness for datafile-only RPO (PASS/FAIL). Production recovery uses 50.

The fine print

As with any automation that interacts with database and storage infrastructure, validate these scripts in a non-production environment and ensure they align with your organization's backup, recovery, and operational requirements before production use. This product is licensed under the Apache 2 license. This is not an officially supported NetApp project

About

Application-Consistent Snapshots for Oracle on GCNV (ONTAP mode) — Runbook

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages