From ab0af06642d0c681fdfb0f7b19622ac261239668 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 2 Oct 2024 14:53:23 -0500 Subject: [PATCH 01/10] Made all the create and delete script support a 'wait' option; Made the delete_fsxn_svm support deleting all the volumes under the SVM; Now delete_fsxn_filesystem calls delete_fsxn_svm to delete SVMs, and delete_fsxn_svm calls delete_fsxn_volume to delete volumes. --- .../fsx-ontap-aws-cli-scripts/README.md | 10 +- .../create_fsxn_filesystem | 66 +++- .../fsx-ontap-aws-cli-scripts/create_fsxn_svm | 54 ++- .../create_fsxn_volume | 39 ++- .../delete_fsxn_filesystem | 307 ++++++------------ .../fsx-ontap-aws-cli-scripts/delete_fsxn_svm | 183 ++++++++++- .../delete_fsxn_volume | 66 +++- 7 files changed, 464 insertions(+), 261 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md index 7f42b1e..890dfbe 100644 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md @@ -14,17 +14,17 @@ Before running the UNIX based scripts, make sure the following package is instal | Script | Description | |:------------------------|:----------------| -|create_fsxn_filesystem | Creates a new FSx for NetApp ONTAP file-system | -|create_fsxn_svm | Creates a new Storage Virtual Server (svm) in a soecific FSx ONTAP filesystem | +|create_fsxn_filesystem | Creates a new FSx for NetApp ONTAP file-system. | +|create_fsxn_svm | Creates a new Storage Virtual Server (SVM) in a soecific FSx ONTAP filesystem. | |create_fsxn_volume | Creates a new volume under a specified SVM. | |list_fsx_filesystems | List all the FSx for NetApp ONTAP filesystems that the user has access to. | |list_fsx_filesystems.ps1 | List all the FSx for NetApp ONTAP filesystems that the user has access to, written in PowerShell. | |list_fsxn_volumes | List all the FSx for NetApp ONTAP volumes that the user has access to. | |list_fsxn_svms | List all the storage virtual machines that the user access to. | |list_aws_subnets | List all the aws subnets. | -|list_aws_vpcs | List all the aws vpcs. | -|delete_fsxn_filesystem | Deletes an FSx for NetApp ONTAP filesystem. | -|delete_fsxn_svm | Deletes an svm. | +|list_aws_vpcs | List all the aws VPCs. | +|delete_fsxn_filesystem | Deletes an FSx for NetApp ONTAP filesystem. Including all the SVMs and volumes on it. | +|delete_fsxn_svm | Deletes an svm. Including all the volumes assigned to it. | |delete_fsxn_volume | Deletes a volume. | diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem index 112391b..f0cd4e0 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem @@ -20,7 +20,7 @@ ################################################################################ usage () { cat 1>&2 < /dev/null 2>&1; then - : -else - echo "Error, both the 'aws' and 'jq' commands are required to run this script." 1>&2 - exit 1 -fi +for cmd in jq aws; do + if which $cmd > /dev/null 2>&1; then + : + else + echo "Error, the '$cmd' is required to run this script." 1>&2 + exit 1 + fi +done # # Set some defaults. size=1024 @@ -55,6 +66,7 @@ region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') securityGroupOption="" endpointips="" azType="MULTI_AZ_1" +waitForCompletion=false # # Process command line arguments. while [ ! -z "$1" ]; do @@ -110,6 +122,9 @@ while [ ! -z "$1" ]; do endpointips='"EndpointIpAddressRange": "'$2'",' shift ;; + -wait|--wait) + waitForCompletion=true + ;; -h|-help|--help) usage ;; @@ -151,11 +166,44 @@ if [ $? != "0" ]; then else status=$(jq -r .FileSystem.Lifecycle $tmpout 2> /dev/null) if [ "$status" == "CREATING" -o "$status" == "PENDING" ]; then - echo "File system '$fileSystemName' ($(jq -r .FileSystem.FileSystemId $tmpout)) is being created." - exit 0 + fsid=$(jq -r .FileSystem.FileSystemId $tmpout) + printf "File system '$fileSystemName' ($fsid) is being created." + if [ $waitForCompletion == "true" ]; then + i=0 + while [ $i -lt $MaxIterations ]; do + aws fsx describe-file-systems --file-system-ids $fsid --output=json --region=$region > $tmpout 2>&1 + if [ $? -eq 0 ]; then + status=$(jq -r '.FileSystems[0].Lifecycle' $tmpout 2> /dev/null) + if [ "$status" == "AVAILABLE" ]; then + printf "\nFile system '$fileSystemName' ($fsid) has been created.\n" + break + fi + if [ "$status" != "CREATING" -a "$status" != "PENDING" ]; then + printf "\nError, failed to create the file system. Status = $status\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + fi + printf "." + else + printf "\nError, failed to get the file system status.\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + fi + sleep $SleepTime + let i+=1 + done + if [ $i -ge $MaxIterations ]; then + printf "\nFailed to create file system('$fsid'). Taking too long.\n" 1>&2 + exit 1 + fi + exit 0 + else + echo + fi else echo "Unknown status '$status'. Complete output returned from the AWS api:" 1>&2 cat $tmpout 1>&2 exit 1 fi fi +exit 0 diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm index 8935954..74cb055 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm @@ -21,12 +21,13 @@ ################################################################################ usage () { cat 1>&2 < /dev/null | jq -r ".FileSystems[] | if((.Tags[] | select(.Key == \"Name\") .Value) == \"${fileSystemName}\") then .FileSystemId else empty end" 2> /dev/null) + fsid=$(aws fsx describe-file-systems --region $region --output=json 2> /dev/null | jq -r ".FileSystems[] | if((.Tags[] | select(.Key == \"Name\") .Value) == \"${fileSystemName}\") then .FileSystemId else empty end" 2> /dev/null) fi if [ -z "$fsid" ]; then - echo "Error, could not find the file system with name '$fileSystemName}' in region $region." 1>&2 + echo "Error, could not find the file system with name '${fileSystemName}' in region $region." 1>&2 exit 1 fi # @@ -94,11 +100,45 @@ if [ $? != "0" ]; then else status=$(jq -r .StorageVirtualMachine.Lifecycle $tmpout 2> /dev/null) if [ "$status" == "CREATING" -o "$status" == "PENDING" ]; then - echo "Stroage Virtaul Machine '$svmName'($(jq -r '.StorageVirtualMachine.StorageVirtualMachineId' $tmpout)) is being created." - exit 0 + svmId=$(jq -r '.StorageVirtualMachine.StorageVirtualMachineId' $tmpout) + printf "Stroage Virtaul Machine '$svmName'($svmId) is being created." + # + # Wait for the svm to be deleted. + if [ $waitForCompletion == true ]; then + i=0 + while [ $i -lt $maxIterations ]; do + aws fsx describe-storage-virtual-machines --storage-virtual-machine-ids $svmId --output=json --region=$region > $tmpout 2>&1 + if [ $? -eq 0 ]; then + status=$(jq -r '.StorageVirtualMachines[0].Lifecycle' $tmpout 2> /dev/null) + if [ "$status" == "CREATED" ]; then + printf "\nStorage Virtual Machine '$svmName'($svmId) has been created.\n" + break + fi + if [ "$status" != "CREATING" -a "$status" != "PENDING" ]; then + printf "\nError, failed to create SVM with SVM ID '$svmId'. Status = $status\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + fi + else + printf "\nError, failed to get status of SVM with SVM ID '$svmId'.\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + fi + printf "." + sleep $sleepTime + let i+=1 + done + if [ $i -ge $maxIterations ]; then + printf "\nFailed to create SVM with SVM ID of '$svmID'. Taking too long.\n" 1>&2 + exit 1 + fi + else + printf "\n" + fi else echo "Unknown status '$status'. Complete output returned from the AWS api:" 1>&2 cat $tmpout 1>&2 exit 1 fi fi +exit 0 diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume index eb9e592..9577ffd 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume @@ -38,9 +38,18 @@ EOF tmpout=/tmp/create_volume.$$ trap 'rm -f $tmpout' exit # +# Set the maximum number of times to check that a volume has been +# created. Multiple it by the SleepTime set below to the total amount of +# time allowed. +maxIterations=24 +# +# Set the number of seconds to wait between checks that a volume and/or SVM has been deleted. +sleepTime=5 +# # Set some defaults. size=20 region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') +waitForCompletion=false # # Process command line arguments. while getopts "hi:n:r:s:w" option; do @@ -53,7 +62,7 @@ while getopts "hi:n:r:s:w" option; do ;; s) size=$OPTARG ;; - w) wait=1 + w) waitForCompletion=true ;; *) usage ;; @@ -84,21 +93,35 @@ else status=$(jq -r .Volume.Lifecycle $tmpout 2> /dev/null) if [ "$status" == "CREATING" -o "$status" == "PENDING" ]; then volumeId=$(jq -r .Volume.VolumeId $tmpout) - echo "FSxN volume '$volumeName'($volumeId) is being created." - if [ ! -z "$wait" ]; then - echo -n "Waiting for volume to be created." - while [ $status == "CREATING" -o $status == "PENDING" ]; do - sleep 4 + printf "FSxN volume '$volumeName'($volumeId) is being created." + if [ "$waitForCompletion" == "true" ]; then + i=0 + while [ $i -lt $maxIterations ]; do aws fsx describe-volumes --volume-ids $volumeId --region=$region --output=json > $tmpout 2>&1 status=$(jq -r .Volumes[0].Lifecycle $tmpout 2> /dev/null) + if [ $status == "CREATED" ]; then + printf "\nVolume '$volumeName'($volumeId) has been created.\n" + break + fi + if [ $status != "CREATING" -a $status != "PENDING" ]; then + echo "Error, volume $volumeId creation failed." 1>&2 + cat $tmpout 1>&2 + exit 1 + fi echo -n "." + sleep $sleepTime done - printf "\nVolume as been $status.\n" + if [ $i -gt $maxIterations ]; then + printf "\nError, volume creation failed. Took too long." 1>&2 + exit 1 + fi + else + printf "\n" fi - exit 0 else echo "Unknown status '$status'. Complete output returned from the AWS api:" 1>&2 cat $tmpout 1>&2 exit 1 fi fi +exit 0 diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem index 0d8b7d5..d24aff0 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem @@ -12,7 +12,13 @@ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ################################################################################ # -# This script is used to delete a FSxN filesystem. +# This script is used to delete a FSxN file system. It does that by first +# displaying all the SVM and volumes associated with the file system and then +# asking the user if they are sure they want to delete the file system. If the +# user responds with 'yes', then the script will delete all the SVMs associated +# with the file system. The 'delete_fsxn_svm' script will delete all the volumes +# associated with the SVM. Once all the SVMs and volumes have been deleted, the +# script will then delete the file system itself. ################################################################################ ################################################################################ @@ -21,12 +27,13 @@ ################################################################################ usage () { cat 1>&2 < $tmpout 2>&1 - if [ $? != "0" ]; then - printf "\nError, failed to delete a volume with volumeId: '$volumeId'.\n" 1>&2 - cat $tmpout 1>&2 - return 1 - fi - # - # Wait for the volume to be deleted. - i=0 - while [ $i -lt $MaxIterations ]; do - aws fsx describe-volumes --volume-ids $volumeId --output=json --region=$region > $tmpout 2>&1 - if [ $? -eq 0 ]; then - status=$(jq -r .Volumes[0].Lifecycle $tmpout 2> /dev/null) - if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then - printf "\nError, failed to delete volume with volume ID '$volumeId'. Status = ${status}.\n" 1>&2 - cat $tmpout 1>&2 - return 1 - fi - else - # Assume if it failed, it is because the volume was deleted and doesn't exist anymore. - break - fi - sleep $SleepTime - let i+=1 - done - if [ $i -ge $MaxIterations ]; then - echo "Failed to delete volume with volume ID of '$volumeId'. Taking too long." 1>&2 - return 1 - fi - return 0 -} - -################################################################################ -# This function is used to delete an FSxN SVM. It waits for the SVM to be -# deleted. It assumes the SVM has been deleted when the API call to display -# its status returns an error. -################################################################################ -delete_svm() { - - local tmpout=/tmp/delete_fsxn_delete_svm.$BASHPID - trap 'rm -f $tmpout' RETURN - - local svmId=$1 - aws fsx delete-storage-virtual-machine --region=$region --output=json --storage-virtual-machine-id $svmId > $tmpout 2>&1 - if [ $? != "0" ]; then - printf "\nError, failed to delete a SVM with svmID: '$svmId'.\n" 1>&2 - cat $tmpout 1>&2 - return 1 - fi - # - # Wait for the svm to be deleted. - i=0 - while [ $i -lt $MaxIterations ]; do - aws fsx describe-storage-virtual-machines --storage-virtual-machine-ids $svmId --output=json --region=$region > $tmpout 2>&1 - if [ $? -eq 0 ]; then - status=$(jq -r '.StorageVirtualMachines[0].Lifecycle' $tmpout 2> /dev/null) - if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then - printf "\nError, failed to delete SVM with SVM ID '$svmId'. Status = $status\n" 1>&2 - cat $tmpout 1>&2 - return 1 - fi - else - # Assume if it failed, it is because the SVM was delted and therefore doesn't exist anymore. - break - fi - sleep $SleepTime - let i+=1 - done - if [ $i -ge $MaxIterations ]; then - printf "\nFailed to delete SVM with SVM ID of '$svmID'. Taking too long.\n" 1>&2 - return 1 - fi - return 0 -} - ################################################################################ # Main logic starts here. ################################################################################ @@ -144,31 +63,32 @@ svmsFile=/tmp/fsx_fs_delete_svms.$$ volumesFile=/tmp/fsx_fs_delete_volumes.$$ trap 'rm -f $tmpout $svmsFile $volumesFile' exit # -# Set the maximum number of times to check that a volume and/or SVM has been -# deleted. Multiple it by the SleepTime set below to the total amount of -# time allowed. Note, it takes at least 4 minutes to delete a volume. +# Set the maximum number of times to check that will be made to see if a +# file system has been deleted. Multiple it by the SleepTime set below to +# the total amount of time allowed. MaxIterations=120 # -# Set the number of seconds to wait between checks that a volume and/or SVM has been deleted. +# Set the number of seconds to wait between checks that the file system +# has been deleted. SleepTime=5 # -# Set the maximum number of "volume deletes" that can be running at the same time. -MaxDeletesRunning=20 -# # Check that the required commands are available. -if which jq aws > /dev/null 2>&1; then - : -else - echo "Error, both the 'aws' and 'jq' commands is required to run this script." 1>&2 - exit 1 -fi +for cmd in jq aws delete_fsxn_svm delete_fsxn_volume; do + if which $cmd > /dev/null 2>&1; then + : + else + echo "Error, command '$cmd' is required to run this script." 1>&2 + exit 1 + fi +done # # Get the default region. region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') -skipBackup=true +enableBackup=false +waitForCompletion=false # # Process command line arguments. -while getopts "hbr:f:i:" option; do +while getopts "hwbr:f:i:" option; do case $option in f) fileSystemName=$OPTARG ;; @@ -176,7 +96,9 @@ while getopts "hbr:f:i:" option; do ;; i) fsid=$OPTARG ;; - b) skipBackup=false + b) enableBackup=true + ;; + w) waitForCompletion=true ;; *) usage ;; @@ -190,9 +112,15 @@ fi # # Ensure all the required parameters have been provided. if [ -z "$fileSystemName" -a -z "$fsid" ]; then - echo "Error, missing required arguments." 1>&2 + echo "Error, you must provide either the filesystem name or the file system id that you want to delete." 1>&2 usage # implied exit fi + +if [ $enableBackup == "true" ]; then + enableBackup="-b" # Turn it into a flag passed to the delete_fsxn_svm script. +else + enableBackup="" +fi # # Get the file system id based on the name. if [ -z "$fsid" ]; then @@ -212,135 +140,61 @@ if [ -z "$fsid" ]; then else # # Get the file system name based on the fsid. - fileSystemName=$(aws fsx describe-file-systems --file-system-ids $fsid --region=$region --output=json 2> /dev/null | jq -r '.FileSystems[0].Tags[] | select(.Key == "Name") .Value' 2> /dev/null) - if [ -z "$fileSystemName" ]; then + aws fsx describe-file-systems --file-system-ids $fsid --region=$region --output=json > $tmpout 2>&1 + if [ $? -ne 0 ]; then echo "Error, failed to get the file system name based on the ID ($fsid)." 1>&2 + cat $tmpout 1>&2 exit 1 fi + fileSystemName=$(jq -r '.FileSystems[0].Tags[] | select(.Key == "Name") .Value' $tmpout) + # + # Since it isn't required to have a name (Name tag), set it to "Not Set" if it doesn't exist.k + if [ -z "$fileSystemName" ]; then + fileSystemName="Not Set" + fi fi # -# Create a JSON file with all the FSxN SVMs in the region. -aws fsx describe-storage-virtual-machines --region=$region --output=json > $svmsFile 2>&1 +# Create a JSON file with all the SVMs associated with the file system. +aws fsx describe-storage-virtual-machines --region=$region --output=json --filters Name=file-system-id,Values=$fsid > $svmsFile 2>&1 if [ $? -ne 0 ]; then echo "Error, failed to get the list of SVMs." 1>&2 cat $svmsFile 1>&2 exit 1 fi # -# Create a JSON file with all the FSXN volumes in the region. -aws fsx describe-volumes --region=$region --output=json > $volumesFile 2>&1 +# Create a JSON file with all the FSXN volumes associated with the file system. +aws fsx describe-volumes --region=$region --output=json --filters Name=file-system-id,Values=$fsid > $volumesFile 2>&1 if [ $? -ne 0 ]; then echo "Error, failed to get the list of volumes." 1>&2 cat $volumesFile 1>&2 exit 1 fi +numVolumes=$(jq '.Volumes | length' $volumesFile) +numSvms=$(jq '.StorageVirtualMachines | length' $svmsFile) # # Make sure the user really wants to delete the file system. -echo "Here are the current contents of the '$fileSystemName'($fsid) file system you have indicated you want to delete:" -displayFileSystemContents $fsid -read -p "Are you sure you want to delete this file system, with all the above volumes (yes/no)? " response -if [ "$response" != "yes" ]; then - echo "Aborted." - exit 1 +if [ $numVolumes -gt 0 -o $numSvms -gt 0 ]; then + echo "Here are the current contents of the '$fileSystemName'($fsid) file system you have indicated you want to delete:" + displayFileSystemContents $fsid + read -p "Are you sure you want to delete this file system, with all the above volumes (yes/no)? " response + if [ "$response" != "yes" ]; then + echo "Aborted." + exit 1 + fi fi # -# Before you can delete a file system, you have to first delete all the volumes, -# and then all the SVMs. So, first get the list of SVMs: -declare -a svms -declare -a volumes -svms=($(jq -r '.StorageVirtualMachines[] | if(.FileSystemId == "'$fsid'") then .StorageVirtualMachineId else empty end' $svmsFile)) +# Create a list of all the SVMs associated with the file system. +svms=($(jq -r '.StorageVirtualMachines[] | select(.FileSystemId == "'$fsId'") | .StorageVirtualMachineId' $svmsFile)) # -# Now delete all the volumes for each SVM. I could just deleted all the volumes -# associated with the fsid, but I wanted the extra check on the volumeId to be -# associated with one of the SVMs that is associated with the fsid. +# First delete all the SVMs. The 'delete_fsxn_svm' script will delete all the volumes associated with the SVM. for svmId in ${svms[*]}; do - # - # Create an array with all the non-root volume IDs for this SVM. - volumes=($(jq -r '.Volumes[] | if(.OntapConfiguration.StorageVirtualMachineId == "'$svmId'" and (.OntapConfiguration.StorageVirtualMachineRoot | not) and .FileSystemId == "'$fsid'") then .VolumeId else empty end' $volumesFile)) - if [ ! -z "${volumes[*]}" ]; then - # - # Since it can take a while for a single volume to be deleted (e.g. 4 minutes - # for a small empty volume) and you can do multiple deletes in parallel, - # spawn them in the background and wait for them to finish. Although, since - # we don't want to overwhelm either AWS or ONTAP, only allow a certain - # number at a time. - i=0 - numRunning=0 - numVolumes=${#volumes[*]} - maxNumRunning=1 # Only do one initially, if it completes successfully, then do the rest concurrently. - printf "\nDeleting all the volumes associated with ${svmId}.\n" - while [ $i -lt $numVolumes ]; do - delete_volume ${volumes[$i]} $skipBackup & - let i+=1 - let numRunning+=1 - printf "\rTotal number of volumes to delete: ${numVolumes}. Number of deletes currently running: ${numRunning}. Number waiting to be started: $((numVolumes-i)). " - if [ $numRunning -ge $maxNumRunning ]; then - # - # Wait for a job to complete. - wait -n - rc=$? - if [ $rc -eq 127 ]; then - # - # 127 means there were no background jobs. Since we just deployed one, that shouldn't happen. - printf "\nError, got an expected response from 'wait'. Aborting.\n" 1>&2 - exit 1 - fi - if [ $rc -ne 0 ]; then - printf "\nError, one of the volume deletes failed. Aborting!\n" 1>&2 - exit 1 - fi - let numRunning-=1 - if [ $i -eq 1 ]; then - # The first one succeeded, open up the flood gates. - maxNumRunning=$MaxDeletesRunning - fi - fi - done - # - # Now that we have queued them all up, wait for them to finish. - wait -n - rc=$? - let numRunning-=1 - while [ "$rc" != 127 ]; do - printf "\rTotal number of volumes to delete: ${numVolumes}. Number of deletes currently running: ${numRunning}. Number waiting to be started: $((numVolumes-i)). " - if [ "$rc" != 0 ]; then - printf "\nError, one of the volume deletes failed. Aborting!\n" 1>&2 - exit 1 - fi - wait -n - rc=$? - let numRunning-=1 - done + delete_fsxn_svm -n -w $enableBackup -i $svmId -r $region + if [ $? -ne 0 ]; then + echo "Error, failed to delete the SVM with SVM ID '$svmId'." 1>&2 + exit 1 fi -done # for svmId in ${svms[*]}; do -# -# Now that all the volumes are deleted, delete the SVMs. -# Since there can only be 24 SVMs, don't really have to worry about spawning -# too many at a time. -[ ${#svms[*]} -gt 0 ] && printf "\nDeleting SVMs.\n" -for svmId in ${svms[*]}; do - delete_svm $svmId & done # -# Now wait for them to finish. -if [ ! -z "$svms" ]; then - numRunning=${#svms[*]} - printf "\rTotal number of SVMs to delete: ${#svms[*]}. Number of deletes currently running: ${numRunning}. Number waiting to be started: 0. " - wait -n - rs=$? - let numRunning-=1 - while [ "$rs" != 127 ]; do - if [ "$rs" != 0 ]; then - printf "\nError, one of the SVM deletes failed. Aborting!\n" 1>&2 - exit 1 - fi - printf "\rTotal number of SVMs to delete: ${#svms[*]}. Number of deletes currently running: ${numRunning}. Number waiting to be started: 0. " - wait -n - rs=$? - let numRunning-=1 - done -fi -# # Now that all the volumes and all the SVMs have been deleted, we can delete the filesystem. aws fsx delete-file-system --file-system-id $fsid --output=json --region=$region > $tmpout 2>&1 if [ $? != "0" ]; then @@ -350,7 +204,36 @@ if [ $? != "0" ]; then else status=$(jq -r .Lifecycle $tmpout) if [ "$status" == "DELETING" -o "$status" == "PENDING" ]; then - printf "\nFile system '$fileSystemName' is being deleted.\n" + printf "\nFile system '$fileSystemName'($fsid) is being deleted." + if [ $waitForCompletion == "true" ]; then + i=0 + while [ $i -lt $MaxIterations ]; do + aws fsx describe-file-systems --file-system-ids $fsid --output=json --region=$region > $tmpout 2>&1 + if [ $? -eq 0 ]; then + status=$(jq -r '.FileSystems[0].Lifecycle' $tmpout 2> /dev/null) + if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then + printf "\nError, failed to delete file system with file system ID '$fsid'. Status = $status\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + else + printf "." + fi + else + # Assume if it failed, it is because the filesystem was deleted and therefore doesn't exist anymore. + printf "\nFile system '$fileSystemName'($fsid) has been deleted.\n" + break + fi + sleep $SleepTime + let i+=1 + done + if [ $i -ge $MaxIterations ]; then + printf "\nFailed to delete file system with filesystem ID of '$fsid'. Taking too long.\n" 1>&2 + exit 1 + fi + exit 0 + else + echo + fi exit 0 else printf "\nUnknown status '$status'. Complete output returned from the AWS api:\n" 1>&2 diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm index 3c9707a..2ed7ca1 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm @@ -13,7 +13,9 @@ ################################################################################ # # This script is used to delete a storage virtual machine from a -# FSxN filesystem. +# FSxN filesystem. It will delete all the volumes associated with the +# storage virtual machine as well. +# ################################################################################ ################################################################################ @@ -21,10 +23,13 @@ ################################################################################ usage () { cat 1>&2 < /dev/null 2>&1; then - : -else - echo "Error, both the 'aws' and 'jq' commands are required to run this script." 1>&2 - exit 1 -fi +for cmd in aws jq delete_fsxn_volume; do + if which $cmd > /dev/null 2>&1; then + : + else + echo "Error, a required command '$cmd' is not in the search path. Please install it and try again." 1>&2 + exit 1 + fi +done # # Set any defaults. region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') +waitForDelete=false +noQuery=false +enableBackup=false # # Process command line arguments. -while getopts "hi:r:" option; do +while getopts "hbi:wnr:" option; do case $option in i) svmID=$OPTARG ;; r) region=$OPTARG ;; + w) waitForDelete=true + ;; + n) noQuery=true + ;; + b) enableBackup=true + ;; *) usage ;; esac - shift done + +if [ $enableBackup == "true" ]; then + enableBackup="-b" # This is just a flag to the delete_fsxn_volume script. +else + enableBackup="" +fi # # Ensure all the required parameters have been provided. if [ -z "$svmID" ]; then @@ -65,18 +86,150 @@ if [ -z "$svmID" ]; then usage exit 1 fi +# +# Set the maximum number of volume deletes that can be running at the same time. +MaxDeletesRunning=20 +# +# Set the maximum number of iterations to wait for the SVM delete to complete. +# The total time to wait is the product of MaxIterations and SleepTime. +MaxIterations=120 +# +# Set the sleep time between iterations checking to see if the SVM delete has completed. +SleepTime=5 +# +# Get the list of volumes associated with the SVM. +aws fsx describe-volumes --region=$region --output=json --filters Name=storage-virtual-machine-id,Values=$svmID > $volumesFile 2>&1 +if [ $? -ne 0 ]; then + echo "Error, failed to get the list of volumes for SVM: $svmID." 1>&2 + cat $volumesFile 1>&2 + exit 1 +fi + +if [ $noQuery != "true" ]; then + # + # Display the voluems in the SVM to make sure the user really wants to delete them. + numVolumes=$(jq '.Volumes | length' $volumesFile) + if [ $numVolumes -gt 1 ]; then # Assume there is a root volume that will be skipped. + echo "The following volumes are associated with the storage virtual machine with an id of '$svmID':" + while read volumeId volumeName; do + volumes=(${volumes[@]} $volumeId) + printf "\t$volumeId - '$volumeName'\n" + done < <(jq -r '.Volumes[] | select(.OntapConfiguration.StorageVirtualMachineRoot | not) | .VolumeId + " " + .Name' $volumesFile) + fi + read -p "Are you sure you want to delete the storage virtual machine with an id of '$svmID' and all its volumes? (yes/no): " answer + + if [ "$answer" != "yes" ]; then + echo "Aborting deletion of storage virtual machine." 1>&2 + exit 1 + fi +else + # + # Create the volumes array. + while read volumeId; do + volumes=(${volumes[@]} $volumeId) + done < <(jq -r '.Volumes[] | select(.OntapConfiguration.StorageVirtualMachineRoot | not) | .VolumeId' $volumesFile) +fi + +if [ ! -z "${volumes[*]}" ]; then + # + # Since it can take a while for a single volume to be deleted (e.g. 4 minutes + # for a small empty volume) and you can do multiple deletes in parallel, + # spawn them in the background and wait for them to finish. Although, since + # we don't want to overwhelm either AWS or ONTAP, only allow a certain + # number at a time. + i=0 + numRunning=0 + numVolumes=${#volumes[*]} + maxNumRunning=1 # Only do one initially, if it completes successfully, then do the rest concurrently. + printf "\nDeleting all the volumes associated with ${svmID}.\n" + while [ $i -lt $numVolumes ]; do + delete_fsxn_volume -r $region -w -q -i ${volumes[$i]} $enableBackup & + let i+=1 + let numRunning+=1 + printf "\rTotal number of volumes to delete: ${numVolumes}. Number of deletes currently running: ${numRunning}. Number waiting to be started: $((numVolumes-i)). " + if [ $numRunning -ge $maxNumRunning ]; then + # + # Wait for a job to complete. + wait -n + rc=$? + if [ $rc -eq 127 ]; then + # + # 127 means there were no background jobs. Since we just deployed one, that shouldn't happen. + printf "\nError, got an expected response from 'wait'. Aborting.\n" 1>&2 + exit 1 + fi + if [ $rc -ne 0 ]; then + printf "\nError, one of the volume deletes failed. Aborting!\n" 1>&2 + exit 1 + fi + let numRunning-=1 + if [ $i -eq 1 ]; then + # The first one succeeded, open up the flood gates. + maxNumRunning=$MaxDeletesRunning + fi + fi + done + # + # Now that we have queued them all up, wait for them to finish. + wait -n + rc=$? + let numRunning-=1 + while [ "$rc" != 127 ]; do + printf "\rTotal number of volumes to delete: ${numVolumes}. Number of deletes currently running: ${numRunning}. Number waiting to be started: $((numVolumes-i)). " + if [ "$rc" != 0 ]; then + printf "\nError, one of the volume deletes failed. Aborting!\n" 1>&2 + exit 1 + fi + wait -n + rc=$? + let numRunning-=1 + done + echo "" +fi +# +# Now that all the volumes have been deleted, delete the storage virtual machine. aws fsx delete-storage-virtual-machine --region=$region --storage-virtual-machine-id $svmID > $tmpout 2>&1 if [ $? != "0" ]; then echo "Failed to delete storage virtual machine." 1>&2 - cat $tmpout + cat $tmpout 1>&2 exit 1 else status=$(jq -r .Lifecycle $tmpout) if [ "$status" == "DELETING" ]; then - echo "Storage Virtual Machine with an id of '$svmID' is being deleted." - exit 0 + echo -n "Storage Virtual Machine with an id of '$svmID' is being deleted." + # + # Wait for the svm to be deleted. + if [ $waitForDelete == "true" ]; then + i=0 + while [ $i -lt $MaxIterations ]; do + aws fsx describe-storage-virtual-machines --storage-virtual-machine-ids $svmID --output=json --region=$region > $tmpout 2>&1 + if [ $? -eq 0 ]; then + status=$(jq -r '.StorageVirtualMachines[0].Lifecycle' $tmpout 2> /dev/null) + if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then + printf "\nError, failed to delete SVM with SVM ID '$svmID'. Status = $status\n" 1>&2 + cat $tmpout 1>&2 + exit 1 + else + printf "." + fi + else + # Assume if it failed, it is because the SVM was delted and therefore doesn't exist anymore. + printf "\nStorage Virtual Machine with an id of '$svmID' has been deleted.\n" + break + fi + sleep $SleepTime + let i+=1 + done + if [ $i -ge $MaxIterations ]; then + printf "\nFailed to delete SVM with SVM ID of '$svmID'. Taking too long.\n" 1>&2 + exit 1 + fi + exit 0 + else + echo + fi else echo "Unknown status '$status'. Complete output returned from the AWS api:" cat $tmpout diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume index b164aff..fa8619d 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume @@ -20,15 +20,51 @@ ################################################################################ usage () { cat 1>&2 < $tmpout 2>&1 + if [ $? -eq 0 ]; then + status=$(jq -r .Volumes[0].Lifecycle $tmpout 2> /dev/null) + if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then + printf "\nError, failed to delete volume with volume ID '$volumeId'. Status = ${status}.\n" 1>&2 + cat $tmpout 1>&2 + return 1 + fi + else + # Assume if it failed, it is because the volume was deleted and doesn't exist anymore. + break + fi + [ $quiet != "true" ] && printf "." + sleep $SleepTime + let i+=1 + done + if [ $i -ge $MaxIterations ]; then + printf "\nFailed to delete volume with volume ID of '$volumeId'. Taking too long.\n" 1>&2 + return 1 + fi + return 0 +} + ################################################################################ # Main logic starts here. ################################################################################ @@ -37,10 +73,12 @@ trap 'rm -f $tmpout' exit # # Set some defaults. region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') +skipBackup=true +waitForCompletion=false +quiet=false # # Process command line arguments. -skipBackup=true -while getopts "hbi:r:" option; do +while getopts "qhwbi:r:" option; do case $option in r) region="$OPTARG" ;; @@ -48,10 +86,21 @@ while getopts "hbi:r:" option; do ;; b) skipBackup=false ;; + w) waitForCompletion=true + ;; + q) quiet=true + ;; *) usage ;; esac done + +if which jq aws > /dev/null 2>&1; then + : +else + echo "Error, both 'jq' and 'aws' are required to run this script." 1>&2 + exit 1 +fi # # Ensure all the required parameters have been provided. if [ -z "$volumeId" ]; then @@ -68,11 +117,18 @@ if [ $? != "0" ]; then else status=$(jq -r .Lifecycle $tmpout 2> /dev/null) if [ "$status" == "DELETING" -o "$status" == "PENDING" ]; then - echo "Volume '$volumeId' is being deleted." - exit 0 + [ $quiet != "true" ] && printf "Volume '$volumeId' is being deleted." + if [ "$waitForCompletion" == "true" ]; then + waitForVolumeDelete $volumeId + if [ $? -ne 0 ]; then + exit 1 + fi + [ $quiet != "true" ] && printf "\n" + fi else echo "Unknown status '$status'. Complete output returned from the AWS api:" 1>&2 cat $tmpout 1>&2 exit 1 fi fi +exit 0 From 277b9c3a5df22926168ce8ad0cde903380b3ac62 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Thu, 3 Oct 2024 06:44:55 -0500 Subject: [PATCH 02/10] Fixed a typo in a comment. --- .../fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem index d24aff0..aa8f61c 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem @@ -41,7 +41,7 @@ EOF ################################################################################ # This function is used to display the contents of a FSxN file system based on # the file system ID passed as the first and only argument. It assumes that -# the svmsFile and volumesFile fles have already been created. +# the svmsFile and volumesFile files have already been created. ################################################################################ displayFileSystemContents() { From 80eb0beb50d75ac3dc2d8dbe03989471528ec5d6 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Thu, 3 Oct 2024 13:43:09 -0500 Subject: [PATCH 03/10] Corrected some spelling errors. --- .../fsx-ontap-aws-cli-scripts/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md index 890dfbe..66951e4 100644 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md @@ -14,17 +14,17 @@ Before running the UNIX based scripts, make sure the following package is instal | Script | Description | |:------------------------|:----------------| -|create_fsxn_filesystem | Creates a new FSx for NetApp ONTAP file-system. | -|create_fsxn_svm | Creates a new Storage Virtual Server (SVM) in a soecific FSx ONTAP filesystem. | +|create_fsxn_filesystem | Creates a new FSx for NetApp ONTAP file system. | +|create_fsxn_svm | Creates a new Storage Virtual Server (SVM) in a specified FSx for ONTAP file system. | |create_fsxn_volume | Creates a new volume under a specified SVM. | -|list_fsx_filesystems | List all the FSx for NetApp ONTAP filesystems that the user has access to. | -|list_fsx_filesystems.ps1 | List all the FSx for NetApp ONTAP filesystems that the user has access to, written in PowerShell. | +|list_fsx_filesystems | List all the FSx for NetApp ONTAP file systems that the user has access to. | +|list_fsx_filesystems.ps1 | List all the FSx for NetApp ONTAP file systems that the user has access to, written in PowerShell. | |list_fsxn_volumes | List all the FSx for NetApp ONTAP volumes that the user has access to. | |list_fsxn_svms | List all the storage virtual machines that the user access to. | -|list_aws_subnets | List all the aws subnets. | -|list_aws_vpcs | List all the aws VPCs. | -|delete_fsxn_filesystem | Deletes an FSx for NetApp ONTAP filesystem. Including all the SVMs and volumes on it. | -|delete_fsxn_svm | Deletes an svm. Including all the volumes assigned to it. | +|list_aws_subnets | List all the AWS subnets. | +|list_aws_vpcs | List all the AWS VPCs. | +|delete_fsxn_filesystem | Deletes an FSx for ONTAP file system. Including all the SVMs and volumes on it. | +|delete_fsxn_svm | Deletes an SVM. Including all the volumes assigned to it. | |delete_fsxn_volume | Deletes a volume. | From 685b981d38482c527e73bf4548d39bb7f74c4cea Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Thu, 3 Oct 2024 13:50:31 -0500 Subject: [PATCH 04/10] Corrected some spelling errors. --- Management-Utilities/fsx-ontap-aws-cli-scripts/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md index 66951e4..056f139 100644 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/README.md @@ -23,9 +23,9 @@ Before running the UNIX based scripts, make sure the following package is instal |list_fsxn_svms | List all the storage virtual machines that the user access to. | |list_aws_subnets | List all the AWS subnets. | |list_aws_vpcs | List all the AWS VPCs. | -|delete_fsxn_filesystem | Deletes an FSx for ONTAP file system. Including all the SVMs and volumes on it. | -|delete_fsxn_svm | Deletes an SVM. Including all the volumes assigned to it. | -|delete_fsxn_volume | Deletes a volume. | +|delete_fsxn_filesystem | Deletes a specified FSx for ONTAP file system. Including all the SVMs and volumes on it. | +|delete_fsxn_svm | Deletes a specified SVM. Including all the volumes assigned to it. | +|delete_fsxn_volume | Deletes a specified volume. | ## Author Information From 175dbe43e528fbab3b6e2da8675f721e1af69a4b Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 12:08:01 -0500 Subject: [PATCH 05/10] Made them handle a failure message from AWS better. --- .../fsx-ontap-aws-cli-scripts/create_fsxn_filesystem | 7 ++++++- .../fsx-ontap-aws-cli-scripts/create_fsxn_svm | 7 ++++++- .../fsx-ontap-aws-cli-scripts/create_fsxn_volume | 7 ++++++- .../fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem | 7 ++++++- .../fsx-ontap-aws-cli-scripts/delete_fsxn_svm | 7 ++++++- .../fsx-ontap-aws-cli-scripts/delete_fsxn_volume | 7 ++++++- 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem index f0cd4e0..db1bf75 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem @@ -180,7 +180,12 @@ else fi if [ "$status" != "CREATING" -a "$status" != "PENDING" ]; then printf "\nError, failed to create the file system. Status = $status\n" 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.FileSystems[0].LifecycleTransitionReason.Message' $tmpout 2> /dev/null)" + if [ ! -z "$reason" ]; then + echo "Reason: $reason" 1>&2 + else + cat $tmpout 1>&2 + fi exit 1 fi printf "." diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm index 74cb055..aa16246 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_svm @@ -116,7 +116,12 @@ else fi if [ "$status" != "CREATING" -a "$status" != "PENDING" ]; then printf "\nError, failed to create SVM with SVM ID '$svmId'. Status = $status\n" 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.StorageVirtualMachines[0].LifecycleTransitionReason.Message' $tmpout)" + if [ ! -z "$reason" ]; then + echo "Reason: $reason" 1>&2 + else + cat $tmpout 1>&2 + fi exit 1 fi else diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume index 9577ffd..62f69a7 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume @@ -105,7 +105,12 @@ else fi if [ $status != "CREATING" -a $status != "PENDING" ]; then echo "Error, volume $volumeId creation failed." 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.Volumes[0].LifecycleTransitionReason.Message' $tmpout 2> /dev/null)" + if [ -n "$reason" ]; then + echo "Reason: $reason" 1>&2 + else + cat $tmpout 1>&2 + fi exit 1 fi echo -n "." diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem index aa8f61c..39a0750 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_filesystem @@ -213,7 +213,12 @@ else status=$(jq -r '.FileSystems[0].Lifecycle' $tmpout 2> /dev/null) if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then printf "\nError, failed to delete file system with file system ID '$fsid'. Status = $status\n" 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.FileSystems[0].LifecycleTransitionReason.Message' $tmpout 2> /dev/null)" + if [ ! -z "$reason" ]; then + printf "Reason: $reason\n" 1>&2 + else + cat $tmpout 1>&2 + fi exit 1 else printf "." diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm index 2ed7ca1..aad0270 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_svm @@ -209,7 +209,12 @@ else status=$(jq -r '.StorageVirtualMachines[0].Lifecycle' $tmpout 2> /dev/null) if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then printf "\nError, failed to delete SVM with SVM ID '$svmID'. Status = $status\n" 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.StorageVirtualMachines[0].LifecycleTransitionReason.Message' $tmpout 2> /dev/null)" + if [ ! -z "$reason" ]; then + echo "Reason: $reason" 1>&2 + else + cat $tmpout 1>&2 + fi exit 1 else printf "." diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume index fa8619d..e372fce 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume @@ -47,7 +47,12 @@ waitForVolumeDelete () { status=$(jq -r .Volumes[0].Lifecycle $tmpout 2> /dev/null) if [ "$status" != "DELETING" -a "$status" != "PENDING" ]; then printf "\nError, failed to delete volume with volume ID '$volumeId'. Status = ${status}.\n" 1>&2 - cat $tmpout 1>&2 + reason="$(jq -r '.Volumes[0].LifecycleTransitionReason.Message' $tmpout 2> /dev/null)" + if [ ! -z "$reason" ]; then + echo "Reason: $reason" 1>&2 + else + cat $tmpout 1>&2 + fi return 1 fi else From 60a61afdb795c304bd102ef8421ef20e8d487417 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 17:24:29 -0500 Subject: [PATCH 06/10] Fixed a bug where they weren't honoring the -r option. --- .../fsx-ontap-aws-cli-scripts/list_aws_subnets | 4 ++-- Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_vpcs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_subnets b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_subnets index 66be940..dc8ebe5 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_subnets +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_subnets @@ -51,8 +51,8 @@ for region in $regions; do printf "\nRegion: $region\n" fi if [ -z "$vpcId" ]; then - aws ec2 describe-subnets | jq -r '.Subnets[] | .VpcId + "," + .SubnetId + "," + .CidrBlock + "," + (first(.Tags[] | select(.Key == "Name").Value) // "")' | awk -F, 'BEGIN {formatStr="%21s %24s %18s %s\n"; printf(formatStr, "VPC Id", "Subnet ID", "CIDR", "Name")} {printf(formatStr , $1, $2, $3, $4)}' + aws ec2 describe-subnets --region=$region | jq -r '.Subnets[] | .VpcId + "," + .SubnetId + "," + .CidrBlock + "," + (if(has("Tags")) then first(.Tags[] | select(.Key == "Name").Value) // "" else "" end)' | awk -F, 'BEGIN {formatStr="%21s %24s %18s %s\n"; printf(formatStr, "VPC Id", "Subnet ID", "CIDR", "Name")} {printf(formatStr , $1, $2, $3, $4)}' else - aws ec2 describe-subnets --filters '[{"Name": "vpc-id", "Values": ["'$vpcId'"]}]' | jq -r '.Subnets[] | .VpcId + "," + .SubnetId + "," + .CidrBlock + "," + (first(.Tags[] | select(.Key == "Name").Value) // "")' | awk -F, 'BEGIN {formatStr="%21s %24s %18s %s\n"; printf(formatStr, "VPC Id", "Subnet ID", "CIDR", "Name")} {printf(formatStr , $1, $2, $3, $4)}' + aws ec2 describe-subnets --region=$region --filters '[{"Name": "vpc-id", "Values": ["'$vpcId'"]}]' | jq -r '.Subnets[] | .VpcId + "," + .SubnetId + "," + .CidrBlock + "," + (if(has("Tags")) then first(.Tags[] | select(.Key == "Name").Value) // "" else "" end)' | awk -F, 'BEGIN {formatStr="%21s %24s %18s %s\n"; printf(formatStr, "VPC Id", "Subnet ID", "CIDR", "Name")} {printf(formatStr , $1, $2, $3, $4)}' fi done diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_vpcs b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_vpcs index 3ecdc96..c35176a 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_vpcs +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_aws_vpcs @@ -59,7 +59,7 @@ vpcFormatStr="%21s %19s %s\n" for region in $regions; do [ "$quiet" != "True" ] && printf "\nRegion: $region\n" first=True - aws ec2 describe-vpcs --region $region | jq -r '.Vpcs[] | .VpcId + " " + .CidrBlock + " " + (if (.Tags != null) then (.Tags[] | (select(.Key == "Name") .Value)) else "" end)' | \ + aws ec2 describe-vpcs --region=$region | jq -r '.Vpcs[] | .VpcId + " " + .CidrBlock + " " + (if (has("Tags")) then .Tags[] | (select(.Key == "Name") .Value) else "" end)' | \ while read vpcId cidr name; do if [ "$quiet" != "True" -a "$first" == "True" ]; then printf "\n$vpcFormatStr" "VPC IP" "CIDR" "Name" @@ -69,7 +69,7 @@ for region in $regions; do if [ "$subnets" == "True" ]; then printf "\n\tSubnets:\n" - aws ec2 describe-subnets --filters '[{"Name": "vpc-id", "Values": ["'$vpcId'"]}]' | jq -r '.Subnets[] | .VpcId + " " + .SubnetId + " " + .CidrBlock + " " + (first(.Tags[] | select(.Key == "Name").Value) // "")' | awk 'BEGIN {formatStr="\t\t%24s %18s %s\n"; printf(formatStr, "Subnet ID", "CIDR", "Name")} {name=$4; for (i=5; i<=NF; i++) {name=name " " $(i)}; printf(formatStr , $2, $3, name)}' + aws ec2 describe-subnets --region=$region --filters '[{"Name": "vpc-id", "Values": ["'$vpcId'"]}]' | jq -r '.Subnets[] | .VpcId + " " + .SubnetId + " " + .CidrBlock + " " + (if(has("Tags")) then first(.Tags[] | select(.Key == "Name").Value) // "" else "" end)' | awk 'BEGIN {formatStr="\t\t%24s %18s %s\n"; printf(formatStr, "Subnet ID", "CIDR", "Name")} {name=$4; for (i=5; i<=NF; i++) {name=name " " $(i)}; printf(formatStr , $2, $3, name)}' first=True fi done From 8beac4571c831bef6881f7d7d0b0c793397e460a Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 17:26:00 -0500 Subject: [PATCH 07/10] Fixed a bug where it wouldn't exit if it couldn't find the filesystemID based on the name passed via the -f option. --- .../fsx-ontap-aws-cli-scripts/list_fsxn_svms | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_fsxn_svms b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_fsxn_svms index 26b7d64..a5c199f 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/list_fsxn_svms +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/list_fsxn_svms @@ -101,7 +101,11 @@ else fi if [ ! -z "$fileSystemName" ]; then - fileSystemID=$(aws fsx describe-file-systems --output=json 2> /dev/null | jq -r '.FileSystems[] | if((.Tags[] | select(.Key == "Name") .Value) == "'"${fileSystemName}"'") then .FileSystemId else empty end' 2> /dev/null) + fileSystemID=$(aws fsx describe-file-systems --output=json --region=$region 2> /dev/null | jq -r '.FileSystems[] | if((.Tags[] | select(.Key == "Name") .Value) == "'"${fileSystemName}"'") then .FileSystemId else empty end' 2> /dev/null) + if [ -z "$fileSystemID" ]; then + echo "Error, failed to find a file system with the name '$fileSystemName'. Maybe in a different region?" 1>&2 + exit 1 + fi fi # # Loop on all the regions. From 83c82fe9d2b5fe61e5fdb04583ee757e3ca3c3c0 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 17:29:32 -0500 Subject: [PATCH 08/10] Added support for Gen2 and Scale-Out. --- .../create_fsxn_filesystem | 116 ++++++++++++++---- .../create_fsxn_volume | 46 +++++-- .../delete_fsxn_volume | 2 + 3 files changed, 126 insertions(+), 38 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem index db1bf75..baf58d7 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem @@ -20,18 +20,19 @@ ################################################################################ usage () { cat 1>&2 < /dev/null 2>&1; then @@ -65,7 +89,8 @@ throughput=128 region=$(aws configure list | egrep '^.*egion ' | awk '{print $2}') securityGroupOption="" endpointips="" -azType="MULTI_AZ_1" +availType=multi +numPairs=1 waitForCompletion=false # # Process command line arguments. @@ -78,13 +103,10 @@ while [ ! -z "$1" ]; do shift ;; -size|--size) size="$2" - if ! [[ "$size" =~ '^[0-9]+$' ]]; then + if ! [[ "$size" =~ $integerRegEx ]]; then echo "-size must be an integer." usage fi - if [ "$size" -le 1024 ]; then - usage - fi shift ;; -subnetid1|--subnetid1) subnetID1="$2" @@ -97,31 +119,31 @@ while [ ! -z "$1" ]; do shift ;; -type|--type) - if [ "$(echo $2 | tr [A-Z] [a-z])" == "single" ]; then - azType="SINGLE_AZ_1" - elif [ "$(echo $2 | tr [A-Z] [a-z])" == "multi" ]; then - azType="MULTI_AZ_1" - else - echo "Error, known availability type '$2'." + availType=$2 + if [ $availType != "single" -a $availType != "multi" ]; then + echo "-type must be 'single' or 'multi'." 1>&2 usage fi shift ;; -throughput|--throughput) throughput="$2" - if ! [[ "$throughput" =~ '^[0-9]+$' ]]; then + if ! [[ "$throughput" =~ $integerRegEx ]]; then echo "-throughput must be an integer." usage fi - if [ "$througput" != "128" -a "$througput" != "256" -a "$throughput" != "512" -a "$throughput" != "1024" -a "$throughput" != "2048" -a "$throughput" != "4096" ]; then - echo "-throughput must be 128 or 256 or 512 or 1024 or 2048 or 4096." - usage - fi shift ;; -endpointiprange|--endpointiprange) endpointips='"EndpointIpAddressRange": "'$2'",' shift ;; + -numberpairs|--numberpairs) numPairs="$2" + if ! [[ "$numPairs" =~ $integerRegEx ]]; then + echo "-numPairs must be an integer." + usage + fi + shift + ;; -wait|--wait) waitForCompletion=true ;; @@ -134,16 +156,39 @@ while [ ! -z "$1" ]; do esac shift done + +if is_in "$throughput" ${throughputValuesGen1[@]}; then + if [ $availType="single" ]; then + azType="SINGLE_AZ_1" + elif [ $availType="multi" ]; then + azType="MULTI_AZ_1" + else + echo "Error, unknown availability type '$availType'." + usage + fi +elif is_in "$throughput" ${throughputValuesGen2[@]}; then + if [ $availType="single" ]; then + azType="SINGLE_AZ_2" + elif [ $availType="multi" ]; then + azType="MULTI_AZ_2" + else + echo "Error, unknown availability type '$availType'." + usage + fi +else + echo "Error, unsupported throughput value '$throughput'." + usage +fi # # Ensure all the required parameters have been provided. -if [ -z "$fileSystemName" -o -z "$subnetID1" -o "$azType" == "MULTI_AZ_1" -a -z "$subnetID2" ]; then +if [ -z "$fileSystemName" -o -z "$subnetID1" -o "$azType" == "MULTI_AZ_1" -a -z "$subnetID2" -o "$azType" == "MULTI_AZ_2" -a -z "$subnetID2" ]; then echo "Missing arguments." 1>&2 usage - exit 1 fi -if [ $azType == "SINGLE_AZ_1" ]; then + +if [[ $azType == *"SINGLE_AZ"* ]]; then if [ ! -z "$endpointips" ]; then - echo "Error, you can not specify Endpoint IP address range when deploying in a single availability zone." 1>&2 + echo "Error, you cannot specify Endpoint IP address range when deploying in a single availability zone." 1>&2 exit 1 fi @@ -153,11 +198,30 @@ if [ $azType == "SINGLE_AZ_1" ]; then fi fi +if [ $numPairs -gt 1 ]; then + if [ $azType != "SINGLE_AZ_2" ]; then + echo "Error, you can only specify more than one HA pair with a single availability zone deployment." 1>&2 + usage + fi + + if ! is_in "$throughput" ${throughputValuesMultiHAPairs[@]}; then + echo "Error, you can only specify more than one HA pair with throughput values of 1536, 3072, and 6144." 1>&2 + usage + fi +fi + +minSize=$((1024*numPairs)) +if [ $size -lt $minSize ]; then + echo "Error, the size must be at least $minSize for $numPairs HA pairs. In other words 1024 per HA pair." 1>&2 + usage +fi + aws fsx create-file-system --output=json --file-system-type ONTAP --storage-capacity $size --subnet-ids $subnetID1 $subnetID2 --storage-type SSD --tags "Key=Name,Value=$fileSystemName" $securityGroupOption --ontap-configuration '{ "PreferredSubnetId": "'$subnetID1'", '$endpointips' "DeploymentType": "'$azType'", - "ThroughputCapacity": '$throughput'}' --region=$region > $tmpout 2>&1 + "HAPairs": '$numPairs', + "ThroughputCapacityPerHAPair": '$throughput'}' --region=$region > $tmpout 2>&1 if [ $? != "0" ]; then echo "Failed to create FSxN file system." 1>&2 diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume index 62f69a7..d16bda6 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_volume @@ -21,12 +21,14 @@ ################################################################################ usage () { cat 1>&2 <&2 + usage + fi + ;; + v) volumeStyle=$OPTARG + ;; + a) aggregateOption='"AggregateConfiguration":{"Aggregates":["'$OPTARG'"]},' ;; w) waitForCompletion=true ;; @@ -75,15 +89,23 @@ if [ -z "$volumeName" -o -z "$svmId" ]; then usage fi -aws fsx create-volume --volume-type ONTAP --name $volumeName --ontap-configuration "{ - \"JunctionPath\": \"/$volumeName\", - \"SecurityStyle\": \"UNIX\", - \"SizeInMegabytes\" : $size, - \"StorageEfficiencyEnabled\": true, - \"StorageVirtualMachineId\": \"$svmId\", - \"TieringPolicy\" : {\"CoolingPeriod\": 31, \"Name\": \"SNAPSHOT_ONLY\"}, - \"OntapVolumeType\": \"RW\", - \"SnapshotPolicy\": \"default\"}" --region=$region --output=json > $tmpout 2>&1 +volumeStyle=$(echo $volumeStyle | tr '[a-z] ' '[A-Z]') +if [ $volumeStyle != "FLEXVOL" -a $volumeStyle != "FLEXGROUP" ]; then + echo "Error, volume style must be either FlexVol or FlexGroup." 1>&2 + usage +fi + +aws fsx create-volume --volume-type ONTAP --name $volumeName --ontap-configuration '{ + "JunctionPath": "/'$volumeName'", + "SecurityStyle": "UNIX", + "SizeInMegabytes" : '$size', + "StorageEfficiencyEnabled": true, + "StorageVirtualMachineId": "'$svmId'", + "TieringPolicy" : {"CoolingPeriod": 31, "Name": "SNAPSHOT_ONLY"}, + "OntapVolumeType": "RW", + "VolumeStyle": "'$volumeStyle'", + '$aggregateOption' + "SnapshotPolicy": "default"}' --region=$region --output=json > $tmpout 2>&1 if [ $? != "0" ]; then echo "Failed to create the FSxN volume." 1>&2 @@ -93,7 +115,7 @@ else status=$(jq -r .Volume.Lifecycle $tmpout 2> /dev/null) if [ "$status" == "CREATING" -o "$status" == "PENDING" ]; then volumeId=$(jq -r .Volume.VolumeId $tmpout) - printf "FSxN volume '$volumeName'($volumeId) is being created." + printf "Volume '$volumeName'($volumeId) is being created." if [ "$waitForCompletion" == "true" ]; then i=0 while [ $i -lt $maxIterations ]; do diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume index e372fce..31d2144 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/delete_fsxn_volume @@ -129,6 +129,8 @@ else exit 1 fi [ $quiet != "true" ] && printf "\n" + else + [ $quiet != "true" ] && printf "\n" fi else echo "Unknown status '$status'. Complete output returned from the AWS api:" 1>&2 From 20b877433da5b712faeba344730861c6c542fac6 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 17:53:26 -0500 Subject: [PATCH 09/10] Added support for Gen2 and scale-out. --- .../create_fsxn_filesystem | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem index baf58d7..4f468ab 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem @@ -66,7 +66,7 @@ is_in(){ local value=$1 shift - for i in $@; do + for i in "$@"; do if [ $i == $value ]; then return 0 fi @@ -157,8 +157,8 @@ while [ ! -z "$1" ]; do shift done -if is_in "$throughput" ${throughputValuesGen1[@]}; then - if [ $availType="single" ]; then +if is_in "$throughput" "${throughputValuesGen1[@]}"; then + if [ $availType == "single" ]; then azType="SINGLE_AZ_1" elif [ $availType="multi" ]; then azType="MULTI_AZ_1" @@ -166,10 +166,10 @@ if is_in "$throughput" ${throughputValuesGen1[@]}; then echo "Error, unknown availability type '$availType'." usage fi -elif is_in "$throughput" ${throughputValuesGen2[@]}; then - if [ $availType="single" ]; then +elif is_in "$throughput" "${throughputValuesGen2[@]}"; then + if [ $availType == "single" ]; then azType="SINGLE_AZ_2" - elif [ $availType="multi" ]; then + elif [ $availType == "multi" ]; then azType="MULTI_AZ_2" else echo "Error, unknown availability type '$availType'." @@ -181,8 +181,13 @@ else fi # # Ensure all the required parameters have been provided. -if [ -z "$fileSystemName" -o -z "$subnetID1" -o "$azType" == "MULTI_AZ_1" -a -z "$subnetID2" -o "$azType" == "MULTI_AZ_2" -a -z "$subnetID2" ]; then - echo "Missing arguments." 1>&2 +if [ -z "$fileSystemName" ]; then + echo "Error, you must specify a file system name." 1>&2 + usage +fi + +if [ -z "$subnetID1" -o "$azType" == "MULTI_AZ_1" -a -z "$subnetID2" -o "$azType" == "MULTI_AZ_2" -a -z "$subnetID2" ]; then + echo "Error, you must specify only subnetID1 for a single availability zone deployments or both subnetID1 and subnetID2 for a multi availability zone deployments." 1>&2 usage fi @@ -199,13 +204,13 @@ if [[ $azType == *"SINGLE_AZ"* ]]; then fi if [ $numPairs -gt 1 ]; then - if [ $azType != "SINGLE_AZ_2" ]; then - echo "Error, you can only specify more than one HA pair with a single availability zone deployment." 1>&2 + if ! is_in "$throughput" "${throughputValuesMultiHAPairs[@]}"; then + echo "Error, you can only specify more than one HA pair with throughput values of 1536, 3072, and 6144." 1>&2 usage fi - if ! is_in "$throughput" ${throughputValuesMultiHAPairs[@]}; then - echo "Error, you can only specify more than one HA pair with throughput values of 1536, 3072, and 6144." 1>&2 + if [ $azType != "SINGLE_AZ_2" ]; then + echo "Error, you can only specify more than one HA pair with a single availability zone deployment." 1>&2 usage fi fi @@ -216,13 +221,14 @@ if [ $size -lt $minSize ]; then usage fi -aws fsx create-file-system --output=json --file-system-type ONTAP --storage-capacity $size --subnet-ids $subnetID1 $subnetID2 --storage-type SSD --tags "Key=Name,Value=$fileSystemName" $securityGroupOption --ontap-configuration '{ +echo aws fsx create-file-system --output=json --file-system-type ONTAP --storage-capacity $size --subnet-ids $subnetID1 $subnetID2 --storage-type SSD --tags "Key=Name,Value=$fileSystemName" $securityGroupOption --ontap-configuration '{ "PreferredSubnetId": "'$subnetID1'", '$endpointips' "DeploymentType": "'$azType'", "HAPairs": '$numPairs', - "ThroughputCapacityPerHAPair": '$throughput'}' --region=$region > $tmpout 2>&1 - + "ThroughputCapacityPerHAPair": '$throughput'}' --region=$region +# "ThroughputCapacityPerHAPair": '$throughput'}' --region=$region > $tmpout 2>&1 +exit if [ $? != "0" ]; then echo "Failed to create FSxN file system." 1>&2 cat $tmpout 1>&2 From 50155f184a066df39d20f87c27314df4fe7c0e85 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Fri, 4 Oct 2024 17:59:15 -0500 Subject: [PATCH 10/10] Added support for Gen2 and scale-out. --- .../fsx-ontap-aws-cli-scripts/create_fsxn_filesystem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem index 4f468ab..3a33901 100755 --- a/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem +++ b/Management-Utilities/fsx-ontap-aws-cli-scripts/create_fsxn_filesystem @@ -160,7 +160,7 @@ done if is_in "$throughput" "${throughputValuesGen1[@]}"; then if [ $availType == "single" ]; then azType="SINGLE_AZ_1" - elif [ $availType="multi" ]; then + elif [ $availType == "multi" ]; then azType="MULTI_AZ_1" else echo "Error, unknown availability type '$availType'."