From b4712995892db32549be67218e9ddf116001440b Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 19 Aug 2026 13:42:52 -0500 Subject: [PATCH 1/3] Updated the paths for the terraform validation action. --- .github/workflows/fsxn_as_pvc_terraform.yaml | 50 +++++++++++++++++++ .../fsxn_rotate_secret_terraform.yml | 50 +++++++++++++++++++ .../Terraform/deploy-fsx-ontap/module/main.tf | 8 +-- 3 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/fsxn_as_pvc_terraform.yaml create mode 100644 .github/workflows/fsxn_rotate_secret_terraform.yml diff --git a/.github/workflows/fsxn_as_pvc_terraform.yaml b/.github/workflows/fsxn_as_pvc_terraform.yaml new file mode 100644 index 00000000..bcd30874 --- /dev/null +++ b/.github/workflows/fsxn_as_pvc_terraform.yaml @@ -0,0 +1,50 @@ +--- +# Copyright (c) NetApp, Inc. +# SPDX-License-Identifier: Apache-2.0 + +name: "Code Quality: Terraform Validation for EKS/FSxN-as-PVC-for-EKS/terraform" + +permissions: + contents: read + +on: + pull_request: + paths: + - 'EKS/FSxN-as-PVC-for-EKS/terraform/**' + push: + paths: + - 'EKS/FSxN-as-PVC-for-EKS/terraform/**' + branches: + - main + +jobs: + terraform: + name: Terraform + runs-on: ubuntu-latest + defaults: + run: + working-directory: 'EKS/FSxN-as-PVC-for-EKS/terraform' + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: Checkout pull request + uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: Set up Terraform + uses: hashicorp/setup-terraform@ed3a0531877aca392eb870f440d9ae7aba83a6bd # v1.4.0 + with: + terraform_wrapper: false + terraform_version: 1.12.1 + + - name: Initialize Terraform + run: terraform init + + - name: Validate Terraform configuration + run: terraform validate diff --git a/.github/workflows/fsxn_rotate_secret_terraform.yml b/.github/workflows/fsxn_rotate_secret_terraform.yml new file mode 100644 index 00000000..99a53294 --- /dev/null +++ b/.github/workflows/fsxn_rotate_secret_terraform.yml @@ -0,0 +1,50 @@ +--- +# Copyright (c) NetApp, Inc. +# SPDX-License-Identifier: Apache-2.0 + +name: "Code Quality: Terraform Validation for Management-Utilities/fsxn-rotate-secret/terraform" + +permissions: + contents: read + +on: + pull_request: + paths: + - 'Management-Utilities/fsxn-rotate-secret/terraform/**' + push: + paths: + - 'Management-Utilities/fsxn-rotate-secret/terraform/**' + branches: + - main + +jobs: + terraform: + name: Terraform + runs-on: ubuntu-latest + defaults: + run: + working-directory: 'Management-Utilities/fsxn-rotate-secret/terraform' + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: Checkout pull request + uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: Set up Terraform + uses: hashicorp/setup-terraform@ed3a0531877aca392eb870f440d9ae7aba83a6bd # v1.4.0 + with: + terraform_wrapper: false + terraform_version: 1.12.1 + + - name: Initialize Terraform + run: terraform init + + - name: Validate Terraform configuration + run: terraform validate diff --git a/Infrastructure_as_Code/Terraform/deploy-fsx-ontap/module/main.tf b/Infrastructure_as_Code/Terraform/deploy-fsx-ontap/module/main.tf index 3241062f..62164b38 100644 --- a/Infrastructure_as_Code/Terraform/deploy-fsx-ontap/module/main.tf +++ b/Infrastructure_as_Code/Terraform/deploy-fsx-ontap/module/main.tf @@ -54,8 +54,8 @@ data "aws_region" "current" {} # associated with it that will set the initial password. module "fsxn_rotate_secret" { source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" - fsx_region = data.aws_region.current.name - secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.name + fsx_region = data.aws_region.current.region + secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.region aws_account_id = var.aws_account_id secret_name_prefix = var.secret_name_prefix fsx_id = aws_fsx_ontap_file_system.terraform-fsxn.id @@ -72,8 +72,8 @@ resource "aws_fsx_ontap_storage_virtual_machine" "mysvm" { # associated with it that will set the initial password. module "svm_rotate_secret" { source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" - fsx_region = data.aws_region.current.name - secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.name + fsx_region = data.aws_region.current.region + secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.region aws_account_id = var.aws_account_id secret_name_prefix = var.secret_name_prefix svm_id = aws_fsx_ontap_storage_virtual_machine.mysvm.id From 171f283e64dd1c7912eef9c1f113b059afa1f703 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 19 Aug 2026 16:18:59 -0500 Subject: [PATCH 2/3] Updated to use the current paths for the terraform directories --- .github/workflows/fsxn_as_pvc_terraform.yaml | 2 +- .github/workflows/fsxn_rotate_secret_terraform.yml | 2 +- .github/workflows/terraform.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/fsxn_as_pvc_terraform.yaml b/.github/workflows/fsxn_as_pvc_terraform.yaml index bcd30874..1927280d 100644 --- a/.github/workflows/fsxn_as_pvc_terraform.yaml +++ b/.github/workflows/fsxn_as_pvc_terraform.yaml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Set up Terraform uses: hashicorp/setup-terraform@ed3a0531877aca392eb870f440d9ae7aba83a6bd # v1.4.0 diff --git a/.github/workflows/fsxn_rotate_secret_terraform.yml b/.github/workflows/fsxn_rotate_secret_terraform.yml index 99a53294..01ac6737 100644 --- a/.github/workflows/fsxn_rotate_secret_terraform.yml +++ b/.github/workflows/fsxn_rotate_secret_terraform.yml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 with: fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Set up Terraform uses: hashicorp/setup-terraform@ed3a0531877aca392eb870f440d9ae7aba83a6bd # v1.4.0 diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml index 442a10eb..ead6d950 100644 --- a/.github/workflows/terraform.yml +++ b/.github/workflows/terraform.yml @@ -43,7 +43,7 @@ jobs: uses: hashicorp/setup-terraform@ed3a0531877aca392eb870f440d9ae7aba83a6bd # v1.4.0 with: terraform_wrapper: false - terraform_version: 1.6.6 + terraform_version: 1.12.1 - name: Initialize Terraform run: terraform init From 395330061335c95223820a393942178396f3017b Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Thu, 20 Aug 2026 16:49:36 -0500 Subject: [PATCH 3/3] Added an option to display the progress of the reading of each file. --- .../warm_performance_tier | 464 +++++++++++++++--- 1 file changed, 401 insertions(+), 63 deletions(-) diff --git a/Management-Utilities/warm_performance_tier/warm_performance_tier b/Management-Utilities/warm_performance_tier/warm_performance_tier index abfcd86f..813098c0 100755 --- a/Management-Utilities/warm_performance_tier/warm_performance_tier +++ b/Management-Utilities/warm_performance_tier/warm_performance_tier @@ -2,10 +2,12 @@ # ################################################################################ # This script is used to warm an FSx for ONTAP volume. It does that simply -# by reading every byte of every file in a volume. By doing reading all the +# by reading every byte of every file in a volume. By reading all the # contents of a file, that forces the data to be read from the capacity tier # and stored in the performance tier. The assumption is that the user has -# changed the tiering policy to something other than "all". +# changed the tiering policy to something other than "all" and that +# the volume is of type "DP" since ONTAP will not promote data for +# a DP volume unless the tiering is set to "None." # # To try and speed up the process, it will spawn multiple threads to process # the volume. It will spawn a separate thread for each directory @@ -28,15 +30,22 @@ usage () { cat 1>&2 <&2 + exit 1 + } + currentTime=$(date +%s) + elaspedTime=$((currentTime-startTime)) + hours=$((elaspedTime/3600)) + minutes=$(((elaspedTime-hours*3600)/60)) + seconds=$((elaspedTime-(hours*3600+minutes*60))) + if [ $verbose == "true" ]; then + printf "\033[1;1H\033[KElasped Time: %02d:%02d:%02d" $hours $minutes $seconds + else + printf "\rElasped Time: %02d:%02d:%02d" $hours $minutes $seconds + fi + ) 100<$displaySlotsFile + sleep 1 + x=$(ps --ppid $ppid | sed -e 1d | fgrep -v $$ | wc -l) + # + # If the displaySlotsFile is no longer readable, then the script has exited and we should exit too. + if [ ! -r $displaySlotsFile ]; then + exit + fi + done +} + +################################################################################ +# This function is used to add a line to the status section at the top of the +# display. It will add the line to the bottom, and push the other lines up. +################################################################################ +addStatusLine() { + line="$1" + if [ $verbose == "false" ]; then + echo $line + return + fi + # + # If the displaySlotsFile is no longer readable, then the script has exited and we should exit too. + if [ ! -r $displaySlotsFile ]; then + exit + fi + ( + flock -x -w 10 100 + if [ $? -ne 0 ]; then + echo "Error, cannot acquire the lock to add a status line." 1>&2 + exit 1 + fi + . $statusLinesFile + + for i in $(seq 1 3); do + statusLines[$i]="${statusLines[$(($i+1))]}" + done + statusLines[4]="$line" + displaySlots[5]="$line" + > $statusLinesFile + for slot in $(seq 1 4); do + printf "statusLines[$slot]=\"${statusLines[$slot]}\"\n" >> $statusLinesFile + printf "\033[$((slot+1));1H\033[K${statusLines[$slot]}" + done + ) 100<$displaySlotsFile +} + +################################################################################ +# This function returns the next available display slot and mark that slot +# as used. +################################################################################ +getNextDisplaySlot() { + # + # If the displaySlotsFile is no longer readable, then the script has exited and we should exit too. + if [ ! -r $displaySlotsFile ]; then + exit + fi + ( + flock -x -w 10 100 + if [ $? -ne 0 ]; then + echo "Error, cannot acquire the lock to get the next display slot." 1>&2 + exit 1 + fi + . $displaySlotsFile + for slot in $(seq 1 $maxDisplaySlots); do + if [ ${displaySlots[$slot]} -eq 0 ]; then + displaySlots[$slot]=1 + echo $slot + echo "displaySlots=(${displaySlots[*]})" > $displaySlotsFile + return 0 + fi + done + echo "Error, no display slots available. This shouldn't happen." 1>&2 + exit 1 + ) 100<$displaySlotsFile +} + +################################################################################ +# This function frees a display slot so it can be used by another thread. +################################################################################ +freeDisplaySlot () { + slot=$1 + # + # If the displaySlotsFile is no longer readable, then the script has exited and we should exit too. + if [ ! -r $displaySlotsFile ]; then + exit + fi + ( + flock -x -w 10 100 || { + echo "Error, cannot acquire the lock to free the display slot." 1>&2 + exit 1 + } + . $displaySlotsFile + if [ $slot -lt 1 -o $slot -gt $maxDisplaySlots ]; then + echo "Error, invalid display slot '$slot'." 1>&2 + exit 1 + fi + displaySlots[$slot]=0 + echo "displaySlots=(${displaySlots[*]})" > $displaySlotsFile + ) 100<$displaySlotsFile +} + +################################################################################ +# This function is used to update a display slot with a message. +################################################################################ +updateDisplay() { + slot=$1 + message="$2" + # + # If the displaySlotsFile is no longer readable, then the script has exited and we should exit too. + if [ ! -r $displaySlotsFile ]; then + exit + fi + ( + flock -x -w 10 100 || { + echo "Error, cannot acquire the lock to update the display." 1>&2 + exit 1 + } + printf "\033[$slot;1H\033[K$message" + ) 100<$displaySlotsFile +} + ################################################################################ # This function is used to see if a volume is already mounted. It will echo # to standard output the mount point if it is mounted, otherwise it will echo @@ -90,30 +247,160 @@ isMounted () { return 1 } +################################################################################ +# This function is used to read a file and discard the output. +################################################################################ +readFile() { + local file="$1" + local directory="$2" + local displaySlot + + if [ $verbose == "true" ]; then + displaySlot=$(getNextDisplaySlot) + fi + + if [ $createCopy == "true" ]; then + out="${curDir}${directory}" + mkdir -p "$out" + out="$out/$file" + else + out="/dev/null" + fi + updateDisplay $displaySlot "cat ${file} - Start" + cat "$file" > "$out" 2>/dev/null + updateDisplay $displaySlot "cat ${file} - Done" + + if [ $verbose == "true" ]; then + freeDisplaySlot $displaySlot + fi +} + ################################################################################ # This function is used to read a file and discard the output. It reads the file # in blocks of 4MB in reverse order. It is done this way so ONTAP doesn't # assume this is a backup process and not promote the data to the performance # tier. ################################################################################ -readFile () { - local file=$1 - local blockSize=$((2*1024*1024)) +readFileReverse () { + local file="$1" + local directory="$2" + local runningPIDs + + fileSize=$(stat -c "%s" "$file") + totalFileBlocks=$((fileSize / blockSize)) + + if [ $createCopy == "true" ]; then + out="${curDir}${directory}" + mkdir -p "$out" + out="$out/$file" + else + out="/dev/null" + fi + + if [ $verbose == "true" ]; then + displaySlot=$(getNextDisplaySlot) + fi + + fileBlocks=$totalFileBlocks + lastUpdatePercent=99 # just needs to be non-zero. + while [ $fileBlocks -ge 0 ]; do + if [ $totalFileBlocks -gt 0 ]; then + let percentDone=100-fileBlocks*100/totalFileBlocks + else + percentDone=100 + fi + if [ $((percentDone%10)) == 0 -a $verbose == "true" -a $percentDone != $lastUpdatePercent ]; then + lastUpdatePercent=$percentDone + updateDisplay $displaySlot "${file}: $percentDone%%" + fi + if [ ${#runningPIDs[*]} -ge $maxFileThreads ]; then + wait -n -p pid + if [ $? -eq 127 ]; then + echo "$BASHPID $(date +%s) - Warning, 'wait -n' returned 127" 1>&2 + return 1 + else + # + # Check to make sure the PID is one that we recorded. + if [ "${runningPIDs[$pid]}" != $pid ]; then + echo "$BASHPID $(date +%s) - Warning, expected $pid, got '${runningPIDs[$pid]}'" 1>&2 + fi + unset runningPIDs[$pid] + fi + fi + + dd if="$file" of="$out" bs=$blockSize conv=sparse,notrunc count=1 skip=$fileBlocks seek=$fileBlocks > /dev/null 2>&1 & + runningPIDs[$!]=$! + let fileBlocks-=1 + done + wait + if [ $verbose == "true" ]; then + freeDisplaySlot $displaySlot + fi + return 0 +} + +################################################################################ +# This function is used to read a file and discard the output. It reads the file +# in blocks of $blocksize in random order. It is done this way so ONTAP doesn't +# assume this is a backup process and not promote the data to the performance +# tier. +################################################################################ +readFileRandom () { + + local file="$1" + local directory="$2" + local blocks fileSize=$(stat -c "%s" "$file") - fileBlocks=$((fileSize/blockSize)) + fileBlocks=$((fileSize / blockSize)) if [ $((fileSize % blockSize)) -ne 0 -o $fileSize -eq 0 ]; then let fileBlocks+=1 fi + totalFileBlocks=$fileBlocks + # + # Create a random list of blocks to read. + for ((i=0; i<$fileBlocks; i++)); do + blocks[$i]=$i + done + # + # Shuffle the blocks. + for ((i=0; i<$fileBlocks; i++)); do + j=$(($SRANDOM % $fileBlocks)) + tmp=${blocks[$i]} + blocks[$i]=${blocks[$j]} + blocks[$j]=$tmp + done + + if [ $createCopy == "true" ]; then + out="${curDir}${directory}" + mkdir -p "$out" + out="$out/$file" + else + out="/dev/null" + fi - while [ $fileBlocks -ge 0 ]; do - if dd if="$file" of=/dev/null bs=$blockSize count=1 skip=$fileBlocks > /dev/null 2>&1; then + if [ $verbose == "true" ]; then + displaySlot=$(getNextDisplaySlot) + fi + + lastUpdatePercent=99 # Just set to something non-zero. + for ((i=0; i<$fileBlocks; i++)); do + let percentDone=i*100/fileBlocks + if [ $((percentDone%10)) == 0 -a $verbose == "true" -a $percentDone != $lastUpdatePercent ]; then + lastUpdatePercent=$percentDone + updateDisplay $displaySlot "${file}: ${percentDone}%%" + fi + if dd if="$file" of="$out" bs=$blockSize conv=sparse,notrunc count=1 skip=${blocks[$i]} seek=${blocks[$i]} > /dev/null 2>&1; then : else return 1 fi - let fileBlocks-=1 done + + if [ $verbose == "true" ]; then + freeDisplaySlot $displaySlot + fi + return 0 } @@ -125,31 +412,46 @@ processDirectory () { local runningPIDs if [ "$verbose" = "true" ]; then - echo "$BASHPID $(date +%s) - Processing $1" + addStatusLine "$(date) - Processing directory: $1" fi cd "$1" + if [ $? -ne 0 ]; then + addStatusLine "$(date) - Warning, cannot change to directory '$1'." + return + fi while read file; do if [ -f "$file" ]; then # # If there are too many threads running already, wait until one finishes. - if [ ${#runningPIDs[*]} -ge $maxFileThreads ]; then + if [ ${#runningPIDs[*]} -ge $maxFilesThreads ]; then wait -n -p pid if [ $? -eq 127 ]; then - echo "$BASHPID $(date +%s) - Warning, 'wait -n' returned 127" 1>&2 + addStatusLine "$(date) - Warning, 'wait -n' returned 127." else # # Check to make sure the PID is one that we recorded. if [ "${runningPIDs[$pid]}" != $pid ]; then - echo "$BASHPID $(date +%s) - Warning, expected $pid, got '${runningPIDs[$pid]}'" 1>&2 + addStatusLine "$(date) - Warning, expected $pid, got '${runningPIDs[$pid]}'." fi unset runningPIDs[$pid] fi fi - if [ "$verbose" == "true" ]; then - echo "$BASHPID $(date +%s) - Reading $1/$file and discarding output. Number of threads: $((${#runningPIDs[*]}+1))" - fi - readFile "$file" || echo "$BASHPID $(date +%s) - Warning, cannot read '${file}'." 1>&2 & + case $readMethod in + reverse) + readFileReverse "$file" "$1" || echo "$BASHPID $(date +%s) - Warning, cannot read '${file}'." 1>&2 & + ;; + random) + readFileRandom "$file" "$1" || echo "$BASHPID $(date +%s) - Warning, cannot read '${file}'." 1>&2 & + ;; + cat) + readFile "$file" "$1" || echo "$BASHPID $(date +%s) - Warning, cannot read '${file}'." 1>&2 & + ;; + *) + echo "Error, unknown read method '${readMethod}'." 1>&2 + exit 1 + ;; + esac # # Record the PID of the process mostly so we can keep up with how many are running. runningPIDs[$!]=$! @@ -159,7 +461,7 @@ processDirectory () { # Wait for all the file threads to finish. wait if [ "$verbose" = "true" ]; then - echo "$BASHPID $(date +%s) - Done processing $1." + addStatusLine "$(date) - Done processing $1." fi } @@ -168,41 +470,68 @@ processDirectory () { ################################################################################ # # Set some defaults. -maxDirThreads=2 -maxFileThreads=5 +maxDirThreads=4 # Maximum number of directories to process at the same time. +maxFilesThreads=5 # Maximum number of files to processs at the same time. +maxFileThreads=10 # Maximum number of threads to read a file with at the same time. nfsType=nfs4 -verbose=false +export verbose=false +readMethod=reverse +createCopy=false +blockSize=$((2*1024*1024)) +displaySlotsFile=$(mktemp /tmp/displaySlotsLock.XXXXXX) +statusLinesFile=$(mktemp /tmp/statusLines.XXXXXX) +exitFile=$(mktemp /tmp/exit.XXXXXX) +trapCommands="rm -f $displaySlotsFile $statusLinesFile $exitFile" +trap 'eval "$trapCommands"' EXIT +# +# Initialize the displaySlots array to all slots (lines) available except the first 4 that are used for status messages. +# The first element of the array isn't used, but since when you echo the array out +# and then read them back in, the array starts at index 0, and we want to start with 1. +displaySlots[0]=1 +# Reserve the first 4 lines for status messages. +displaySlots[1]=1 +displaySlots[2]=1 +displaySlots[3]=1 +displaySlots[4]=1 +displaySlots[5]=1 +firstFreeSlot=${#displaySlots[*]} +maxDisplaySlots=$((maxDirThreads*maxFilesThreads+(firstFreeSlot-1))) +for slot in $(seq $firstFreeSlot $maxDisplaySlots); do + displaySlots[$slot]=0 +done +echo "displaySlots=(${displaySlots[*]})" > $displaySlotsFile # # process command line options. -while getopts "f:v:t:d:n:x:hV" option; do +while getopts "f:v:t:d:n:x:X:r:b:hVc" option; do case $option in - f) - filesystemHostname=$OPTARG - ;; - v) - volumeName=$OPTARG - ;; - d) - rootDirectory=$OPTARG - ;; - t) - maxDirThreads=$OPTARG - ;; - x) - maxFileThreads=$OPTARG - ;; - n) - nfsType=$OPTARG - ;; - V) - verbose=true - ;; - *) - usage + f) filesystemHostname=$OPTARG ;; + v) volumeName=$OPTARG ;; + d) rootDirectory=$OPTARG ;; + t) maxDirThreads=$OPTARG ;; + x) maxFilesThreads=$OPTARG ;; + X) maxFileThreads=$OPTARG ;; + n) nfsType=$OPTARG ;; + V) verbose=true ;; + r) readMethod=$OPTARG ;; + b) blockSize=$OPTARG ;; + c) createCopy=true curDir=$(pwd) ;; + *) usage exit 1 ;; esac done +if [ $verbose == "true" ]; then + LINES=$(stty size | awk '{print $1}') + if [ $maxDisplaySlots -gt $LINES ]; then + echo "Warning, to provide verbose output you need at least ${maxDisplaySlots} lines in the terminal. The current terminal only has $LINES lines." 1>&2 + echo " Verbose output has been disabled." 1>&2 + verbose=false + else + printf "\033[s" # Save the cursor position. + printf "\033[2J" # Clear the screen. + fi +fi +addStatusLine "Using the $readMethod reading method." # # If the user provided a filesystem endpoint, then we need to try to mount the volume. if [ ! -z "$filesystemHostname" ]; then @@ -226,11 +555,11 @@ if [ ! -z "$filesystemHostname" ]; then exit 1 fi - if mount -t $nfsType -o hard,ro $filesystemHostname:/$volumeName $tmpMount; then + if mount -t $nfsType -o hard,ro,nconnect=16 $filesystemHostname:/$volumeName $tmpMount; then if [ "$verbose" == "true" ]; then - echo "Volume '${volumeName}' from file system '${filesystemHostname}' mounted at '${tmpMount}'." + addStatusLine "Volume '${volumeName}' from file system '${filesystemHostname}' mounted at '${tmpMount}'." fi - trap 'umount $tmpMount; rmdir $tmpMount' EXIT + trapCommands="$trapCommands; umount $tmpMount; rmdir $tmpMount" else echo "Error, cannot mount ${filesystemHostname}:${volumeName}." 1>&2 rmdir $tmpMount @@ -239,7 +568,7 @@ if [ ! -z "$filesystemHostname" ]; then rootDirectory=$tmpMount else if [ $verbose == "true" ]; then - echo "Volume '${volumeName}' from file system '${filesystemHostname}' is already mounted at '${rootDirectory}'." + addStatusLine "Volume '${volumeName}' from file system '${filesystemHostname}' is already mounted at '${rootDirectory}'." fi fi fi @@ -256,7 +585,8 @@ if [ ! -d "$rootDirectory" ]; then exit 1 fi # -# Process all the driectories in the volume. +# Process all the directories in the volume. +updateTimer $$ & while read directory; do # # If there are too many threads running already, wait until one finishes. @@ -268,20 +598,28 @@ while read directory; do # # Check to make sure the PID is one that we recorded. if [ "${runningPIDs[$pid]}" != $pid ]; then - echo "$$ $(date +%s) - Warning, expected $pid, got '${runningPIDs[$pid]}'" 1>&2 + addStatusLine "$(date) - Warning, expected $pid, got '${runningPIDs[$pid]}'." else unset runningPIDs[$pid] fi fi fi - if [ "$verbose" == "true" ]; then - echo "$$ $(date +%s) - Processing directory $directory. Number of threads: $((${#runningPIDs[*]}+1))." - fi processDirectory "$directory" & runningPIDs[$!]=$! done < <(find $rootDirectory -type d) if [ "$verbose" = "true" ]; then - echo "$$ $(date +%s) - Waiting for all directory threads to finish." + addStatusLine "$(date) - Waiting for all directory threads to finish." fi wait +printf "\033[u" # Restore the cursor position. + +if [ $createCopy == "true" ]; then + echo "Compare the results" + if diff -r "$rootDirectory" "$curDir/${rootDirectory#/}"; then + echo "The results are the same. Removing directory." + rm -rf "$curDir/${rootDirectory#/}" + else + echo "Error, the results are different." 1>&2 + fi +fi