From 45df4d8de24f7a5f4ee62d4e4fd0d2d083c77778 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Tue, 24 Mar 2026 22:26:29 -0500 Subject: [PATCH 1/5] Added support for other Linux distributions. --- .../EC2-cloud_formation.yaml | 9 +- .../README.md | 32 +- .../build_linux_userData | 69 +++ .../linux_userData.sh | 528 +++++------------- .../linux_userData_real.sh | 447 +++++++++++++++ 5 files changed, 675 insertions(+), 410 deletions(-) create mode 100755 Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData create mode 100755 Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml index d6cdacf..b4f0ffe 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml @@ -61,7 +61,7 @@ Metadata: SvmName: default: "SVM Name" Username: - default: "Username" + default: "ONTAP Username" DriveLetter: default: "Drive Letter (Windows Only)" CidrIp: @@ -115,14 +115,15 @@ Parameters: Description: SVM Name Username: Type: String - Description: Username to run under + Description: Username to run ONTAP APIs as. + Default: fsxadmin DriveLetter: Type: String Default: d Description: Drive Letter - valid for Windows only CidrIp: Type: String - Description: CIDR IP for SSH access to the instance + Description: CIDR IP for SSH or RDP access to the instance. LinuxUserDataUrl: Type: String Default: https://raw.githubusercontent.com/NetApp/FSx-ONTAP-samples-scripts/refs/heads/main/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh @@ -219,4 +220,4 @@ Resources: Outputs: InstanceId: Description: EC2 Instance ID - Value: !Ref MyEC2Instance \ No newline at end of file + Value: !Ref MyEC2Instance diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md index 920b86c..9856745 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md @@ -9,7 +9,12 @@ volume and LUN, mount it to the instance, while installing all the needed librar This means that usuable volume size is 90% of the requestd size. - The process might take several minutes to be compleetd. -## Set Up +## Deployment +There are two ways to deploy an EC2 instance with the needed user data script: +1. Copy the CloudFormation template found in the repo [EC2-cloud_formation.yaml](EC2-cloud_formation.yaml) to you local machine and deploy a CLoudFormation stack using it. CloudFormation will prmopt you for all the required parameters. +2. Follow the instruction below to deploy an EC2 instance from the AWS console. + +## AWS console deployment preparation 1. Create an AWS SecretsManager secret to hold the password of the account you plan to use to authenicate to the FSxN file system with. The secret should be of type `other` with value set to `Plain Text` that holds just the password. 2. Create an AWS IAM role that has EC2 as the trusted entity and has permissions to read the secret value. Here is an example policy that will do that: @@ -33,11 +38,10 @@ The secret should be of type `other` with value set to `Plain Text` that holds j 3. Download the needed script according to the instance type you want to run (Linux or Windows). For the Linux version of the script, set the following values at the top of it: - - SECRET_NAME - Secret name has has the password for the `ONTAP-USER`. - - AWS_REGION - AWS secret manager region. + - SECRET_ARN - The ARN of the secret that has the password for the `ONTAP-USER`. - FSXN_ADMIN_IP - IP address, or hostname, of the FSxN management endpoint. - VOLUME_NAME - The name of the volume you want to create in your FSxN. - - VOLUME_SIZE - The size of the volume you want to create in GB e.g [100g] + - VOLUME_SIZE - The size of the volume you want to create in GB e.g [100] - SVM_NAME - The name of the SVM where the volume is to be created. - ONTAP_USER - The ONTAP user id you wish to authenicate with. @@ -60,7 +64,7 @@ The secret should be of type `other` with value set to `Plain Text` that holds j
  1. Fill in the server name.
  2. Select 'Amazon Linux'.
  3. -
  4. Under Amazon Machine Image select 'Amazon Linux 2023 AMI'.
  5. +
  6. Under Amazon Machine Image select the Linux distrubution of your choice. The supported disibutions are: `Amazon Linux 2023 AMI`, `Ubuntu`, `Red Hat` and `Debian`
  7. Fill in the other settings based on your networking and business needs.
  8. Under 'Advanced details':
      @@ -73,7 +77,7 @@ The secret should be of type `other` with value set to `Plain Text` that holds j
    1. Launch the instance.
    -The installation log file can be found at: `/home/ec2-user/install.log`. +The installation log file can be found at: `/var/log/iscsi-install.log`. If an error occurs while the installation is running, the script will terminate and all installations and setup will roll back. ### For Windows installation: @@ -99,3 +103,19 @@ The installation log file can be found at: `C:\Users\Administrator\install.log`. If an error occurs while the installation is running, a message will be inserted into the installation log file, it will attempt to roll back any work that it preformed, finally the script will terminate. **Note:** It can take 20 to 30 minutes for the script to compplete. Check the installation log file to confirm it is done. The line `Uninstall script removed` should be at the bottom of the file when the script has finished. + +## Author Information + +This repository is maintained by the contributors listed on [GitHub](https://github.com/NetApp/FSx-ONTAP-samples-scripts/graphs/contributors). + +## License + +Licensed under the Apache License, Version 2.0 (the "License"). + +You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an _"AS IS"_ basis, without WARRANTIES or conditions of any kind, either express or implied. + +See the License for the specific language governing permissions and limitations under the License. + +© 2026 NetApp, Inc. All Rights Reserved. diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData new file mode 100755 index 0000000..4db3e56 --- /dev/null +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Since, for some reason, the maximum size of a EC2 User Data script is +# 16KB we have to compress the real script, with some logic to uncompress +# it on the EC2 instance when it is deployed, and then pass that as the +# user data content. +# +# This script is used to create the linux_userData.sh script from the +# linux_userdata_real.sh file. +################################################################################ + +cat <<'EOF' > linux_userData.sh +#!/bin/bash +# +# Set the ARN of the secret that should contain just the password for the ONTAP admin user set below. +SECRET_ARN="" +# +# Set the FSx admin IP. +FSXN_ADMIN_IP="" +# +# Set the name of the volume to be created on the FSx for ONTAP file system. Note, volume names cannot have dashes in them. +VOLUME_NAME="" +# +# Set the volume size in GB. It should just be a number, without the 'GB' suffix. +VOLUME_SIZE= +# +# Set the SVM name. The default is 'fsx'. +SVM_NAME="fsx" +# +# Set the ONTAP admin user. The default is fsxadmin. +ONTAP_USER="fsxadmin" +# +################################################################################ +# **** You should not need to edit anything below this line **** +################################################################################ +# +# When called from the CloudFormation template, the parameters are passsed as +# arguments. +SECRET_ARN="${SECRET_ARN:=$1}" +FSXN_ADMIN_IP="${FSXN_ADMIN_IP:=$2}" +VOLUME_NAME="${VOLUME_NAME:=$3}" +VOLUME_SIZE="${VOLUME_SIZE:=$4}" +SVM_NAME="${5:-$SVM_NAME}" +ONTAP_USER="${6:-$ONTAP_USER}" +# +# Since AWS only allows up to 16KB for the user data script, the rest of this script +# will be the compressed version of the linux_userData_real.sh file, which will be +# uncompressed and executed on the EC2 instance when it is deployed. +cat < /tmp/linux_userData.sh +#!/bin/bash +export SECRET_ARN="$SECRET_ARN" +export FSXN_ADMIN_IP="$FSXN_ADMIN_IP" +export VOLUME_NAME="$VOLUME_NAME" +export VOLUME_SIZE="$VOLUME_SIZE" +export SVM_NAME="$SVM_NAME" +export ONTAP_USER="$ONTAP_USER" +EOF2 + +cat <> /tmp/linux_userData.sh +EOF + +cat linux_userData_real.sh | gzip -c | base64 >> linux_userData.sh + +cat <> linux_userData.sh +EOF3 + +chmod +x /tmp/linux_userData.sh +/tmp/linux_userData.sh +EOF4 diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh index ac4b468..8189d43 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh @@ -1,402 +1,130 @@ #!/bin/bash - -# user data -# Set the secret name and region -SECRET_NAME= -AWS_REGION= -# Set the FSx admin IP -FSXN_ADMIN_IP= -# Volume name -VOLUME_NAME= -# Volume size in GB +# +# Set the ARN of the secret that should contain just the password for the ONTAP admin user set below. +SECRET_ARN="" +# +# Set the FSx admin IP. +FSXN_ADMIN_IP="" +# +# Set the name of the volume to be created on the FSx for ONTAP file system. Note, volume names cannot have dashes in them. +VOLUME_NAME="" +# +# Set the volume size in GB. It should just be a number, without the 'GB' suffix. VOLUME_SIZE= -# SVM name (default: fsx) -SVM_NAME=fsx -# ONTAP admin user (default: fsxadmin) -ONTAP_USER=fsxadmin -# end - user data -SECRET_NAME="${SECRET_NAME:=$1}" -AWS_REGION="${AWS_REGION:=$2}" -FSXN_ADMIN_IP="${FSXN_ADMIN_IP:=$3}" -VOLUME_NAME="${VOLUME_NAME:=$4}" -VOLUME_SIZE="${VOLUME_SIZE:=$5}" -SVM_NAME="${6:-$SVM_NAME}" - -min=100 -max=999 -LUN_NAME=${VOLUME_NAME}_$(($RANDOM%($max-$min+1)+$min)) -# defaults -# Log file in ec2-user home -LOG_FILE=/home/ec2-user/install.log -TIMEOUT=5 - -LUN_SIZE=$(bc -l <<< "0.90*$VOLUME_SIZE" ) -echo "# Uninstall file" >> uninstall.sh -chmod u+x uninstall.sh - -function getSecretValue() { - secret_name=$1 - aws_region=$2 - SECRET_VALUE="$(aws secretsmanager get-secret-value \ - --secret-id "$secret_name" \ - --region "$aws_region" \ - --query 'SecretString' \ - --output text)" - - if [ $? -ne 0 ]; then - echo "Failed to retrieve the secret: $secret_name, Aborting." - exit 1 - fi -} -logMessage() { - echo "$(date) - $1" >> $LOG_FILE -} -checkCommand() { - if [ $? -ne 0 ]; then - logMessage "$1 failed. Aborting." - ./uninstall.sh - exit 1 - fi -} -addUndoCommand() { - sed -i "1i$1" uninstall.sh -} -invokeLambda() { - aws lambda invoke \ - --function-name "arn:aws:lambda:${AWS_REGION}:718273455463:function:reporting-monitoring-dashboard-usage" \ - --payload "$LAMBDA_PAYLOAD" \ - --cli-binary-format raw-in-base64-out \ - /home/ec2-user/lambda_response.json 2>/home/ec2-user/lambda_error.log -} -logMessage "Get secret data" -getSecretValue "${SECRET_NAME}" "${AWS_REGION}" -FSXN_PASSWORD="${SECRET_VALUE}" -logMessage "Secret data retrieved successfully" -commandDescription="Install linux iSCSI packages" -logMessage "${commandDescription}" -yum install -y device-mapper-multipath iscsi-initiator-utils -checkCommand "${commandDescription}" -addUndoCommand "yum remove -y device-mapper-multipath iscsi-initiator-utils" -commandDescription="Set multisession timeout from 120s to 5s" -logMessage "${commandDescription}" -sed -i 's/node.session.timeo.replacement_timeout = .*/node.session.timeo.replacement_timeout = 5/' /etc/iscsi/iscsid.conf; cat /etc/iscsi/iscsid.conf | grep node.session.timeo.replacement_timeout -cat /etc/iscsi/iscsid.conf | grep "node.session.timeo.replacement_timeout = 5" -checkCommand "${commandDescription}" -addUndoCommand "sed -i 's/node.session.timeo.replacement_timeout = .*/node.session.timeo.replacement_timeout = 120/' /etc/iscsi/iscsid.conf;" -commandDescription="Start iscsi service" -logMessage "${commandDescription}" -systemctl enable iscsid -systemctl start iscsid -checkCommand "${commandDescription}" -# check service status -isIscsciServiceRunning=$(systemctl is-active --quiet iscsid.service && echo "1" || echo "0") -if [ "$isIscsciServiceRunning" -eq 1 ]; then - logMessage "iscsi service is running" - addUndoCommand "systemctl --now disable iscsid.service" -else - logMessage "iscsi service is not running, aborting" - ./uninstall.sh -fi -commandDescription="Set multipath config for automatic failover" -logMessage "${commandDescription}" -mpathconf --enable --with_multipathd y -checkCommand "${commandDescription}" -addUndoCommand "mpathconf --disable" -# set Linux host initiator name -name=$(cat /etc/iscsi/initiatorname.iscsi) -initiatorName="${name:14}" -logMessage "initiatorName is: ${initiatorName}" -# Test connection to ONTAP -logMessage "Testing connection to ONTAP." -versionResponse=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/cluster?fields=version") -if [[ "$versionResponse" == *"version"* ]]; then - logMessage "Connection to ONTAP is successful." -else - logMessage "Connection to ONTAP failed, aborting." - ./uninstall.sh -fi -# group name = hostname -groupName=$(hostname) -iGroupResult=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups?svm.name=$SVM_NAME&name=$groupName&initiators.name=$initiatorName&protocol=iscsi&os_type=linux") -initiatorExists=$(echo "${iGroupResult}" | jq '.num_records') -if [ "$initiatorExists" -eq 0 ]; then - logMessage "Initiator ${initiatorName} with group ${groupName} does not exist, creating it." - logMessage "Create initiator group for vserver: ${SVM_NAME} group: ${groupName} initiator: ${initiatorName}" - createGroupResult=$(curl -m $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -H "Content-Type: application/json" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups" -d '{ - "protocol": "iscsi", - "initiators": [ - { - "name": "'$initiatorName'" - } - ], - "os_type": "linux", - "name": "'$groupName'", - "svm": { - "name": "'$SVM_NAME'" - } - }') - iGroupResult=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups?svm.name=$SVM_NAME&name=$groupName&initiators.name=$initiatorName&protocol=iscsi&os_type=linux") - iGroupUuid=$(echo ${iGroupResult} | jq -r '.records[] | select(.name == "'$groupName'" ) | .uuid') - # Check if iGroup was created successfully - if [ -n "$iGroupUuid" ]; then - logMessage "Initiator group ${groupName} was created successfully with UUID: ${iGroupUuid}" - else - logMessage "Initiator group ${groupName} was not created, aborting" - ./uninstall.sh - fi - # Add undo for iGroup - addUndoCommand "curl -m $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/protocols/san/igroups/$iGroupUuid\"" -else - logMessage "Initiator ${initiatorName} with group ${groupName} already exists, skipping creation." -fi - -instance_id=$(ec2-metadata -i | awk '{print $2}') -if [ -z "$instance_id" ]; then - instance_id="unknown" -fi - -logMessage "Create volume: ${SVM_NAME} vol: ${VOLUME_NAME} size: ${VOLUME_SIZE}g" -createVolumeResult=$(curl -m $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/volumes" -d '{ - "name": "'$VOLUME_NAME'", - "size": "'$VOLUME_SIZE'g", - "state": "online", - "svm": { - "name": "'$SVM_NAME'" - }, - "aggregates": [{ - "name": "aggr1" - }], - "_tags": [ - "instanceId:'$instance_id'", - "hostName:'$(hostname)'", - "mountPoint:'$VOLUME_NAME'" - ] -}') -sleep 10 -jobId=$(echo "${createVolumeResult}" | jq -r '.job.uuid') -jobStatus=$(curl -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/cluster/jobs/$jobId") -jobState=$(echo "$jobStatus" | jq -r '.state') -if [ "$jobState" != "success" ]; then - logMessage "Volume creation job did not complete successfully, aborting" - jobError=$(echo "$jobStatus" | jq -r '.error') - logMessage "Error details: $jobError" - ./uninstall.sh -fi - -# validate volume creation -volumeResult=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/volumes?name=${VOLUME_NAME}&svm.name=${SVM_NAME}") -volumeUUid=$(echo "${volumeResult}" | jq -r '.records[] | select(.name == "'$VOLUME_NAME'" ) | .uuid') -if [ -n "$volumeUUid" ]; then - logMessage "Volume ${VOLUME_NAME} was created successfully with UUID: ${volumeUUid}" -else - logMessage "Volume ${VOLUME_NAME} was not created, aborting" - ./uninstall.sh -fi -addUndoCommand "curl -m $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/storage/volumes/${volumeUUid}\"" - -logMessage "Create iscsi lun: ${SVM_NAME} vol: ${VOLUME_NAME} lun: ${LUN_NAME} size: ${LUN_SIZE}g (90% of volume)" -createLunResult=$(curl -m $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns" -d '{ - "name": "'/vol/${VOLUME_NAME}/$LUN_NAME'", - "space": { - "size": "'$LUN_SIZE'GB", - "scsi_thin_provisioning_support_enabled": true - }, - "svm": { - "name": "'$SVM_NAME'" - }, - "os_type": "linux" -}') -lunResult=$(curl -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns?fields=uuid&name=/vol/${VOLUME_NAME}/$LUN_NAME") -# Validate LUN creation -lunUuid=$(echo "${lunResult}" | jq -r '.records[] | select(.name == "'/vol/${VOLUME_NAME}/$LUN_NAME'" ) | .uuid') -if [ -n "$lunUuid" ]; then - logMessage "LUN ${LUN_NAME} was created successfully with UUID: ${lunUuid}" -else - logMessage "LUN ${LUN_NAME} was not created, aborting" - ./uninstall.sh -fi - -addUndoCommand "curl -m $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/storage/luns/${lunUuid}\"" - -# LUN ID is mapping-specific, used by initiators as Logical Unit Number -logMessage "Create a mapping from the LUN you created to the igroup you created" - -lunMapResult=$(curl -m $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps" -d '{ - "lun": { - "name": "/vol/'${VOLUME_NAME}'/'${LUN_NAME}'" - }, - "igroup": { - "name": "'${groupName}'" - }, - "svm": { - "name": "'${SVM_NAME}'" - }, - "logical_unit_number": 0 -}') -logMessage "Validate the lun mapping was created" - -getLunMap=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps?lun.name=/vol/${VOLUME_NAME}/${LUN_NAME}&igroup.name=${groupName}&svm.name=${SVM_NAME}") -lunGroupCreated=$(echo "${getLunMap}" | jq -r '.num_records') -if [ "$lunGroupCreated" -eq 0 ]; then - logMessage "LUN mapping was not created, aborting" - ./uninstall.sh -else - logMessage "LUN mapping was created successfully" -fi - -addUndoCommand "curl -m $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps?lun.name=/vol/${VOLUME_NAME}/${LUN_NAME}&igroup.name=${groupName}&svm.name=${SVM_NAME}\"" - -# Serial hex needed for readable block device name -getLunSerialNumberResult=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns?fields=serial_number") -serialNumber=$(echo "${getLunSerialNumberResult}" | jq -r '.records[] | select(.name == "'/vol/$VOLUME_NAME/$LUN_NAME'" ) | .serial_number') -serialHex=$(echo -n "${serialNumber}" | xxd -p) -if [ -z "$serialHex" ]; then - logMessage "Serial number for the LUN is not available, aborting" - ./uninstall.sh -fi - -logMessage "Get the iscsi interface addresses for the svm ${SVM_NAME}" -getInterfacesResult=$(curl -m $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/network/ip/interfaces?svm.name=$SVM_NAME&fields=ip") -iscsi1IP=$(echo "$getInterfacesResult" | jq -r '.records[] | select(.name == "iscsi_1") | .ip.address') -iscsi2IP=$(echo "$getInterfacesResult" | jq -r '.records[] | select(.name == "iscsi_2") | .ip.address') - -if [ -n "$iscsi1IP" ] && [ -n "$iscsi2IP" ]; then - iscsi1IP=$(echo ${iscsi1IP%/*}) - iscsi2IP=$(echo ${iscsi2IP%/*}) - logMessage "iscsi interface addresses for the svm ${SVM_NAME} are: ${iscsi1IP} and ${iscsi2IP}" -else - logMessage "iscsi interface addresses for the svm ${SVM_NAME} are not available, aborting" - ./uninstall.sh -fi - -logMessage "Discover the target iSCSI nodes, iscsi IP: ${iscsi1IP}" -iscsiadm --mode discovery --op update --type sendtargets --portal $iscsi1IP -checkCommand "${commandDescription}" -addUndoCommand "iscsiadm --mode discovery --op delete --type sendtargets --portal ${iscsi1IP}" -addUndoCommand "iscsiadm --mode discovery --op delete --type sendtargets --portal ${iscsi2IP}" - -logMessage "Getting target initiator" -targetInitiator=$(iscsiadm --mode discovery --op update --type sendtargets --portal $iscsi1IP | awk '{print $2}' | head -n 1) -logMessage "Target initiator is: ${targetInitiator}" - -# update sessions to 8 (optional) -#iscsiadm --mode node -T $targetInitiator --op update -n node.session.nr_sessions -v 8 -# Login to target initiators - iSCSI LUNs presented as disks -logMessage "Log into target initiator: ${targetInitiator}" -iscsiadm --mode node -T $targetInitiator --login -addUndoCommand "iscsiadm --mode node -T $targetInitiator --logout" - -# Add the following section to the /etc/multipath.conf file: -# multipaths { -# multipath { -# wwid 3600a0980${serialHex} -# alias ${VOLUME_NAME} -# } -# } -# Assign block device name -logMessage "Update /etc/multipath.conf file, Assign name to block device." -cp /etc/multipath.conf /etc/multipath.conf_backup - -SERIAL_HEX=$serialHex -ALIAS=$VOLUME_NAME -CONF=/etc/multipath.conf -chmod o+rw $CONF -grep -q '^multipaths {' $CONF -UNCOMMENTED=$? -if [ $UNCOMMENTED -eq 0 ]; then - sed -i '/^multipaths {/a\\tmultipath {\n\t\twwid 3600a0980'"${SERIAL_HEX}"'\n\t\talias '"${ALIAS}"'\n\t}\n' $CONF -else - printf "multipaths {\n\tmultipath {\n\t\twwid 3600a0980$SERIAL_HEX\n\t\talias $ALIAS\n\t}\n}" >> $CONF -fi - -fileContent="$(cat $CONF)" -logMessage "Updated /etc/multipath.conf file content: $fileContent" - -commandDescription="Restart multipathd for /etc/multipathd.conf changes" -logMessage "${commandDescription}" -systemctl restart multipathd.service -checkCommand "${commandDescription}" -addUndoCommand "cp /etc/multipath.conf_backup /etc/multipath.conf" -addUndoCommand "systemctl restart multipathd.service" - -logMessage "Checking if the new partition exists." -timeout=90 -interval=5 -elapsed=0 - -while [ $elapsed -lt $timeout ]; do - if [ -e "/dev/mapper/$VOLUME_NAME" ]; then - logMessage "The device $VOLUME_NAME exists." - break - fi - sleep $interval - elapsed=$((elapsed + interval)) -done -if [ ! -e "/dev/mapper/$VOLUME_NAME" ]; then - logMessage "The device $VOLUME_NAME does not exists. Exiting." - ./uninstall.sh - exit 1 -fi - -# Partition the LUN -# mount the LUN on Linux client -# Create mount point directory -directory_path=mnt -mount_point=$VOLUME_NAME - -commandDescription="Create mount point /${directory_path}/${mount_point}" -logMessage "${commandDescription}" -mkdir /$directory_path/$mount_point -checkCommand "${commandDescription}" -addUndoCommand "rm -rf /$directory_path/$mount_point" -# volume_name = friendly device name from multipath.conf -commandDescription="Create file system for /dev/mapper/${ALIAS}" -logMessage "${commandDescription}" -mkfs.ext4 /dev/mapper/$ALIAS -checkCommand "${commandDescription}" - -commandDescription="Mount the file system" -logMessage "${commandDescription}" -mount -t ext4 /dev/mapper/$ALIAS /$directory_path/$mount_point -checkCommand "${commandDescription}" -addUndoCommand "umount /$directory_path/$mount_point" -# verify read/write access -commandDescription="Verify read/write access" -logMessage "${commandDescription}" -echo "test mount iscsci" > /$directory_path/$mount_point/testIscsi.txt -cat /$directory_path/$mount_point/testIscsi.txt -checkCommand "${commandDescription}" -rm /$directory_path/$mount_point/testIscsi.txt - -logMessage "FSXn iSCSI volume mount successful." -# Add mount to /etc/fstab -commandDescription="Add mount to /etc/fstab" -logMessage "${commandDescription}" -echo "/dev/mapper/$ALIAS /$directory_path/$mount_point ext4 defaults,_netdev 0 0" >> /etc/fstab -checkCommand "${commandDescription}" -addUndoCommand "sed -i '/\/dev\/mapper\/$ALIAS \/mnt\/$mount_point ext4 defaults,_netdev 0 0/d' /etc/fstab" - -# Report usage -logMessage "Report usage" -logMessage "Attempting Lambda invoke" -LAMBDA_PAYLOAD='{"ResourceProperties":{"Source":"Deploy_EC2_Wizard","Region":"'$AWS_REGION'"},"RequestType":"CLI"}' - -# Try Lambda invoke -invokeLambda -if [ $? -ne 0 ] && grep -q "initializing" /home/ec2-user/lambda_error.log 2>/dev/null; then - logMessage "Lambda initializing, retrying in 10s..." - sleep 10 - invokeLambda -fi - -# Check final result -if [ $? -eq 0 ]; then - logMessage "Usage reporting completed successfully" -else - logMessage "Usage reporting failed" -fi - -# End -logMessage "Script completed successfully." - -rm -f uninstall.sh \ No newline at end of file +# +# Set the SVM name. The default is 'fsx'. +SVM_NAME="fsx" +# +# Set the ONTAP admin user. The default is fsxadmin. +ONTAP_USER="fsxadmin" +# +################################################################################ +# **** You should not need to edit anything below this line **** +################################################################################ +# +# When called from the CloudFormation template, the parameters are passsed as +# arguments. +SECRET_ARN="${SECRET_ARN:=$1}" +FSXN_ADMIN_IP="${FSXN_ADMIN_IP:=$2}" +VOLUME_NAME="${VOLUME_NAME:=$3}" +VOLUME_SIZE="${VOLUME_SIZE:=$4}" +SVM_NAME="${5:-$SVM_NAME}" +ONTAP_USER="${6:-$ONTAP_USER}" +# +# Since AWS only allows up to 16KB for the user data script, the rest of this script +# will be the compressed version of the linux_userData_real.sh file, which will be +# uncompressed and executed on the EC2 instance when it is deployed. +cat < /tmp/linux_userData.sh +#!/bin/bash +export SECRET_ARN="$SECRET_ARN" +export FSXN_ADMIN_IP="$FSXN_ADMIN_IP" +export VOLUME_NAME="$VOLUME_NAME" +export VOLUME_SIZE="$VOLUME_SIZE" +export SVM_NAME="$SVM_NAME" +export ONTAP_USER="$ONTAP_USER" +EOF2 + +cat <> /tmp/linux_userData.sh +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 +EOF3 + +chmod +x /tmp/linux_userData.sh +/tmp/linux_userData.sh diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh new file mode 100755 index 0000000..5f64f5b --- /dev/null +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh @@ -0,0 +1,447 @@ +#!/bin/bash + +LUN_NAME=${VOLUME_NAME}_$(($RANDOM%(900)+100)) +LOG_FILE=/var/log/iscsi-install.log +TIMEOUT=5 +# +# Get the O/S Linux distribution. +. /etc/os-release +case "$ID" in + amzn|centos|rhel) + OS_TYPE=rhel;; + ubuntu|debian) + OS_TYPE=debian;; + *) + echo "Unknown OS type: '$ID'." >> $LOG_FILE + exit 1;; +esac + +LUN_SIZE=$(bc -l <<< "0.90*$VOLUME_SIZE" ) +echo "# Uninstall file" > uninstall.sh +chmod u+x uninstall.sh + +getSecretValue() { + secret_arn=$1 + SECRET_VALUE="$(aws secretsmanager get-secret-value \ + --secret-id "$secret_arn" \ + --query 'SecretString' \ + --output text)" + + if [ $? -ne 0 ]; then + echo "Failed to retrieve the secret from '$secret_arn', Aborting." + exit 1 + fi +} +logMessage() { + echo "$(date) - $1" >> $LOG_FILE +} +checkCommand() { + if [ $? -ne 0 ]; then + logMessage "$1 failed. Aborting." + ./uninstall.sh + exit 1 + fi +} +addUndoCommand() { + sed -i "1i$1" uninstall.sh +} +LambdaErrorFile="/tmp/lambda_error.log" +LambdaResponseFile="/tmp/lambda_response.json" +invokeLambda() { + aws lambda invoke \ + --function-name "arn:aws:lambda:${AWS_REGION}:718273455463:function:reporting-monitoring-dashboard-usage" \ + --payload "$LAMBDA_PAYLOAD" \ + --cli-binary-format raw-in-base64-out \ + $LambdaResponseFile 2>$LambdaErrorFile +} +requiredCmds="curl unzip jq" +if [ "$OS_TYPE" == "rhel" ]; then + yum update -y + checkCommand "yum update" + for cmd in $requiredCmds; do + if ! command -v $cmd &> /dev/null; then + logMessage "Installing $cmd" + if [ "$cmd" == "jq" ]; then + # For RHEL/CentOS, install jq from EPEL repository + yum install -y epel-release + checkCommand "Install epel-release for jq" + fi + yum install -y $cmd + checkCommand "Install $cmd" + addUndoCommand "yum remove -y $cmd" + fi + done + + if [ "$ID" != "amzn" ]; then + curl -s https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip + unzip -q awscliv2.zip + ./aws/install + rm -rf aws awscliv2.zip + fi +elif [ "$OS_TYPE" == "debian" ]; then + apt-get update > /dev/null 2>&1 + for cmd in $requiredCmds; do + if ! command -v $cmd &> /dev/null; then + logMessage "Installing $cmd" + apt-get install -y $cmd + checkCommand "Install $cmd" + addUndoCommand "apt-get remove -y $cmd" + fi + done + curl -s https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip + unzip -q awscliv2.zip + ./aws/install + rm -rf aws awscliv2.zip +fi + +logMessage "Get secret data" +getSecretValue "${SECRET_ARN}" +FSXN_PASSWORD="${SECRET_VALUE}" +logMessage "Secret data retrieved successfully" +commandDescription="Install linux iSCSI packages" +logMessage "${commandDescription}" +if [ "$OS_TYPE" == "rhel" ]; then + yum install -y device-mapper-multipath iscsi-initiator-utils + checkCommand "${commandDescription}" + addUndoCommand "yum remove -y device-mapper-multipath iscsi-initiator-utils" +elif [ "$OS_TYPE" == "debian" ]; then + apt-get update > /dev/null 2>&1 + apt-get install -y multipath-tools open-iscsi + checkCommand "${commandDescription}" + addUndoCommand "apt-get remove -y multipath-tools open-iscsi" +fi +commandDescription="Set multisession timeout from 120s to 5s" +logMessage "${commandDescription}" +sed -i 's/node.session.timeo.replacement_timeout = .*/node.session.timeo.replacement_timeout = 5/' /etc/iscsi/iscsid.conf +grep "node.session.timeo.replacement_timeout = 5" /etc/iscsi/iscsid.conf +checkCommand "${commandDescription}" +addUndoCommand "sed -i 's/node.session.timeo.replacement_timeout = .*/node.session.timeo.replacement_timeout = 120/' /etc/iscsi/iscsid.conf" +commandDescription="Start iscsi service" +logMessage "${commandDescription}" +systemctl enable iscsid +systemctl start iscsid +checkCommand "${commandDescription}" +# check service status +isIscsciServiceRunning=$(systemctl is-active --quiet iscsid.service && echo "1" || echo "0") +if [ "$isIscsciServiceRunning" -eq 1 ]; then + logMessage "iscsi service is running" + addUndoCommand "systemctl --now disable iscsid.service" +else + logMessage "iscsi service is not running, aborting" + ./uninstall.sh + exit 1 +fi +commandDescription="Set multipath config for automatic failover" +logMessage "${commandDescription}" +if [ $OS_TYPE == "rhel" ]; then + mpathconf --enable --with_multipathd y + checkCommand "${commandDescription}" + addUndoCommand "mpathconf --disable" +elif [ $OS_TYPE == "debian" ]; then + systemctl enable multipathd + systemctl start multipathd + checkCommand "${commandDescription}" + isServiceRunning=$(systemctl is-active --quiet multipathd && echo "1" || echo "0") + if [ "$isServiceRunning" -eq 1 ]; then + logMessage "multipathd service is running" + addUndoCommand "systemctl --now disable multipathd" + else + logMessage "multipathd service is not running, aborting" + ./uninstall.sh + exit 1 + fi +fi + +. /etc/iscsi/initiatorname.iscsi +logMessage "InitiatorName is: ${InitiatorName}" + +logMessage "Testing connection to ONTAP." +versionResponse=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/cluster?fields=version" | jq -r .version) +if [ "$versionResponse" == "null" ]; then + logMessage "Connection to ONTAP failed, aborting." + ./uninstall.sh + exit 1 +fi + +groupName=$(hostname) +iGroupResult=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups?svm.name=$SVM_NAME&name=$groupName&initiators.name=$InitiatorName&protocol=iscsi&os_type=linux") +initiatorExists=$(echo "${iGroupResult}" | jq '.num_records') +if [ "$initiatorExists" -eq 0 ]; then + logMessage "Initiator ${InitiatorName} with group ${groupName} does not exist, creating it." + logMessage "Create initiator group for vserver: ${SVM_NAME} group: ${groupName} initiator: ${InitiatorName}" + createGroupResult=$(curl -sm $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -H "Content-Type: application/json" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups" -d '{ + "protocol": "iscsi", + "initiators": [ + { + "name": "'$InitiatorName'" + } + ], + "os_type": "linux", + "name": "'$groupName'", + "svm": { + "name": "'$SVM_NAME'" + } + }') + iGroupResult=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/igroups?svm.name=$SVM_NAME&name=$groupName&initiators.name=$InitiatorName&protocol=iscsi&os_type=linux") + iGroupUuid=$(echo ${iGroupResult} | jq -r '.records[] | select(.name == "'$groupName'" ) | .uuid') + + if [ -n "$iGroupUuid" ]; then + logMessage "Initiator group ${groupName} was created successfully with UUID: ${iGroupUuid}" + else + logMessage "Initiator group ${groupName} was not created, aborting" + ./uninstall.sh + exit 1 + fi + + addUndoCommand "curl -sm $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/protocols/san/igroups/$iGroupUuid\"" +else + logMessage "Initiator ${InitiatorName} with group ${groupName} already exists, skipping creation." +fi +# +# Get the EC2 instanace ID. +TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") +instance_id=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id) +if [ -z "$instance_id" ]; then + instance_id="unknown" +fi + +logMessage "Create volume: ${SVM_NAME} vol: ${VOLUME_NAME} size: ${VOLUME_SIZE}g" +createVolumeResult=$(curl -sm $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/volumes" -d '{ + "name": "'$VOLUME_NAME'", + "size": "'$VOLUME_SIZE'g", + "state": "online", + "svm": { + "name": "'$SVM_NAME'" + }, + "aggregates": [{ + "name": "aggr1" + }], + "_tags": [ + "instanceId:'$instance_id'", + "hostName:'$(hostname)'", + "mountPoint:'$VOLUME_NAME'" + ] +}') +sleep 10 +jobId=$(echo "${createVolumeResult}" | jq -r '.job.uuid') +jobStatus=$(curl -sX GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/cluster/jobs/$jobId") +jobState=$(echo "$jobStatus" | jq -r '.state') +if [ "$jobState" != "success" ]; then + logMessage "Volume creation job did not complete successfully, aborting" + jobError=$(echo "$jobStatus" | jq -r '.error') + logMessage "Error details: $jobError" + ./uninstall.sh + exit 1 +fi + +volumeResult=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/volumes?name=${VOLUME_NAME}&svm.name=${SVM_NAME}") +volumeUUid=$(echo "${volumeResult}" | jq -r '.records[] | select(.name == "'$VOLUME_NAME'" ) | .uuid') +if [ -n "$volumeUUid" ]; then + logMessage "Volume ${VOLUME_NAME} was created successfully with UUID: ${volumeUUid}" +else + logMessage "Volume ${VOLUME_NAME} was not created, aborting" + ./uninstall.sh + exit 1 +fi +addUndoCommand "curl -sm $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/storage/volumes/${volumeUUid}\"" + +logMessage "Create iscsi lun: ${SVM_NAME} vol: ${VOLUME_NAME} lun: ${LUN_NAME} size: ${LUN_SIZE}g (90% of volume)" +createLunResult=$(curl -sm $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns" -d '{ + "name": "'/vol/${VOLUME_NAME}/$LUN_NAME'", + "space": { + "size": "'$LUN_SIZE'GB", + "scsi_thin_provisioning_support_enabled": true + }, + "svm": { + "name": "'$SVM_NAME'" + }, + "os_type": "linux" +}') +lunResult=$(curl -sX GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns?fields=uuid&name=/vol/${VOLUME_NAME}/$LUN_NAME") + +lunUuid=$(echo "${lunResult}" | jq -r '.records[] | select(.name == "'/vol/${VOLUME_NAME}/$LUN_NAME'" ) | .uuid') +if [ -n "$lunUuid" ]; then + logMessage "LUN ${LUN_NAME} was created successfully with UUID: ${lunUuid}" +else + logMessage "LUN ${LUN_NAME} was not created, aborting" + ./uninstall.sh + exit 1 +fi + +addUndoCommand "curl -sm $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/storage/luns/${lunUuid}\"" + +logMessage "Create a mapping from the LUN you created to the igroup you created" + +lunMapResult=$(curl -sm $TIMEOUT -X POST -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps" -d '{ + "lun": { + "name": "/vol/'${VOLUME_NAME}'/'${LUN_NAME}'" + }, + "igroup": { + "name": "'${groupName}'" + }, + "svm": { + "name": "'${SVM_NAME}'" + }, + "logical_unit_number": 0 +}') +logMessage "Validate the lun mapping was created" + +getLunMap=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps?lun.name=/vol/${VOLUME_NAME}/${LUN_NAME}&igroup.name=${groupName}&svm.name=${SVM_NAME}") +lunGroupCreated=$(echo "${getLunMap}" | jq -r '.num_records') +if [ "$lunGroupCreated" -eq 0 ]; then + logMessage "LUN mapping was not created, aborting" + ./uninstall.sh + exit 1 +else + logMessage "LUN mapping was created successfully" +fi + +addUndoCommand "curl -sm $TIMEOUT -X DELETE -u \"$ONTAP_USER\":\"$FSXN_PASSWORD\" -k \"https://$FSXN_ADMIN_IP/api/protocols/san/lun-maps?lun.name=/vol/${VOLUME_NAME}/${LUN_NAME}&igroup.name=${groupName}&svm.name=${SVM_NAME}\"" +# +# Serial hex needed for readable block device name +getLunSerialNumberResult=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/storage/luns?fields=serial_number") +serialNumber=$(echo "${getLunSerialNumberResult}" | jq -r '.records[] | select(.name == "'/vol/$VOLUME_NAME/$LUN_NAME'" ) | .serial_number') +serialHex=$(echo -n "${serialNumber}" | xxd -p) +if [ -z "$serialHex" ]; then + logMessage "Serial number for the LUN is not available, aborting" + ./uninstall.sh + exit 1 +fi + +logMessage "Get the iscsi interface addresses for the svm ${SVM_NAME}" +getInterfacesResult=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/network/ip/interfaces?svm.name=$SVM_NAME&fields=ip") +iscsi1IP=$(echo "$getInterfacesResult" | jq -r '.records[] | select(.name == "iscsi_1") | .ip.address') +iscsi2IP=$(echo "$getInterfacesResult" | jq -r '.records[] | select(.name == "iscsi_2") | .ip.address') + +if [ -n "$iscsi1IP" ] && [ -n "$iscsi2IP" ]; then + iscsi1IP=$(echo ${iscsi1IP%/*}) + iscsi2IP=$(echo ${iscsi2IP%/*}) + logMessage "iscsi interface addresses for the svm ${SVM_NAME} are: ${iscsi1IP} and ${iscsi2IP}" +else + logMessage "iscsi interface addresses for the svm ${SVM_NAME} are not available, aborting" + ./uninstall.sh + exit 1 +fi + +logMessage "Discover the target iSCSI nodes, iscsi IP: ${iscsi1IP}" +iscsiadm --mode discovery --op update --type sendtargets --portal $iscsi1IP +checkCommand "${commandDescription}" +addUndoCommand "iscsiadm --mode discovery --op delete --type sendtargets --portal ${iscsi1IP}" +addUndoCommand "iscsiadm --mode discovery --op delete --type sendtargets --portal ${iscsi2IP}" + +logMessage "Getting target initiator" +targetInitiator=$(iscsiadm --mode discovery --op update --type sendtargets --portal $iscsi1IP | awk '{print $2}' | head -n 1) +logMessage "Target initiator is: ${targetInitiator}" + +iscsiadm --mode node -T $targetInitiator --op update -n node.session.nr_sessions -v 8 + +logMessage "Log into target initiator: ${targetInitiator}" +iscsiadm --mode node -T $targetInitiator --login +addUndoCommand "iscsiadm --mode node -T $targetInitiator --logout" +# +# Add the following section to the /etc/multipath.conf file: +# multipaths { +# multipath { +# wwid 3600a0980${serialHex} +# alias ${VOLUME_NAME} +# } +# } +logMessage "Update /etc/multipath.conf file, Assign name to block device." +cp /etc/multipath.conf /etc/multipath.conf_backup + +SERIAL_HEX=$serialHex +ALIAS=$VOLUME_NAME +CONF=/etc/multipath.conf +chmod o+rw $CONF +grep -q '^multipaths {' $CONF +UNCOMMENTED=$? +if [ $UNCOMMENTED -eq 0 ]; then + sed -i '/^multipaths {/a\\tmultipath {\n\t\twwid 3600a0980'"${SERIAL_HEX}"'\n\t\talias '"${ALIAS}"'\n\t}\n' $CONF +else + printf "multipaths {\n\tmultipath {\n\t\twwid 3600a0980$SERIAL_HEX\n\t\talias $ALIAS\n\t}\n}" >> $CONF +fi + +fileContent="$(cat $CONF)" +logMessage "Updated /etc/multipath.conf file content: $fileContent" + +commandDescription="Restart multipathd for /etc/multipathd.conf changes" +logMessage "${commandDescription}" +systemctl restart multipathd.service +checkCommand "${commandDescription}" +addUndoCommand "systemctl restart multipathd.service" +addUndoCommand "cp /etc/multipath.conf_backup /etc/multipath.conf" + +logMessage "Checking if the new partition exists." +timeout=90 +interval=5 +elapsed=0 + +while [ $elapsed -lt $timeout ]; do + if [ -e "/dev/mapper/$VOLUME_NAME" ]; then + logMessage "The device $VOLUME_NAME exists." + break + fi + sleep $interval + elapsed=$((elapsed + interval)) +done +if [ ! -e "/dev/mapper/$VOLUME_NAME" ]; then + logMessage "The device $VOLUME_NAME does not exists. Exiting." + ./uninstall.sh + exit 1 +fi + +directory_path=mnt +mount_point=$VOLUME_NAME + +commandDescription="Create mount point /${directory_path}/${mount_point}" +logMessage "${commandDescription}" +mkdir /$directory_path/$mount_point +checkCommand "${commandDescription}" +addUndoCommand "rm -rf /$directory_path/$mount_point" + +commandDescription="Create file system for /dev/mapper/${ALIAS}" +logMessage "${commandDescription}" +mkfs.ext4 /dev/mapper/$ALIAS +checkCommand "${commandDescription}" + +commandDescription="Mount the file system" +logMessage "${commandDescription}" +mount -t ext4 /dev/mapper/$ALIAS /$directory_path/$mount_point +checkCommand "${commandDescription}" +addUndoCommand "umount /$directory_path/$mount_point" + +commandDescription="Verify read/write access" +logMessage "${commandDescription}" +echo "test mount iscsci" > /$directory_path/$mount_point/testIscsi.txt +cat /$directory_path/$mount_point/testIscsi.txt +checkCommand "${commandDescription}" +rm /$directory_path/$mount_point/testIscsi.txt + +logMessage "FSXn iSCSI volume mount successful." + +commandDescription="Add mount to /etc/fstab" +logMessage "${commandDescription}" +echo "/dev/mapper/$ALIAS /$directory_path/$mount_point ext4 defaults,_netdev 0 0" >> /etc/fstab +checkCommand "${commandDescription}" +addUndoCommand "sed -i '$d' /etc/fstab" + +logMessage "Report usage" +logMessage "Attempting Lambda invoke" +LAMBDA_PAYLOAD='{"ResourceProperties":{"Source":"Deploy_EC2_Wizard","Region":"'$AWS_REGION'"},"RequestType":"CLI"}' + +invokeLambda +if [ $? -ne 0 ] && grep -q "initializing" $LambdaErrorFile 2>/dev/null; then + logMessage "Lambda initializing, retrying in 10s..." + sleep 10 + invokeLambda +fi + +if [ $? -eq 0 ]; then + logMessage "Usage reporting completed successfully" +else + logMessage "Usage reporting failed" +fi + +logMessage "Script completed successfully." + +rm -f uninstall.sh From 9c8cabab1b6c7cf6f1c905031c9a63d59d808966 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 25 Mar 2026 06:23:42 -0500 Subject: [PATCH 2/5] Added other Linux distribuation support. --- .../EC2-cloud_formation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml index b4f0ffe..6fce7d6 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/EC2-cloud_formation.yaml @@ -123,7 +123,7 @@ Parameters: Description: Drive Letter - valid for Windows only CidrIp: Type: String - Description: CIDR IP for SSH or RDP access to the instance. + Description: CIDR IP for SSH or RDP access to the instance. MUST be a CIDR! LinuxUserDataUrl: Type: String Default: https://raw.githubusercontent.com/NetApp/FSx-ONTAP-samples-scripts/refs/heads/main/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh From 060a093c77e5cf9cd962f09758a1329aa70cd5ed Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 25 Mar 2026 16:54:54 -0500 Subject: [PATCH 3/5] Added support for more Linux disibutions. --- .../README.md | 35 ++-- .../linux_userData.sh | 162 +++++++++--------- .../linux_userData_real.sh | 53 ++++-- 3 files changed, 147 insertions(+), 103 deletions(-) diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md index 9856745..9a54ec7 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md @@ -9,12 +9,8 @@ volume and LUN, mount it to the instance, while installing all the needed librar This means that usuable volume size is 90% of the requestd size. - The process might take several minutes to be compleetd. -## Deployment -There are two ways to deploy an EC2 instance with the needed user data script: -1. Copy the CloudFormation template found in the repo [EC2-cloud_formation.yaml](EC2-cloud_formation.yaml) to you local machine and deploy a CLoudFormation stack using it. CloudFormation will prmopt you for all the required parameters. -2. Follow the instruction below to deploy an EC2 instance from the AWS console. +## Perperation -## AWS console deployment preparation 1. Create an AWS SecretsManager secret to hold the password of the account you plan to use to authenicate to the FSxN file system with. The secret should be of type `other` with value set to `Plain Text` that holds just the password. 2. Create an AWS IAM role that has EC2 as the trusted entity and has permissions to read the secret value. Here is an example policy that will do that: @@ -35,7 +31,24 @@ The secret should be of type `other` with value set to `Plain Text` that holds j ``` Replace the "Resource" ARN with the ARN of your secret. -3. Download the needed script according to the instance type you want to run (Linux or Windows). +## Deployment Options + +There are two ways to deploy an EC2 instance with the needed user data script: +1. Copy the CloudFormation template found in the repo [EC2-cloud_formation.yaml](EC2-cloud_formation.yaml) to you local machine and deploy a CLoudFormation stack using it. CloudFormation will prmopt you for all the required parameters. +2. Follow the instruction below to deploy an EC2 instance from the AWS console. + +## AWS console deployment + +1. Download the needed script according to the instance type you want to run. Either [linux_userData.sh](linux_userData.sh) +for a Linux distributuino or [windows_userData.ps1](windows_userData.ps1) for Windows. The Linux script has been tested +with `Amazon Linux 2023 AMI`, `Ubuntu`, `Red Hat` and `Debian` distributions, while the Windows script is designed for `Windows Server 2025 Base`. + +Note that since AWS has a 16KB limit for the user data the linux_userData.sh script is made up of the variable +assignment noted below, and a compressed, encoded version of the `linux_userData_real.sh` script. When the +`linux_userData.sh` script is run, it will decode and decompress what was the `linux_userData_real.sh` script +and then execute it. + +Once you have downloaded the script, open it in a text editor and set the required values as noted below. For the Linux version of the script, set the following values at the top of it: - SECRET_ARN - The ARN of the secret that has the password for the `ONTAP-USER`. @@ -54,10 +67,8 @@ The secret should be of type `other` with value set to `Plain Text` that holds j - $user - The ONTAP user id you wish to authenicate with. - $svm_name - The name of the SVM where the volume is to be created. -4. Save the script file. +2. Save the script file. -## On AWS console EC2 - ### For Linux installation:
    1. Launch new instance @@ -100,9 +111,11 @@ If an error occurs while the installation is running, the script will terminate
    The installation log file can be found at: `C:\Users\Administrator\install.log`. -If an error occurs while the installation is running, a message will be inserted into the installation log file, it will attempt to roll back any work that it preformed, finally the script will terminate. +If an error occurs while the installation is running, a message will be inserted into the +installation log file, it will attempt to roll back any work that it preformed, finally the script will terminate. -**Note:** It can take 20 to 30 minutes for the script to compplete. Check the installation log file to confirm it is done. The line `Uninstall script removed` should be at the bottom of the file when the script has finished. +**Note:** It can take 10 to 15 minutes for the script to compplete. Check the installation log file to confirm it is done. +The line `Uninstall script removed` should be at the bottom of the file when the script has finished. ## Author Information diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh index 8189d43..033a227 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh @@ -45,85 +45,89 @@ export ONTAP_USER="$ONTAP_USER" EOF2 cat <> /tmp/linux_userData.sh -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 +BtroE5gZpuWvVv8XVPIEubpEAAA= EOF3 chmod +x /tmp/linux_userData.sh diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh index 5f64f5b..6bca031 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh @@ -1,6 +1,8 @@ #!/bin/bash +# +# Since if aws is installed it goes into /usr/local/bin. +PATH=${PATH}:/usr/local/bin -LUN_NAME=${VOLUME_NAME}_$(($RANDOM%(900)+100)) LOG_FILE=/var/log/iscsi-install.log TIMEOUT=5 # @@ -16,10 +18,6 @@ case "$ID" in exit 1;; esac -LUN_SIZE=$(bc -l <<< "0.90*$VOLUME_SIZE" ) -echo "# Uninstall file" > uninstall.sh -chmod u+x uninstall.sh - getSecretValue() { secret_arn=$1 SECRET_VALUE="$(aws secretsmanager get-secret-value \ @@ -54,7 +52,7 @@ invokeLambda() { --cli-binary-format raw-in-base64-out \ $LambdaResponseFile 2>$LambdaErrorFile } -requiredCmds="curl unzip jq" +requiredCmds="curl unzip jq bc xxd" if [ "$OS_TYPE" == "rhel" ]; then yum update -y checkCommand "yum update" @@ -94,6 +92,12 @@ elif [ "$OS_TYPE" == "debian" ]; then rm -rf aws awscliv2.zip fi +LUN_SIZE=$(bc -l <<< "0.90*$VOLUME_SIZE" ) +LUN_NAME=${VOLUME_NAME}_$(($RANDOM%(900)+100)) + +echo "# Uninstall file" > uninstall.sh +chmod u+x uninstall.sh + logMessage "Get secret data" getSecretValue "${SECRET_ARN}" FSXN_PASSWORD="${SECRET_VALUE}" @@ -340,6 +344,10 @@ iscsiadm --mode node -T $targetInitiator --login addUndoCommand "iscsiadm --mode node -T $targetInitiator --logout" # # Add the following section to the /etc/multipath.conf file: +# defaults { +# user_friendly_names yes +# find_multipaths yes +# } # multipaths { # multipath { # wwid 3600a0980${serialHex} @@ -347,22 +355,41 @@ addUndoCommand "iscsiadm --mode node -T $targetInitiator --logout" # } # } logMessage "Update /etc/multipath.conf file, Assign name to block device." -cp /etc/multipath.conf /etc/multipath.conf_backup SERIAL_HEX=$serialHex ALIAS=$VOLUME_NAME CONF=/etc/multipath.conf + +if egrep -q "alias\t*${ALIAS}$" $CONF; then + echo "Error, there is already an alias in the multipath.conf file for the volume '$ALIAS'. Aborting." + ./uninstall.sh + exit 1 +fi +cp $CONF ${CONF}_backup chmod o+rw $CONF -grep -q '^multipaths {' $CONF -UNCOMMENTED=$? -if [ $UNCOMMENTED -eq 0 ]; then + +if grep -q 'defaults' $CONF; then + if grep -q 'user_friendly_names' $CONF; then + sed -i '/user_friendly_names/s/user_friendly_names.*/user_friendly_names yes/' $CONF + else + sed -i '/defaults/a\\tuser_friendly_names yes' $CONF + fi + if grep -q 'find_multipaths' $CONF; then + sed -i '/find_multipaths/s/find_multipaths.*/find_multipaths yes/' $CONF + else + sed -i '/defaults/a\\tfind_multipaths yes' $CONF + fi +else + printf "\ndefaults {\n\tuser_friendly_names yes\n\tfind_multipaths yes\n}\n" >> $CONF +fi + +if egrep -q '^multipaths {' $CONF; then sed -i '/^multipaths {/a\\tmultipath {\n\t\twwid 3600a0980'"${SERIAL_HEX}"'\n\t\talias '"${ALIAS}"'\n\t}\n' $CONF else - printf "multipaths {\n\tmultipath {\n\t\twwid 3600a0980$SERIAL_HEX\n\t\talias $ALIAS\n\t}\n}" >> $CONF + printf "multipaths {\n\tmultipath {\n\t\twwid 3600a0980$SERIAL_HEX\n\t\talias $ALIAS\n\t}\n}\n" >> $CONF fi -fileContent="$(cat $CONF)" -logMessage "Updated /etc/multipath.conf file content: $fileContent" +logMessage "Updated /etc/multipath.conf file content: $(cat $CONF)" commandDescription="Restart multipathd for /etc/multipathd.conf changes" logMessage "${commandDescription}" From d0cc95d8336acd8bb0fb191a944e08fa28611e7d Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 25 Mar 2026 17:07:28 -0500 Subject: [PATCH 4/5] Added support for more Linux disibutions. --- .../README.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md index 9a54ec7..73f3920 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md @@ -40,15 +40,16 @@ There are two ways to deploy an EC2 instance with the needed user data script: ## AWS console deployment 1. Download the needed script according to the instance type you want to run. Either [linux_userData.sh](linux_userData.sh) -for a Linux distributuino or [windows_userData.ps1](windows_userData.ps1) for Windows. The Linux script has been tested -with `Amazon Linux 2023 AMI`, `Ubuntu`, `Red Hat` and `Debian` distributions, while the Windows script is designed for `Windows Server 2025 Base`. +for a Linux distribution or [windows_userData.ps1](windows_userData.ps1) for Windows. The Linux script has been tested +with `Amazon Linux 2023`, `Ubuntu 24.04`, `Red Hat Enterprise Linux 10` and `Debian 13` distributions, +while the Windows script is designed for `Windows Server 2025 Base`. -Note that since AWS has a 16KB limit for the user data the linux_userData.sh script is made up of the variable -assignment noted below, and a compressed, encoded version of the `linux_userData_real.sh` script. When the -`linux_userData.sh` script is run, it will decode and decompress what was the `linux_userData_real.sh` script -and then execute it. + Note that since AWS has a 16KB limit for the user data the linux_userData.sh script is made up of the variable + assignment noted below, and a compressed, based64 encoded version of the `linux_userData_real.sh` script. When the + `linux_userData.sh` script is run, it will decode and uncompress effecitively the `linux_userData_real.sh` script + and run it. -Once you have downloaded the script, open it in a text editor and set the required values as noted below. + Once you have downloaded the script, open it in a text editor and set the required values as noted below. For the Linux version of the script, set the following values at the top of it: - SECRET_ARN - The ARN of the secret that has the password for the `ONTAP-USER`. @@ -56,7 +57,7 @@ Once you have downloaded the script, open it in a text editor and set the requir - VOLUME_NAME - The name of the volume you want to create in your FSxN. - VOLUME_SIZE - The size of the volume you want to create in GB e.g [100] - SVM_NAME - The name of the SVM where the volume is to be created. - - ONTAP_USER - The ONTAP user id you wish to authenicate with. + - ONTAP_USER - The ONTAP user id you wish to authenticate with. For the Windows version of the script, set the following values at the top of it: - $secretId - secret ARN that holds the password for the `$user`. @@ -64,7 +65,7 @@ Once you have downloaded the script, open it in a text editor and set the requir - $volName - The name of the volume you want to create in your FSxN. - $volSize - The size of the volume you want to create in GB e.g [100] - $drive_letter - The drive letter to assign to the volume. - - $user - The ONTAP user id you wish to authenicate with. + - $user - The ONTAP user id you wish to authenticate with. - $svm_name - The name of the SVM where the volume is to be created. 2. Save the script file. @@ -74,12 +75,11 @@ Once you have downloaded the script, open it in a text editor and set the requir
  9. Launch new instance
    1. Fill in the server name.
    2. -
    3. Select 'Amazon Linux'.
    4. -
    5. Under Amazon Machine Image select the Linux distrubution of your choice. The supported disibutions are: `Amazon Linux 2023 AMI`, `Ubuntu`, `Red Hat` and `Debian`
    6. +
    7. Under the Quick Start tab select the Linux distribution of your choice. The supported disibutions are: `Amazon Linux 2023`, `Ubuntu 24.04`, `Red Hat Enterprise Linux 10` and `Debian 13`
    8. Fill in the other settings based on your networking and business needs.
    9. Under 'Advanced details':
        -
      1. Set the 'IAM instance profile' to the policy you created in the steps above.
      2. +
      3. Set the 'IAM instance profile' to the policy you created in the perperation step above.
      4. At the bottom, under the 'User data' section, press 'choose file' and select the script saved above.
    10. @@ -114,7 +114,7 @@ The installation log file can be found at: `C:\Users\Administrator\install.log`. If an error occurs while the installation is running, a message will be inserted into the installation log file, it will attempt to roll back any work that it preformed, finally the script will terminate. -**Note:** It can take 10 to 15 minutes for the script to compplete. Check the installation log file to confirm it is done. +**Note:** It can take 10 to 15 minutes for the script to complete. Check the installation log file to confirm it is done. The line `Uninstall script removed` should be at the bottom of the file when the script has finished. ## Author Information From eb9de43e80e6bb09e945f1c03a1e533649fb5d59 Mon Sep 17 00:00:00 2001 From: Keith Cantrell Date: Wed, 25 Mar 2026 17:43:33 -0500 Subject: [PATCH 5/5] Add support for multiple Linux distributions. --- .../README.md | 20 +-- .../build_linux_userData | 2 +- .../linux_userData.sh | 166 +++++++++--------- .../linux_userData_real.sh | 9 +- 4 files changed, 100 insertions(+), 97 deletions(-) diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md index 73f3920..5653b75 100644 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/README.md @@ -5,13 +5,13 @@ These sample scripts provide a way to launch an AWS EC2 instance with `user data volume and LUN, mount it to the instance, while installing all the needed libraries and resources. ## Notes -- LUN size will be set to 90% of the volume size, the remain space is needed for the the LUN managment operation. - This means that usuable volume size is 90% of the requestd size. -- The process might take several minutes to be compleetd. +- LUN size will be set to 90% of the volume size, the remaining space is needed for the LUN management operation. + This means that usable volume size is 90% of the requested size. +- The process might take several minutes to be complete. -## Perperation +## Preperation -1. Create an AWS SecretsManager secret to hold the password of the account you plan to use to authenicate to the FSxN file system with. +1. Create an AWS SecretsManager secret to hold the password of the account you plan to use to authenticate to the FSxN file system with. The secret should be of type `other` with value set to `Plain Text` that holds just the password. 2. Create an AWS IAM role that has EC2 as the trusted entity and has permissions to read the secret value. Here is an example policy that will do that: ```json @@ -34,7 +34,7 @@ The secret should be of type `other` with value set to `Plain Text` that holds j ## Deployment Options There are two ways to deploy an EC2 instance with the needed user data script: -1. Copy the CloudFormation template found in the repo [EC2-cloud_formation.yaml](EC2-cloud_formation.yaml) to you local machine and deploy a CLoudFormation stack using it. CloudFormation will prmopt you for all the required parameters. +1. Copy the CloudFormation template found in the repo [EC2-cloud_formation.yaml](EC2-cloud_formation.yaml) to you local machine and deploy a CloudFormation stack using it. CloudFormation will prompt you for all the required parameters. 2. Follow the instruction below to deploy an EC2 instance from the AWS console. ## AWS console deployment @@ -45,8 +45,8 @@ with `Amazon Linux 2023`, `Ubuntu 24.04`, `Red Hat Enterprise Linux 10` and `Deb while the Windows script is designed for `Windows Server 2025 Base`. Note that since AWS has a 16KB limit for the user data the linux_userData.sh script is made up of the variable - assignment noted below, and a compressed, based64 encoded version of the `linux_userData_real.sh` script. When the - `linux_userData.sh` script is run, it will decode and uncompress effecitively the `linux_userData_real.sh` script + assignment noted below, and a compressed, base64 encoded version of the `linux_userData_real.sh` script. When the + `linux_userData.sh` script is run, it will decode and uncompress what was the `linux_userData_real.sh` script and run it. Once you have downloaded the script, open it in a text editor and set the required values as noted below. @@ -75,11 +75,11 @@ while the Windows script is designed for `Windows Server 2025 Base`.
    11. Launch new instance
      1. Fill in the server name.
      2. -
      3. Under the Quick Start tab select the Linux distribution of your choice. The supported disibutions are: `Amazon Linux 2023`, `Ubuntu 24.04`, `Red Hat Enterprise Linux 10` and `Debian 13`
      4. +
      5. Under the Quick Start tab select the Linux distribution of your choice. The supported distributions are: `Amazon Linux 2023`, `Ubuntu 24.04`, `Red Hat Enterprise Linux 10` and `Debian 13`
      6. Fill in the other settings based on your networking and business needs.
      7. Under 'Advanced details':
          -
        1. Set the 'IAM instance profile' to the policy you created in the perperation step above.
        2. +
        3. Set the 'IAM instance profile' to the policy you created in the preperation step above.
        4. At the bottom, under the 'User data' section, press 'choose file' and select the script saved above.
      8. diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData index 4db3e56..0601d01 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/build_linux_userData @@ -6,7 +6,7 @@ # user data content. # # This script is used to create the linux_userData.sh script from the -# linux_userdata_real.sh file. +# linux_userData_real.sh file. ################################################################################ cat <<'EOF' > linux_userData.sh diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh index 033a227..cfb8d08 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData.sh @@ -45,89 +45,89 @@ export ONTAP_USER="$ONTAP_USER" EOF2 cat <> /tmp/linux_userData.sh -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 -BtroE5gZpuWvVv8XVPIEubpEAAA= +H4sIAAAAAAAAA908aVPbSNrf9St6FA2GDJJsJslOPOOkvOAkrjVHYchkd5jXJaQ2aJAlRQdHiP/7 +Pk8fUkuWwbAkU/WmZsDu47nPVotnP9infmifOum59kx7RsZ+6FLiT4lzlRIf/gvTzAkC6hE/I2cR +xZEsInaeJnYQuU6A2y3toH/0oWfc4q95tzqpaaP995N3w9GgZ186OHFm+6mb+qaAbcGIdjTcHewf +H/VeMire04xk55Ts22My8sP8mnh+miX+aZ75EaCziE0z145SM6EBdVKqufCD6MZwRwcCNUKc2Zfw +q0uB1vRrck6DDRgjZH88Ofr3waCHI7/+CkP5aR5m+VePnvpOWF3Dx9iq53yGuucR0Y/DizC6CmEd +yW5i2iUtwNqydPLmDTEkq3z9NcisAxBo6riadkazMXUTmn10gpyub5BbWJWykYmThD2jA9/Hg+3D +wdHkY390POjpxjqqga9JZ07onNGEAByTD5mXCImcMGymHPQ9EEQJVy/mP+c0uSEtTsQYxBmetYrJ +KM/iHKROr7MNXYNBsIE/iPGWmCElbfLnr6iQUJHDO8dHswBjAGiJTy8pUxlHTKZJNAPJlGS0Nkn/ +NEoyQGrpinjg49TX5hoYwS5NU+BQSIZjMdY9J6MbxCRGpybiueaeU/diO5qBZDyxaznVJQKA2iFT +Rr5VJ8qy81DaJbjEIp2O5x2HXlTFmoIgTJ/oHR+prECYayNnduo5gySJkneAs6fb2Sy2AzY6oTiM +HqCLdYc0jaMwpYtLEzFj/ZVGoa754WV0QfkmQQYaC19M+Gyh3Wkeuug6ZujMgH/QRxcWd/nirnHb +/308ORy8H+7vzbv/6Pyy9Y+fX7x8+eLVz125sZvQmAvKnEWhn0VoPaYHYeM0chLPzFGwpanFzk0Q +OWiIo/7uP3f6k4P+v0f7/Z1yhRv4JkQHJ7kxp1EyczKSOFcQEkwIRfTVC7RHsdZYFAzZemPUxAqC +Tujn3E+otz3z0p7u5kkAqvjix+Svz+TUJdfXHkgN7UM3hJPrpNcjOkYDXbGVm3xG8hjtjpg38F01 +M6KXs2gxQDtxZxAdQ2Ko+H8lXsSoB4Q/EFdsNi+JgavX3hDbo5d2mAeBYqJVIx1yIwI5s026WCI4 +wBFG/V+f9Yqd479n5B3QdfhhMLK3IQbujzdlIEdZMN8cHAxGBJWaojJviq3Inlxr3hAa06AIsnJN +VSCCzspSJhegTGwBz2mEjlxod8FUGa96HldEQmfRJZWg+EqGzItCWkQxnhd+AGFhWqiKi5mJmZLz +LIvTrm2DW4BpWs7M+RKF8MUC3YlBk15TM8B0ZF7/8mry6oWFxmVGhE9fbuF3BpSbnfl5ccZCWLYQ +ARtJZsRMeL6trQZGaNBksDw1qXw4cWZCXpBmq5gXAV9Z6/wtliqJeiqFS3h3K/2bqHSZQuvqXKZM +IE8bHe9NxsP/DHrGOkQjMyC//fYb0dvW6/Zz4+P+6Hh3wKZ1ssGW7vV3YemtmMFv84mxvm4c9vd2 +9nd/XH/dbm/81IEfG5rGc+UzciwzD8gjgHD8ppqL3PNZ5JH8p+vqsKbqEksvkcPBlBy9VraAKd6K +GqV/uDfXtXfjT3sQ3cfj3/cPd3rlLKtgYF6FPS7hFkWDR9LcdWHFFCzsRteEAe7Q1E38GFNPrzAO +pijij7fHQxI77gUATasYjNvF/fPVo75iqWD0vkvNmRPHNDFneZD5sZOdE1m6+pnvQOA0oSIN0oUk +sYSO+4LYg5DqTxEdRHBocNUCu5lFUZCSKKahyQh5PLeLHrwci45O02QNYwDAtqWgdRghmT+jWC6w +vNbZaqdYlL5czTJE5dZK7TDyqCVAWgykBekxcFw6gxQ6kUh6xHq++tqXdou3Kowl/tOD+BNOtTPY +QfTVIenLAK2ki7omvjHfoIWlnDf7+DhzkowbOsSfBP1gNQXepBmduRnUH6FzCqUhx6SMpyVkbzVh +PeP2LelACFmean46BCCuP+bDh3kIUfQMwnmJy09NB+pltG1ot3wq8VoS1NqaaGygT/j6VXxu6xsy +RDXj0IlJP5PO0n6mIjZs2xOxT2vKoyW5pgmtLPbWiuSsQvo0EDXfnajCKJPoNokjuqn7mqn7XJtF +PTQW/4wVLk6eRdAj+C7r2yB2JKvHfRkdG6M+ITPEhahAGsKETPPKz84nBSUe4fXxilFvUeIqDiHt +InpXyFuM3dBc1i28pKs2zy29Nr0y0X76IMNWpLPUqJV+pQ69yaTrtqagWGbbD7HvEpw4gAiUnuZ+ +vHcY+hJjVwyel6hYBlqVsChTOvblFs+u1cpazO9h3+6nXWLcVsZAd5UNRzRFstB3Qso6d0yG+3tH +/QNL18BvMHTLVho0LGrlGTHECRwxP5H3A/iVY12B+ybH48Gh3tWNSqkH+rsguiyx+Vx/Z3e4Nxke +2E7s226QgxqSt1OfBtCPC9RgINiCmgmxxEgR+mrE8WIGixQdC3LzS9OSZQFxe5F9ceJTqu7eEx/U +1lkS5TEKGmR1HqUZ6gkofo/DQAYYyjcVYpxEWeRCYWSnTmj7jJr0bXo5s0JG0/jjLmsN1vjXgtq1 +wrBSsbJiNWsSbo+Z3FqUTvAss8cKbExGcvHg2k+zFFgUp3G3KudzocyWFeazSULdKPHSVpnKqkC4 +wy8/kysIXDBxgtGYMN5gruBxDv0e5W5JEcMmge7CYdbvZ0K5FZvAWXCiAg+HiOnlEt2cJuhdUqJz +Pt2tYiw2Nzkii7YMyQrmcbA/Xsk+PjBjzqC8Mo/YcTP0BoHvOmjbNjsJfJQNwS6PtG5FmNLlGr0r +Mry+KadKS4LJP4q4dlt8gjVoYri1VTWzVhkd5+LTnwVcYXO4jZtdMVNCKyTfKmfB+GGyRK8sl7or +8HKs85bIRP/Pvbbk8Tj3Pem0NZ8t4m/LEh77x58wltIA4uU6Q8sCb0X4ZAOWWDlABVGWWd0M0c0L +jIvnkM3+3eDJV04qXKd6HsBd//h4uNMtGEFU83sy+L3IMGoIhI9K5pjNG0u9RqvaGYwGRwM0rBPV +sk707knNtk6YcZ082LpsRQ8n+pLa/REh1glASN4Nj7DpJkkv/DhmBQaLtdAGsj5dfWg32N7i5wgh +9IVkuGNpR/v/GuyVHgfBD8TCWAQOO69eW1svX1jitx2ATtKMcZpFFzTkMfCT6VylJnW3zBnNHDxB +MtmsmWUBPviKQg+Ko63OqzZrphh6l06YGwi0d0AB42I06uRuonCXidtsicH0vQ2tfHpSYHtSZEWH +bSf0jJVMPMeymkjhVXVAVQR6zp9ZMlVpDTnxMgryGa2mPxjDAfX8kaT+F6oM4nHlHLyGO9JHBuRp +st7d8TUFswXybU62ksuUXKDQzZOHjsRX5pD81pmYzPCBDsxGIYRTKgaVVLMszczZSufsDFSDesMk +WduBkx22lmU/fZI5Z2Uy1aWmhl63pWpT5jwd6070Rpgua9BidhblYXYQ+WHWrXEN839qmPzSgNKY +dNraX9Hp0FOquUXFzXUlQcByGfTh45idgqhu/JR9gg0YIIoxCvUCHy2JLShQKWRqK0tOuYs/7BGJ +ZHmXwBkvQhmB7dAsejw5RLM4oOAbajqqpwrYwB5A3kMle8grihAVP9tLPPBzP8DWToJbpTG5XMHb +nkQ/NWd7ywuTSlxYK0ubMoCAEvmW42NftbnLZdZ2TzlSMe1KQVLWIiXCe5Vei2yrFSAl/PmSFLsc ++h0Vx52a/v4FRk3jdoVvLC6aUgg/Fwzy8P4sIhbJh1xlWpFPyOZnZP11+0cSTUVm2pA5ZpSH3zPB +AKWN2QVFY1e5sg3Jj0w3MSTtMn2U2Udy2Xr/TxnDUXaT7NwPJ1DcXfp4xgHGMUnzGC9dTPi5nwfb +sySnRdJZPT0t9FosLQSLwnzimIHykwdA6Ky84blTehA2kDC1g4GgUZD6gIhxj5KWhBCBe3n8AAgV +410tcgiwy8JGE9DHBoy/MWKgvu2S2WWxwiH4hBO7CPbIDpsGFMBNlBeSzCI2zLsbdUZn5rHrPNHx +ykMaecCLj2bViABDiy7IDK9VtbwWDhT6VVyTc9jkx0obpqxf4vRlyFXWguh91wkmYCzZJMxnpzSB +1W3u/GrScgKfPRlGkQNLhXoU29bZBcYRE/13PDyRMn8LH6zl0aMU7RoXqCxHShkuK1IAMOucuW2q +QafgtxJ0Gs86a0DuO+tEa1dl/ChXXxpIGrRXu2Tx90SJ76pZjD3sQjNNfCcg5/SahJR6IAo88MVD +DfZM6DSI3Atx74IgDGHlfNse85nvWGSrCTNlJEi/hS5OIWnBShfpfXCmVOS+mCcrxLQkMR/otaSE +Jc9blUZGwPW1R8x4QzmvKHYuT7FCZxwZ05dMEeIxnHMJHRPq72GJsX7PiWUYVrdC90yTKZ5XgVsk +sIamBV6wLrWkZTeihnJ9+h2MI6TZVZRc2H5sF3Q2HicLw/FjPAJDvjrDg9JSGshe2UQYtElHZ7bg +x5aQUkvg2XpaPFsNeJQSTbIGBoSPntXRLTaqmFVdDMatHPnRfj7fKNdsLazZUtcsXoF4gMkQJ2H9 +jUQNAxBxSzTLqsJHIfpfHKTpTsYOUIEXLhi+zEnYNTF2BQ9vA6WbwoOGBxUOV7uegasdb0ZMcwaw +8EE9Q3WD7yPExR1sE3sXsJXQ4+hTvGAOTEGIKGzhcbeg7iHAo+wE6E4CVJa/GXhuI/X4xR51So3I +43xd4yPF+T5Y9RPKGfzSubqA6jdOwC6JsTVvwdA5pFP0wk61rjyq0SYuMNQIRM7qFKJpEfOIGLW1 +VYJDUrmQFiYT8THF+8u/VAU2is74u0t1iTWT9ACKsMwO71X+3QCiPOP1St/zmKdNoyCIrlDDaXmR +ASfY7ZHihgq7Ucdu+3Zhs0enDsyk0B88A8/OIddOpokPGg1uJhhkU3JDUzY39UOvvOEkx+fwvzLI +wShXssQA/ru68j3y86t222m//qUtUz/k9Xm5BvoKqEGrJR2fnTNkqn6OuVKXsbdJ+qDas5AVaSgL +tXKzwIQgtQ77o8mHwadeWWNo/dGwP+6ptY22vb/3rteAhqUYyq5lmp+Jzmg/yZ4btwzG3NCJgVuL +5MLTHTuw3cSxhN0Skg/MnFBw74dMbQ0sFVGcH3KRlsEwtWovJS2EbOUOXcxpAhHjr/nk1HEv8lhc +9H714gWfZpxJxlrSSFo1fthD3WJVg+0sbijefGrZDevttGnUet40ivZnCwT1R7sFDkm57ZycZEuA +qDDEaycqWzWzv5Ol2lpgpzYCrDS40cPYaABQY6EAwULulOgnYennJ+FSSeBUA/STcH4S8lfpGBbM ++6rht/5PDQCLAirYqKxjvChxApGfZNUY0WJvB0gvnestvoi7CU5yR+PjQKSUw4IAVMS49h68RolU +xci9TeBalMlibPKWBie8bodXdCCVrLtOxqHga5RNBRWUxLV7miwQVGHzq9LEPXfCVV9yKK89JgsY +5KXeR14WXwHy4i4ITg3yEiGqaap+WIiksttcUxYlQ3pFYkDus2zILyRAgBSXznuv2xqrlC+doPcS +bMaJwVJ7bU27OkcN/UEMMUbMADQk76r/qb7/BK0EIGZvR/B3MCpd8d33W46ARHGOoG4qCZWbTiFB +XKjxiT+eNST1Im5w+o31dUn2T0Su2NjQ2KtOjOIfHkDzKvRWL9WlFhlAull2XZLUOwjPh/4OXyic +oFp7szDT2APqSYxPqKuJuNE7xBEx20TYJmIbt1WweCykQF2t2ZhdABCAVQVlGwqgx3mHeOfrTshL +QoFgloUQ7mQ8FKjKlFFxNR6nqUWvsxdVEAzCasw1krnLlMGq0pLS1QhiO000pkaivoU+co70Mfr4 +CHXj9IadDtpXiY+PKvgVglV45fUgXt0R1uuzNznwLbw7abFxC7714VvZNfDs3EN7ff0qMgIbfQjM +Crvvxp9C0fGLQpWzVx4pW0vEib0MX4t/MgID/hQCx+kDpPlQi+F2JsujzUlIM4BA2qTNsntJw//2 +1pThtSr8VBg6ZG/KE/5GfGWmn4HfxKxtH6mv6eta9S35XusWq4QoT1x6kETAfObjzaJbfczG9K6+ +Q+MgupkMtrcmv/tfnMTTN2ELXg6DSWgkihtpLX2OM59zUPARewasb4+G+rylVf6CgFb7wwl4sFa0 +QrxVDvwv7L2N+pv3ZOtN0yvCld5bclvC2WRvgN6w/B6STju1LJFhittKLCmrNIpSldN55wOWY/ar ++JsFxW2e+oOQxmO3+mb+4sDi5bkxs5QlsNEnMDNMq+/a/heZnhrpcEUAAA== EOF3 chmod +x /tmp/linux_userData.sh diff --git a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh index 6bca031..ceed41d 100755 --- a/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh +++ b/Management-Utilities/ec2-user-data-iscsi-create-and-mount/linux_userData_real.sh @@ -161,7 +161,7 @@ logMessage "InitiatorName is: ${InitiatorName}" logMessage "Testing connection to ONTAP." versionResponse=$(curl -sm $TIMEOUT -X GET -u "$ONTAP_USER":"$FSXN_PASSWORD" -k "https://$FSXN_ADMIN_IP/api/cluster?fields=version" | jq -r .version) -if [ "$versionResponse" == "null" ]; then +if [ "$versionResponse" == "null" -o -z "$versionResponse" ]; then logMessage "Connection to ONTAP failed, aborting." ./uninstall.sh exit 1 @@ -205,6 +205,8 @@ fi # Get the EC2 instanace ID. TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") instance_id=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id) +AWS_REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) + if [ -z "$instance_id" ]; then instance_id="unknown" fi @@ -327,7 +329,8 @@ else exit 1 fi -logMessage "Discover the target iSCSI nodes, iscsi IP: ${iscsi1IP}" +commandDescription="Discover the target iSCSI nodes, iscsi IP: ${iscsi1IP}" +logMessage "${commandDescription}" iscsiadm --mode discovery --op update --type sendtargets --portal $iscsi1IP checkCommand "${commandDescription}" addUndoCommand "iscsiadm --mode discovery --op delete --type sendtargets --portal ${iscsi1IP}" @@ -366,7 +369,7 @@ if egrep -q "alias\t*${ALIAS}$" $CONF; then exit 1 fi cp $CONF ${CONF}_backup -chmod o+rw $CONF +chmod 644 $CONF if grep -q 'defaults' $CONF; then if grep -q 'user_friendly_names' $CONF; then