diff --git a/labs/GSP1313/HASHNODE.md b/labs/GSP1313/HASHNODE.md new file mode 100644 index 0000000..396d359 --- /dev/null +++ b/labs/GSP1313/HASHNODE.md @@ -0,0 +1,196 @@ +# Protect your Google Cloud NetApp Volumes data with backup - GSP1313 + +## Overview + +This lab introduces data protection for a managed NFS volume. You mount the pre-provisioned volume, create a regional backup vault, capture a manual backup, apply a daily/weekly/monthly backup schedule, and restore the backup into a second volume. This guide follows the five official tasks and paraphrases their instructions independently. + +### What you'll do + +- Mount the existing NetApp NFSv3 volume on vm1 and verify the share. +- Create vault1 in the same region as volume1. +- Write sample files and create backup1. +- Create policy1 with 30 daily, 8 weekly and 12 monthly retained backups and attach it to volume1. +- Restore backup1 as restore-from-volume1 in pool1. + +## Setup and requirements + +### Before you click the Start Lab button + +Open the [official GSP1313 lab](https://www.skills.google/focuses/124383?parent=catalog) in a private browser. Use only the temporary Google Skills credentials. Do not copy usernames, passwords, or project IDs into public scripts. The timed lab provisions volume1, pool1 and VM vm1. Do not replace these resources or choose an unrelated region. + +### Activate Cloud Shell + +Activate Cloud Shell in the lab's console. Confirm the temporary account and project, then locate volume1. Derive the region from the volume's resource name and vm1's zone from the existing VM rather than hardcoding either location. + +```bash +gcloud auth list +gcloud config get-value project +export PROJECT_ID="$(gcloud config get-value project)" +gcloud netapp volumes list +export VOLUME_PATH="$(gcloud netapp volumes list --format=json | jq -r '.[] | select(.name | endswith("/volumes/volume1")) | .name' | head -n1)" +export LOCATION="$(awk -F/ '{print $(NF-2)}' <<< "$VOLUME_PATH")" +export ZONE="$(gcloud compute instances list --filter='name=vm1' --format='value(zone)' | head -n1 | awk -F/ '{print $NF}')" +printf 'NetApp region: %s | VM zone: %s\n' "$LOCATION" "$ZONE" +``` + +The official lab includes screenshots of the NetApp UI and Cloud Shell. [View the original figures at Google Skills](https://www.skills.google/focuses/124383?parent=catalog). No original images are embedded here because permission to reuse them on Hashnode has not been established. + +## Task 1. Mount the volume + +In Google Cloud console, open NetApp Volumes → Volumes, locate volume1, and choose Mount Instructions. Open a separate Compute Engine tab and SSH into vm1. The mount IP is unique to the lab, so read it from volume1's metadata rather than copying another person's IP address. + +```bash +gcloud netapp volumes describe volume1 --location="$LOCATION" --format='value(mountOptions.instructions)' +gcloud compute ssh vm1 --zone="$ZONE" +``` + +Inside vm1, install the NFS client, create the share directory, and use the NFSv3 mount command from the instructions panel. Replace the placeholder only with the export IP from your own volume. + +```bash +sudo apt-get install -y nfs-common +sudo mkdir -p /share1 +sudo mount -t nfs -o rw,hard,rsize=65536,wsize=65536,vers=3,tcp :/share1 /share1 +df -h | grep share1 +exit +``` + +The Bash solution retrieves mountOptions.exportFull automatically, validates its format and mounts only if /share1 is not already mounted. + +### Test completed task + +Click **Check my progress** for **Mount the volume** (20 points). + +## Task 2. Create a backup vault + +In NetApp Volumes → Data protection → Backup vaults, choose Create. Name the vault vault1 and select the region of volume1. The equivalent CLI operation is: + +```bash +gcloud netapp backup-vaults create vault1 --location="$LOCATION" +gcloud netapp backup-vaults describe vault1 --location="$LOCATION" +``` + +### Test completed task + +Click **Check my progress** for **Create a backup vault** (20 points). + +## Task 3. Create a manual backup + +SSH into vm1 and add two folders and two sample text files to the mounted volume. These strings are exercise content, not credentials. Confirm the files are visible, then return to Cloud Shell. + +```bash +gcloud compute ssh vm1 --zone="$ZONE" +``` + +```bash +sudo mkdir -p /share1/folder1 /share1/folder2 +printf 'important\n' | sudo tee /share1/file1.txt +printf 'top secret\n' | sudo tee /share1/file2.txt +sudo ls -l /share1 +exit +``` + +In the console, open volume1 → Backups → Create backup. Set the name to backup1, source to the volume's current state and destination to vault1. Alternatively: + +```bash +gcloud netapp backup-vaults backups create backup1 \ + --location="$LOCATION" --backup-vault=vault1 --source-volume=volume1 +gcloud netapp backup-vaults backups describe backup1 \ + --location="$LOCATION" --backup-vault=vault1 +``` + +Wait until the backup is READY. The first backup copies the current used data; subsequent backups can be incremental. The published grader lists no separate checkpoint for the manual backup task. + +## Task 4. Set a backup schedule + +### Create a backup policy + +Navigate to NetApp Volumes → Policies → Backup policies → Create. Use the policy name policy1 and the same region as volume1. Set the retention counts below. + +| Retention period | Backups to keep | +|---|---:| +| Daily | 30 | +| Weekly | 8 | +| Monthly | 12 | + +```bash +gcloud netapp backup-policies create policy1 \ + --location="$LOCATION" --enabled=true \ + --daily-backup-limit=30 --weekly-backup-limit=8 --monthly-backup-limit=12 +gcloud netapp backup-policies describe policy1 --location="$LOCATION" +``` + +### Test completed task + +Click **Check my progress** for **Create a backup policy** (20 points). + +### Attach the backup policy to the volume + +Open volume1 → Backups → Manage Backup Policy, enable scheduled backups, select policy1 and vault1, and save. The CLI equivalent uses the complete regional resource names: + +```bash +export VAULT_PATH="projects/$PROJECT_ID/locations/$LOCATION/backupVaults/vault1" +export POLICY_PATH="projects/$PROJECT_ID/locations/$LOCATION/backupPolicies/policy1" +gcloud netapp volumes update volume1 --location="$LOCATION" \ + --backup-config="backup-policies=$POLICY_PATH,backup-vault=$VAULT_PATH,enable-scheduled-backups=true" +gcloud netapp volumes describe volume1 --location="$LOCATION" --format='yaml(backupConfig)' +``` + +### Test completed task + +Click **Check my progress** for **Attach a backup schedule to a volume** (20 points). + +## Task 5. Restore a backup + +In NetApp Volumes → Volumes → volume1 → Backups, find backup1. Wait for it to finish creating, open its actions menu, and choose Create new volume from backup. Use the following fields: + +| Field | Value | +|---|---| +| New volume name | restore-from-volume1 | +| Storage pool | pool1 | +| Share name | share1-restored | +| Source backup | backup1 in vault1 | + +Read the source volume's capacity from its metadata, then create the restored NFSv3 volume with the same capacity and a new share name. The restore can take several minutes depending on the volume size. + +```bash +export CAPACITY="$(gcloud netapp volumes describe volume1 --location="$LOCATION" --format='value(capacityGib)')" +gcloud netapp volumes create restore-from-volume1 \ + --location="$LOCATION" --storage-pool=pool1 --capacity="$CAPACITY" \ + --protocols=nfsv3 --share-name=share1-restored \ + --source-backup=backup1 --backup-vault=vault1 +gcloud netapp volumes describe restore-from-volume1 --location="$LOCATION" +``` + +### Test completed task + +Click **Check my progress** for **Restore a volume from a backup** (20 points). No grader PASS is claimed without running an authorized lab. + +--- + +## Solution of Lab + +### Quick + +These two commands point to main. **They work only after the Draft PR has been reviewed and merged**; an unmerged branch does not make the main-branch URL available. + +```bash +curl -LO https://raw.githubusercontent.com/ePlus-DEV/storage/refs/heads/main/labs/GSP1313/lab.sh +source lab.sh +``` + +The script discovers the temporary project, NetApp region, NFS export and VM zone; performs the mount, backup, policy and restore tasks with safe existing-resource checks; and waits a bounded period for backup readiness. It supports terminal ANSI color, FORCE_COLOR=1 for tee and NO_COLOR override. Do not infer grader success from CI. + +### Manual + +Chưa tìm thấy video YouTube hướng dẫn thủ công đã xác minh cho lab này. + +Use the manual steps for Tasks 1–5 above. A video matching the title exists publicly, but its contents have not been verified as a genuine manual walkthrough, so it is not linked here. + +### Sources and verification + +- [Google Skills — GSP1313 official lab](https://www.skills.google/focuses/124383?parent=catalog) +- [NetApp NFS client mount documentation](https://cloud.google.com/netapp/volumes/docs/connect-clients/connect-nfs-clients) +- [Backup vault management documentation](https://cloud.google.com/netapp/volumes/docs/protect-data/manage-backup-vault) +- [Restore a volume from a backup](https://cloud.google.com/netapp/volumes/docs/protect-data/create-volume-from-backup) +- The original lab text and figures are copyrighted by Google LLC; this guide is independently paraphrased. Script: Copyright (c) 2026 ePlus.DEV | Unlicense. +- **static validated only; runtime/grader unverified**. CI cannot verify Google Skills grading. diff --git a/labs/GSP1313/lab.sh b/labs/GSP1313/lab.sh new file mode 100644 index 0000000..b5aac23 --- /dev/null +++ b/labs/GSP1313/lab.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Copyright (c) 2026 ePlus.DEV | Unlicense +# GSP1313 — Protect your Google Cloud NetApp Volumes data with backup +# static validated only; runtime/grader unverified +set -Eeuo pipefail +if [[ -n "${NO_COLOR:-}" ]]; then C='' G='' Y='' R=''; +elif [[ -t 1 || "${FORCE_COLOR:-0}" == 1 ]]; then + C=$'\033[36m'; G=$'\033[32m'; Y=$'\033[33m'; R=$'\033[0m' +else C='' G='' Y='' R=''; fi +info(){ printf '%s[INFO]%s %s\n' "$C" "$R" "$*"; } +warn(){ printf '%s[WARN]%s %s\n' "$Y" "$R" "$*" >&2; } +die(){ printf '[ERROR] %s\n' "$*" >&2; exit 1; } +printf '%sePlus.DEV – Starting Execution%s\n' "$C" "$R" +printf 'Copyright (c) 2026 ePlus.DEV | Unlicense\n' +for c in gcloud jq; do command -v "$c" >/dev/null || die "Missing $c"; done +PROJECT_ID="${PROJECT_ID:-$(gcloud config get-value project 2>/dev/null)}" +[[ -n "$PROJECT_ID" && "$PROJECT_ID" != '(unset)' ]] || die 'Use the temporary Google Skills lab project.' +VOLUME_PATH="$(gcloud netapp volumes list --project="$PROJECT_ID" --format=json | jq -r '.[] | select(.name | endswith("/volumes/volume1")) | .name' | head -n1)" +[[ "$VOLUME_PATH" == */volumes/volume1 ]] || die 'Pre-provisioned NetApp volume1 not found.' +LOCATION="${LOCATION:-$(awk -F/ '{print $(NF-2)}' <<< "$VOLUME_PATH")}" +[[ "$LOCATION" =~ ^[a-z]+-[a-z0-9]+[0-9]$ ]] || die 'Cannot discover NetApp region.' +VOLUME_JSON="$(gcloud netapp volumes describe volume1 --project="$PROJECT_ID" --location="$LOCATION" --format=json)" +POOL="$(jq -r '.storagePool | split("/")[-1]' <<< "$VOLUME_JSON")" +[[ "$POOL" == pool1 ]] || die "Expected lab storage pool pool1, got $POOL." +CAPACITY="$(jq -r '.capacityGib' <<< "$VOLUME_JSON")" +[[ "$CAPACITY" =~ ^[0-9]+$ ]] || die 'Missing source volume capacity.' +EXPORT_FULL="$(jq -r '[.mountOptions[]? | select(.protocol == "NFSV3") | .exportFull] | first // empty' <<< "$VOLUME_JSON")" +[[ "$EXPORT_FULL" =~ ^[0-9.]+:/[A-Za-z0-9/_-]+$ ]] || die 'Missing safe NFSv3 export path; review Mount Instructions.' +ZONE="${ZONE:-$(gcloud compute instances list --project="$PROJECT_ID" --filter='name=vm1' --format='value(zone)' | head -n1 | awk -F/ '{print $NF}')}" +[[ "$ZONE" =~ ^[a-z]+-[a-z0-9]+[0-9]-[a-z]$ ]] || die 'Cannot discover vm1 zone.' +info "Project=$PROJECT_ID NetApp region=$LOCATION VM zone=$ZONE" +retry(){ local max="$1" delay="$2" i; shift 2; for ((i=1;i<=max;i++)); do + if "$@"; then return 0; fi + if ((i/dev/null 2>&1; } +backup_exists(){ gcloud netapp backup-vaults backups describe backup1 --backup-vault=vault1 --project="$PROJECT_ID" --location="$LOCATION" >/dev/null 2>&1; } +policy_exists(){ gcloud netapp backup-policies describe policy1 --project="$PROJECT_ID" --location="$LOCATION" >/dev/null 2>&1; } +restore_exists(){ gcloud netapp volumes describe restore-from-volume1 --project="$PROJECT_ID" --location="$LOCATION" >/dev/null 2>&1; } +backup_ready(){ [[ "$(gcloud netapp backup-vaults backups describe backup1 --backup-vault=vault1 --project="$PROJECT_ID" --location="$LOCATION" --format='value(state)' 2>/dev/null)" == READY ]]; } + +info 'Task 1: mount the pre-provisioned NetApp NFSv3 volume on vm1' +# The export is read from NetApp API, not guessed. The command is rerun-safe. +gcloud compute ssh vm1 --project="$PROJECT_ID" --zone="$ZONE" --quiet --command="sudo apt-get install -y nfs-common && sudo mkdir -p /share1 && (mountpoint -q /share1 || sudo mount -t nfs -o rw,hard,rsize=65536,wsize=65536,vers=3,tcp '$EXPORT_FULL' /share1) && df -h | grep share1" || die 'NFS mount failed; inspect the lab mount instructions.' +info 'Task 1 checkpoint: Mount the volume' + +info 'Task 2: create a regional backup vault' +if ! vault_exists; then + gcloud netapp backup-vaults create vault1 --project="$PROJECT_ID" --location="$LOCATION" --quiet +fi +retry 10 10 vault_exists || die 'Backup vault not ready after bounded retries.' +info 'Task 2 checkpoint: Create a backup vault' + +info 'Task 3: write test data and create a manual backup' +gcloud compute ssh vm1 --project="$PROJECT_ID" --zone="$ZONE" --quiet --command="sudo mkdir -p /share1/folder1 /share1/folder2 && printf 'important\n' | sudo tee /share1/file1.txt >/dev/null && printf 'top secret\n' | sudo tee /share1/file2.txt >/dev/null && sudo ls /share1" || die 'Could not populate mounted volume.' +if ! backup_exists; then + gcloud netapp backup-vaults backups create backup1 --project="$PROJECT_ID" --location="$LOCATION" --backup-vault=vault1 --source-volume=volume1 --quiet +fi +retry 20 30 backup_ready || die 'Backup1 is not READY after bounded retries; inspect the backup status before proceeding.' +info 'Task 3 checkpoint: Create a manual backup' + +info 'Task 4: create and attach a scheduled backup policy' +if ! policy_exists; then + gcloud netapp backup-policies create policy1 --project="$PROJECT_ID" --location="$LOCATION" --enabled=true --daily-backup-limit=30 --weekly-backup-limit=8 --monthly-backup-limit=12 --quiet +fi +VAULT_PATH="projects/$PROJECT_ID/locations/$LOCATION/backupVaults/vault1" +POLICY_PATH="projects/$PROJECT_ID/locations/$LOCATION/backupPolicies/policy1" +gcloud netapp volumes update volume1 --project="$PROJECT_ID" --location="$LOCATION" --backup-config="backup-policies=$POLICY_PATH,backup-vault=$VAULT_PATH,enable-scheduled-backups=true" --quiet +info 'Task 4 checkpoints: Create a backup policy; Attach a policy to the volume' + +info 'Task 5: restore backup1 to a new volume' +if ! restore_exists; then + gcloud netapp volumes create restore-from-volume1 --project="$PROJECT_ID" --location="$LOCATION" --storage-pool=pool1 --capacity="$CAPACITY" --protocols=nfsv3 --share-name=share1-restored --source-backup=backup1 --backup-vault=vault1 --quiet +fi +gcloud netapp volumes describe restore-from-volume1 --project="$PROJECT_ID" --location="$LOCATION" --format='value(state)' +info 'Task 5 checkpoint: Restore a volume from a backup' +printf '%s[OK]%s Finished. static validated only; runtime/grader unverified\n' "$G" "$R" \ No newline at end of file