#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail
shopt -s globstar

PRETEST_TIME=$(( $PRETEST_FINISH_TIME - $TEST_START_TIME ))
echo "Pretest setup runtime: $((($PRETEST_TIME / 60) % 60))m $(($PRETEST_TIME % 60))s"

INFRASTRUCTURE_DEPLOY_TIME=$(( $INFRASTRUCTURE_DEPLOY_FINISH_TIME - $PRETEST_FINISH_TIME ))
echo "Infrastructure stack deploy runtime: $((($INFRASTRUCTURE_DEPLOY_TIME / 60) % 60))m $(($INFRASTRUCTURE_DEPLOY_TIME % 60))s"

INFRASTRUCTURE_DESTROY_TIME=$(( $INFRASTRUCTURE_DESTROY_FINISH_TIME - $INFRASTRUCTURE_DESTROY_START_TIME ))
echo "Infrastructure stack cleanup runtime: $((($INFRASTRUCTURE_DESTROY_TIME / 60) % 60))m $(($INFRASTRUCTURE_DESTROY_TIME % 60))s"

read_exit_code() {
    EXIT_CODE_FILENAME=$1

    # Read the test run exit code from the file
    if [[ -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/${EXIT_CODE_FILENAME}" ]]
    then
        COMPONENT_EXIT_CODE=$(cat "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/${EXIT_CODE_FILENAME}")
        echo $COMPONENT_EXIT_CODE
    else
        echo -1
    fi
}

# Function pulls test results from test output file and calculates time spent on each stage of the test
report_results () {
    COMPONENT_NAME=$1

    echo
    echo "============================================================"
    echo "[${COMPONENT_NAME}]: TEST REPORT"
    echo "============================================================"
    echo

    # Read the test run exit code from the file
    COMPONENT_EXIT_CODE=$(read_exit_code exitcode)
    if [[ $COMPONENT_EXIT_CODE -ge 0 ]]
    then
        echo "Exit code: ${COMPONENT_EXIT_CODE}"
    else
        echo "Exit code: (unknown)"
    fi
    echo

    # If the component failed, output the deploy and destroy logs for debugging
    if [[ $COMPONENT_EXIT_CODE -ne 0 ]]
    then
        SYNTH_EXIT_CODE=$(read_exit_code synth-exit-code)
        echo

        if [[ $SYNTH_EXIT_CODE -ne 0 && -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/synth.log" ]]
        then
            echo "----------------------------------------------"
            echo "[${COMPONENT_NAME}]: Synth Log"
            echo "----------------------------------------------"
            echo

            cat "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/synth.log"

            echo
        fi

        DEPLOY_EXIT_CODE=$(read_exit_code deploy-exit-code)
        if [[ $DEPLOY_EXIT_CODE -ne 0 && -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/deploy.txt" ]]
        then
            echo "----------------------------------------------"
            echo "[${COMPONENT_NAME}]: Deployment Log"
            echo "----------------------------------------------"
            echo

            cat "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/deploy.txt"

            echo
        fi

        if [[ -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/destroy.txt" ]]
        then
            echo "----------------------------------------------"
            echo "[${COMPONENT_NAME}]: Destroy log"
            echo "----------------------------------------------"
            echo

            cat "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/destroy.txt"

            echo
        fi
    fi

    if [[ -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-output.txt" ]]
    then
        echo "----------------------------------------------"
        echo "[${COMPONENT_NAME}]: Test output"
        echo "----------------------------------------------"
        echo

        cat "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-output.txt"

        echo
    fi

    if [[ -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-report.json" ]]
    then
        # Get test numbers from jest output
        TESTS_RAN=$(node -e $'const json = require(process.argv[1]); console.log(json.numTotalTests)' "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-report.json")
        TESTS_PASSED=$(node -e $'const json = require(process.argv[1]); console.log(json.numPassedTests)' "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-report.json")
        TESTS_FAILED=$(node -e $'const json = require(process.argv[1]); console.log(json.numFailedTests)' "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-report.json")

        echo "Results for test component ${COMPONENT_NAME}: "
        echo "  -Tests ran:     ${TESTS_RAN}"
        echo "  -Tests passed:  ${TESTS_PASSED}"
        echo "  -Tests failed:  ${TESTS_FAILED}"

        if [[ -f "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/timings.sh" ]]
        then
            # File contains bash variable declaration syntax for:
            #     ${COMPONENT_NAME}_START_TIME
            #     ${COMPONENT_NAME}_FINISH_TIME
            source "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/timings.sh"

            DEPLOY_START_TIME=${COMPONENT_NAME}_START_TIME
            DEPLOY_FINISH_TIME=$(node -e $'const json = require(process.argv[1]); console.log(json.startTime)' "${INTEG_TEMP_DIR}/${COMPONENT_NAME}/test-report.json")
            DEPLOY_FINISH_TIME="${DEPLOY_FINISH_TIME:0:10}"
            DESTROY_START_TIME=$(node -e $'const json = require(process.argv[1]); console.log(json.testResults[0].endTime)' "$INTEG_TEMP_DIR/${COMPONENT_NAME}/test-report.json")
            DESTROY_START_TIME="${DESTROY_START_TIME:0:10}"
            DESTROY_FINISH_TIME=${COMPONENT_NAME}_FINISH_TIME

            # Calculate seconds from when deploy began to when test began
            DEPLOY_TIME=$(( $DEPLOY_FINISH_TIME - $DEPLOY_START_TIME ))
            # Calculate seconds from when deploy ended to when teardown began
            TEST_TIME=$(( $DESTROY_START_TIME - $DEPLOY_FINISH_TIME ))
            # Calculate seconds from when test ended to when teardown finished
            DESTROY_TIME=$(( $DESTROY_FINISH_TIME - $DESTROY_START_TIME ))

            echo "  -Deploy runtime:     $((($DEPLOY_TIME / 60) % 60))m $(($DEPLOY_TIME % 60))s"
            echo "  -Test suite runtime: $((($TEST_TIME / 60) % 60))m $(($TEST_TIME % 60))s"
            echo "  -Cleanup runtime:    $((($DESTROY_TIME / 60) % 60))m $(($DESTROY_TIME % 60))s"
        fi
    fi
}

# Report test results for each test component
for COMPONENT in **/cdk.json; do
    COMPONENT_ROOT="$(dirname "$COMPONENT")"
    COMPONENT_NAME=$(basename "$COMPONENT_ROOT")
    # Use a pattern match to exclude the infrastructure app from the results
    if [[ "$COMPONENT_NAME" != _* ]]; then
        report_results $COMPONENT_NAME
    fi
    export ${COMPONENT_NAME}_FINISH_TIME=$SECONDS
done

exit 0


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Script to run end to end test for configured RFDK components
# Configuration information for each test is drawn from integ/test-config.sh
# Script handles stack deployment, execution of the necessary tests, and teardown

set -euo pipefail
shopt -s globstar

USAGE="Usage: ./$0 [-d]

Runs the RFDK integration tests.

Options:
  -d Runs in development mode. CloudFormation stacks will not be torn down and temporary script output will not be deleted.
  -h Displays this help text.
"

export DEV_MODE=${DEV_MODE:-false}

while getopts "hd" opt; do
  case $opt in
    h)
        echo "${USAGE}"
        exit 1
    ;;
    d)
      export DEV_MODE=true
      echo "Running in development mode..."
    ;;
    \?)
        echo -e "\n${USAGE}" >&2
        exit 1
    ;;
  esac
done

SCRIPT_EXIT_CODE=0

echo "RFDK end-to-end integration tests started $(date)"

# Mark test start time
export TEST_START_TIME="$(date +%s)"
SECONDS=$TEST_START_TIME

export INTEG_ROOT="$(pwd)"
BASH_SCRIPTS="$INTEG_ROOT/scripts/bash"

# Load environment variables from config file
if [ ! "${SKIP_TEST_CONFIG-}" = true ]; then
  # Load variables from config file
  echo "Loading config..."
  source "$INTEG_ROOT/test-config.sh"
fi

# Set variables from script
source $BASH_SCRIPTS/set-test-variables.sh

# Make sure SSPL license has been accepted if running repository test
if [ ! "${SKIP_deadline_01_repository_TEST-}" = true ]; then
    if [ $USER_ACCEPTS_SSPL_FOR_RFDK_TESTS != true ]; then
        echo "Error: SSPL license has not been accepted for repository test; test will not run. See README.md for details"
        exit 1
    fi
fi

# Create temp directory
export INTEG_TEMP_DIR="$INTEG_ROOT/.e2etemp"
rm -rf $INTEG_TEMP_DIR
mkdir -p $INTEG_TEMP_DIR

# Stage deadline from script
if [ ! -d "${DEADLINE_STAGING_PATH}" ]
then
  $BASH_SCRIPTS/stage-deadline.sh
fi

# Extract the Deadline version to use for Deadline installations on the farm.
# Tests allow not specifying or specifying a partial version string such as "10.1.12". After staging, we
# obtain the fully resolved version (e.g. "10.1.12.1") which is required to determine
# the matching AWS Portal AMI IDs
export DEADLINE_VERSION=$(node -e $'const json = require(process.argv[1] + \'/manifest.json\'); console.log(json.version)' "$DEADLINE_STAGING_PATH")

# Find Deadline AMIs based on supplied version
source $BASH_SCRIPTS/fetch-worker-amis.sh

# Create a unique tag to add to stack names and some resources
if [ -z ${INTEG_STACK_TAG+x} ]; then
    export INTEG_STACK_TAG="$(date +%s%N)"
fi

# Mark pretest finish time
export PRETEST_FINISH_TIME=$SECONDS

# Define cleanup function for deployment failure
cleanup_on_failure () {
  if [[ "$DEV_MODE" == "true" ]]; then
    echo "Running in development mode, skipping cleanup..."
  else
    echo "Performing best-effort full cleanup..."
    yarn run tear-down
  fi
}

get_component_dirs () {
  # Find all "cdk.json" files (indicates parent dir is a CDK app)
  find . -name "cdk.json"           | \
  # Filter out node_modules
  grep -v node_modules              | \
  # Extract the directory name
  xargs -n1 dirname                 | \
  # Filter out apps whose driectories begin with an underscore (_) as this
  # convention indicates the app is not a test
  grep -v "/_"                      | \
  # Sort
  sort
}

# Deploy the infrastructure app, a cdk app containing only a VPC to be supplied to the following tests
$BASH_SCRIPTS/deploy-infrastructure.sh || (
  echo "$(date "+%Y-%m-%dT%H:%M:%S") [infrastructure] Error deploying infrastructure"
  cleanup_on_failure
  false
)

# Mark infrastructure deploy finish time
export INFRASTRUCTURE_DEPLOY_FINISH_TIME=$SECONDS

XARGS_ARGS="-n 1"
if [[ "${RUN_TESTS_IN_PARALLEL-}" = true ]]
then
  # Instruct xargs to run all the commands in parallel and block until they complete execution
  XARGS_ARGS="${XARGS_ARGS} -P 0"
fi

# At this point in processing, we don't want failures to abort the script
# All statements below this must execute
set +e

# Run the component tests (potentially in parallel).
get_component_dirs | xargs ${XARGS_ARGS} components/deadline/common/scripts/bash/component_e2e_driver.sh
# Capture the exit code for returning later from this process
SCRIPT_EXIT_CODE=$?

# Destroy the infrastructure stack on completion.
export INFRASTRUCTURE_DESTROY_START_TIME=$SECONDS     # Mark infrastructure destroy start time
if [[ "$DEV_MODE" == "true" ]]; then
  echo "Running in development mode, keeping infrastructure up..."
else
  $BASH_SCRIPTS/teardown-infrastructure.sh || (
    echo '$(date "+%Y-%m-%dT%H:%M:%S") [infrastructure] Error destroying infrastructure'
    # This is a best-effort since we always want to report the test results if possible.
    cleanup_on_failure || true
  )
fi
export INFRASTRUCTURE_DESTROY_FINISH_TIME=$SECONDS    # Mark infrastructure destroy finish time

echo "Complete!"

# Report results
$BASH_SCRIPTS/report-test-results.sh

if [[ "$DEV_MODE" == "true" ]]; then
  echo "Running in development mode, skipping folder cleanup..."
else
  echo "Cleaning up folders..."
  yarn run clean
fi

echo "Exiting..."

exit $SCRIPT_EXIT_CODE


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Used as the entry point to run the tests in an automated way. This expects the following env vars to be set:
# USER_ACCEPTS_SSPL_FOR_RFDK_TESTS - Needs to be 'true' to use these tests
#
# Each of these env vars must be set to assume an IAM role in a separate account.
# If at least one is not set, an IAM role will not be assumed.
# ROLE_ARN - The role that will be assumed to deploy the integ tests
# ROLE_SESSION_NAME - A name for the assume role session
# ROLE_EXTERNAL_ID - The external ID matching the assume role
# DEADLINE_VERSION - Optional, will default to the latest Deadline version if not set, otherwise the specified version will be used.

set -euo pipefail

if [ ! -z ${ROLE_ARN+x} ] && \
   [ ! -z ${ROLE_SESSION_NAME+x} ] && \
   [ ! -z ${ROLE_EXTERNAL_ID+x} ]; then

  unset AWS_ACCESS_KEY_ID
  unset AWS_SECRET_ACCESS_KEY
  unset AWS_SESSION_TOKEN

  TEST_PROFILE_NAME=integtestrunner
  # Set up the default profile to dynamically assume-role to the given ROLE_ARN whenever the credentials
  # need to be refreshed.
  # Reference: https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#using-aws-iam-roles
  aws configure --profile ${TEST_PROFILE_NAME} set role_arn ${ROLE_ARN}
  aws configure --profile ${TEST_PROFILE_NAME} set external_id ${ROLE_EXTERNAL_ID}
  aws configure --profile ${TEST_PROFILE_NAME} set role_session_name ${ROLE_SESSION_NAME}

  if [ ! -z ${CODEBUILD_BUILD_NUMBER} ]
  then
    # Running in a CodeBuild container.
    # ref: https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
    echo "Running in ECS"
    aws configure --profile ${TEST_PROFILE_NAME} set credential_source EcsContainer
  elif curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 5" 2> /dev/null >& /dev/null
  then
    # Running on an EC2 instance
    echo "Running on EC2"
    aws configure --profile ${TEST_PROFILE_NAME} set credential_source Ec2InstanceMetadata
  else
    # Not a container or EC2 instance. Use the AWS_PROFILE profile for the source credentials
    # for the assume-role; default to the 'default' profile is there is no AWS_PROFILE defined.
    echo "Non-AWS local run environment"
    aws configure --profile ${TEST_PROFILE_NAME} set source_profile ${AWS_PROFILE:-default}
  fi

  # Work around a CDK bug: https://github.com/aws/aws-cdk/issues/3396#issuecomment-990609132
  touch ~/.aws/credentials

  # Must be the last thing that we do in this code path.
  export AWS_PROFILE=${TEST_PROFILE_NAME}
  export AWS_STS_REGIONAL_ENDPOINTS=regional
fi

# Basic integ test configuration
export SKIP_TEST_CONFIG=true

./scripts/bash/rfdk-integ-e2e.sh

unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN
unset AWS_PROFILE


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

echo "Setting test variables..."

# Get region from CDK_DEFAULT_REGION; assume us-west-2 if it's not set
if [ -z ${CDK_DEFAULT_REGION+x} ]; then
    export AWS_REGION="us-west-2"
else
    export AWS_REGION=$CDK_DEFAULT_REGION
fi

if [ -z ${USER_ACCEPTS_SSPL_FOR_RFDK_TESTS+x} ]; then
    export USER_ACCEPTS_SSPL_FOR_RFDK_TESTS=false
fi

# Set staging path to default if not overridden
if [ -z ${DEADLINE_STAGING_PATH+x} ]; then
    export DEADLINE_STAGING_PATH="$INTEG_ROOT/stage"
elif [ $(ls "$DEADLINE_STAGING_PATH/manifest.json" 2> /dev/null) ]; then
    #If path is set, extract the Deadline version to use for Deadline installations on the farm. This will override any other Deadline version provided.
    export DEADLINE_VERSION=$(node -e $'const json = require(process.argv[1] + \'/manifest.json\'); console.log(json.version)' "$DEADLINE_STAGING_PATH")
fi


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

# Check if Deadline assets are staged at configured path
if [ ! $(ls "$DEADLINE_STAGING_PATH/manifest.json" 2> /dev/null) ]; then
    # If DEADLINE_VERSION is not defined set empty value to get the latest version
    if [ -z ${DEADLINE_VERSION+x} ]; then
        export DEADLINE_VERSION=""
    fi
    # Stage Deadline assets
    npx stage-deadline --output "$DEADLINE_STAGING_PATH" $DEADLINE_VERSION
fi

exit 0


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Script to remove all stacks deployed by the framework
# Searches for configured test components and runs cdk destroy on the app within
# User must set INTEG_STACK_TAG manually so that the program can find the randomized stack names

set -euo pipefail
shopt -s globstar

INTEG_ROOT="$(pwd)"
BASH_SCRIPTS="$INTEG_ROOT/scripts/bash"
INFRASTRUCTURE_APP="$INTEG_ROOT/components/_infrastructure"
source "$INTEG_ROOT/components/deadline/common/scripts/bash/deploy-utils.sh"

if [ -z ${INTEG_STACK_TAG+x} ]; then
    echo "INTEG_STACK_TAG must be set, exiting..."
    exit 1
fi

# Load environment variables from config file
if [ ! "${SKIP_TEST_CONFIG-}" = true ]; then
  # Load variables from config file
  echo "Loading config..."
  source "$INTEG_ROOT/test-config.sh"
fi

# Set variables from script
source $BASH_SCRIPTS/set-test-variables.sh

# This is a best-effort. If any component fails to destroy, we proceed and try
# the others. Disable the exit on error option
set +e

for COMPONENT in **/cdk.json; do
    # In case the yarn install was done inside this integ package, there are some example cdk.json files in the aws-cdk
    # package we want to avoid.
    if [[ $COMPONENT == *"node_modules"* ]]; then
        continue
    fi
    COMPONENT_ROOT="$(dirname "$COMPONENT")"
    COMPONENT_NAME=$(basename "$COMPONENT_ROOT")
    # Use a pattern match to exclude the infrastructure app from the results
    if [[ "$(basename "$COMPONENT_ROOT")" != _* ]]; then
        # Excecute the e2e test in the component's scripts directory
        cd "$INTEG_ROOT/$COMPONENT_ROOT" && ../common/scripts/bash/component_e2e.sh "$COMPONENT_NAME" --destroy-only
    fi
done

cd "$INFRASTRUCTURE_APP" && npx cdk destroy "*" -f

cd "$INTEG_ROOT" && yarn run clean

exit 0


#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

set -euo pipefail

source "$INTEG_ROOT/components/deadline/common/scripts/bash/deploy-utils.sh"

echo "$(timestamp) [infrastructure] destroy started"
INFRASTRUCTURE_APP="$INTEG_ROOT/components/_infrastructure"
cd "$INFRASTRUCTURE_APP"

mkdir -p "${INTEG_TEMP_DIR}/infrastructure"

# Hide the destroy log unless something goes wrong (save the scrollback buffer)
npx cdk destroy "*" -f &> "${INTEG_TEMP_DIR}/infrastructure/destroy.txt"
destroy_exit_code=$?

# If an exit code was returned from the destroy, output the destroy log
if [[ $destroy_exit_code -ne 0 ]]
then
    echo "$(timestamp) [infrastructure] destroy failed"
    cat "${INTEG_TEMP_DIR}/infrastructure/destroy.txt"
else
    echo "$(timestamp) [infrastructure] destroy complete"
fi

exit $destroy_exit_code


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script is meant to build a Lambda Layer using Docker. Its usage is:
#   build_layer.sh <layer_name>
# The layer_name should map to a directory under the layers directory. Full instructions on how to build and publish
# a Lambda Layer can be found in the README.

set -euo pipefail

if test $# -lt 1
then
    echo "Usage: $0 <directory>"
    echo "  Builds the layer located in <directory>"
    exit 1
fi

SCRIPT_DIR=$(dirname $0)
SCRIPT_NAME=$(basename $0)
if ! test -f ${PWD}/${SCRIPT_NAME}
then
    echo "Must be run from the directory containing ${SCRIPT_NAME}"
    exit 1
fi

LAYER_NAME=$(basename $1)
LAYER_DIR="${PWD}/../layers/${LAYER_NAME}"
if ! test -d "${LAYER_DIR}"
then
    echo "${LAYER_NAME} directory must a subdirectory of ${PWD}/../layers/"
    exit 1
fi

for file in layer.zip description.txt license.txt runtimes.txt
do
    test -f "${LAYER_DIR}/${file}" && rm -f "${LAYER_DIR}/${file}"
done

docker build -t "${LAYER_NAME}" "${LAYER_DIR}/"

# Run the docker container as the current user.
# For this to work we need to mount this machine's credentials files
# inside of the container as read-only.

USER_OPT="-u $(id -u):$(id -g)"
USERFILE_MOUNTS="-v /etc/passwd:/etc/passwd:ro -v /etc/shadow:/etc/shadow:ro -v /etc/group:/etc/group:ro"
docker run --rm \
    -v "${LAYER_DIR}":/tmp/layer ${USERFILE_MOUNTS} \
    ${USER_OPT} \
    "${LAYER_NAME}"


set -euo pipefail

echo "Cleaning aws-rfdk..."

rm -rf ./node_modules/

 if [ -f ./.jsii ]; then
     rm ./.jsii
 fi
 if [ -f ./tsconfig.json ]; then
     rm ./tsconfig.json
 fi

echo "Done aws-rfdk"


#!/bin/bash

set -euo pipefail

echo "Running python tests"

python3 -m unittest discover -s "$PWD/lib/deadline/scripts/python" -b

exit 0


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script downloads, installs and configures the cloudwatch agent. Must be run as sudo capable user.

usage() {
  echo "This script downloads, installs and configures the CloudWatch agent. Must be run as sudo capable user.
Arguments:
  -i: [Flag] Attempts to install the CloudWatch agent. If this isn't set we skip right to configuring it.
  -s: [Flag] Skips the verification of the CloudWatch agent installer. Only relevent if we are trying to install the agent.
  \$1: region
  \$2: SSM parameter name

Note: Flags must appear before positional parameters"
  exit 1
}

# Don't exit if commands fail
set -x

function install_agent {
  region="$1"
  # Check if amazon-cloudwatch-agent is already installed
  if rpm -qa | grep amazon-cloudwatch-agent
  then
    return
  fi

  TMPDIR=$(mktemp -d)
  pushd $TMPDIR 2>&1 > /dev/null

  # Download CloudWatch agent installer
  aws s3api get-object --region $region --bucket amazoncloudwatch-agent-$region --key amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm amazon-cloudwatch-agent.rpm

  if [ "$SKIP_VERIFICATION" = false ]
  then
    aws s3api get-object --region $region --bucket amazoncloudwatch-agent-$region --key assets/amazon-cloudwatch-agent.gpg amazon-cloudwatch-agent.gpg
    GPG_IMPORT_OUT=$(gpg --no-default-keyring --keyring ./keyring.gpg --import amazon-cloudwatch-agent.gpg 2>&1)
    GPG_KEY=$(echo "${GPG_IMPORT_OUT}" | grep -Eow 'key [0-9A-F]+' | awk '{print $2}')
    GPG_FINGERPRINT_OUT=$(gpg --no-default-keyring --keyring ./keyring.gpg --fingerprint ${GPG_KEY} 2>&1)
    GPG_FINGERPRINT=$(echo "${GPG_FINGERPRINT_OUT}" | tr -d '[:blank:]' | grep -Eo 'fingerprint=[0-9A-F]{40}')
    if test "${GPG_FINGERPRINT}" != "fingerprint=937616F3450B7D806CBD9725D58167303B789C72"
    then
        # Key failed to verify. Alert AWS!!
        echo "ERROR: Key failed to verify."
        popd
        rm -rf ${TMPDIR}
        return
    fi

    aws s3api get-object --region $region --bucket amazoncloudwatch-agent-$region --key amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm.sig amazon-cloudwatch-agent.rpm.sig
    if ! gpg --no-default-keyring --keyring ./keyring.gpg --verify amazon-cloudwatch-agent.rpm.sig amazon-cloudwatch-agent.rpm 2>&1
    then
        # CloudWatch agent installer failed to verify. Alert AWS!!
        echo "ERROR: Agent installer failed to verify"
        popd
        rm -rf ${TMPDIR}
        return
    fi
  fi

  # Run the CloudWatch agent installer
  sudo rpm -U ./amazon-cloudwatch-agent.rpm

  popd
  rm -rf ${TMPDIR}
}

echo "Starting CloudWatch installation and configuration script."

# Parse options
SKIP_VERIFICATION=false
INSTALL_AGENT=false
OPTIND=1 # Reset index for getopts in case of previous invocations
while getopts "is" opt; do
  case $opt in
  i) INSTALL_AGENT=true ;;
  s) SKIP_VERIFICATION=true ;;
  \?) echo "ERROR: Unknown option specified"; usage ;;
  esac
done
shift $((OPTIND - 1))

# Parse positional arguments
if (($# != 2))
then
  echo "ERROR: Invalid arguments"
  usage
fi
REGION="$1"
SSM_PARAMETER_NAME="$2"

# Check if we want to attempt to install the agent
if $INSTALL_AGENT
then
  install_agent $REGION
else
  echo "Skipped installation of CloudWatch agent"
fi

# starts the agent
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a append-config -m ec2 -c ssm:$SSM_PARAMETER_NAME -s

echo "Script completed successfully."


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script downloads and installs the Lustre client.
# See https://docs.aws.amazon.com/fsx/latest/LustreGuide/install-lustre-client.html

set -xeu
shopt -s extglob

trap exit_trap EXIT
function exit_trap() {
  if [[ $? -ne 0 ]]; then
    echo "ERROR: An error occurred while attempting to install the Lustre client on your device. \
    Please refer to the FSx for Lustre documentation: https://docs.aws.amazon.com/fsx/latest/LustreGuide/install-lustre-client.html"
  fi
}

function is_kernel_version_lower() {
  local IFS='.-'
  read -r -a lhs_array <<< "$1"
  read -r -a rhs_array <<< "$2"

  # Calculate minimum length betweeen the two arrays
  [[ ${#lhs_array[@]} -lt ${#rhs_array[@]} ]] && n=${#lhs_array[@]} || n=${#rhs_array[@]}

  unset IFS
  for i in $( seq 0 $((n-1)) ); do
    local lhs="${lhs_array[$i]}"
    local rhs="${rhs_array[$i]}"
    if [[ $lhs =~ ^[0-9]+$ && $rhs =~ ^[0-9]+$ && $lhs -lt $rhs ]]; then
      return 0
    fi
  done
  return 1
}

function install_on_al2() {
  architecture=$(uname -m)
  case $architecture in
    x86_64)   min_version="4.14.104-95.84.amzn2.x86_64";;
    aarch64)  min_version="4.14.181-142.260.amzn2.aarch64";;
    *) echo "ERROR: Unrecognized Amazon Linux 2 kernel version: $kernel_version"; exit 1;;
  esac

  kernel_version=$(uname -r)
  if is_kernel_version_lower "$kernel_version" "$min_version"; then
    echo "ERROR: Kernel version ($kernel_version) is lower than the minimum required version: $min_version"
    exit 1
  fi

  sudo amazon-linux-extras install -y lustre2.10
}

function install_on_al1() {
  min_version="4.14.104-78.84.amzn1.x86_64"

  kernel_version=$(uname -r)
  if is_kernel_version_lower "$kernel_version" "$min_version"; then
    echo "ERROR: Kernel version ($kernel_version) is lower than the minimum required version: $min_version"
    exit 1
  fi

  sudo yum install -y lustre-client
}

function verify_lustre_kmod() {
  if ! sudo modprobe -v --first-time lustre; then
    echo "ERROR: Lustre client kernel modules were not installed successfully. See above logs for more information."
    exit 1
  fi

  sudo lustre_rmmod
}

function install_on_rhel() {
  # Note: In addition to installing the lustre client packages, an additional "kmod-lustre-client" package also needs to be
  # installed. This package contains kernel-specific modules used by the lustre client.

  # Create map of RHEL release to kernel version shell patterns. See https://access.redhat.com/articles/3078
  # This mapping is needed to determine which version of the Lustre client to install based on the instructions at
  # https://docs.aws.amazon.com/fsx/latest/LustreGuide/install-lustre-client.html#lustre-client-rhel
  declare -A rhel_kernel_versions
  rhel_kernel_versions=(
    [7.5]='3.10.0-862.*'
    [7.6]='3.10.0-957.*'
    [7.7]='3.10.0-1062.*'
    [7.8]='3.10.0-1127.*'
    [7.9]='3.10.0-1160.*'
    [8.1]='4.18.0-147.*'
    [8.2]='4.18.0-193.*'
    [8.3]='4.18.0-240.*'
    [8.4]='4.18.0-305.*'
  )

  kernel_version=$(uname -r)

  id=$(grep ^ID= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
  if [[ $id = "centos" ]]; then
    # Map CentOS release to the RHEL release it was based on
    # This information can be found by referring to the CentOS release announcements
    # For example, see announcement for CentOS 7 (1804): https://lists.centos.org/pipermail/centos-announce/2018-May/022829.html
    #
    # The major and minor versions of CentOS releases match that of RHEL,
    # so we can just extract those bits and treat them as the RHEL version
    rhel_version=$(awk '{print $4}' /etc/centos-release | awk -F "." '{print $1"."$2}')
  else
    rhel_version=$(grep ^VERSION_ID= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
  fi

  case $rhel_version in
    # RHEL 7.5 and 7.6
    # ----------------
    7.5|7.6)
      case $kernel_version in
        ${rhel_kernel_versions[7.5]}) lustre_version="2.10.5";;
        ${rhel_kernel_versions[7.6]}) lustre_version="2.10.8";;
        *) echo "ERROR: Unsupported kernel version $kernel_version for RHEL $rhel_version"; exit 1;;
      esac
      sudo yum -y install "https://downloads.whamcloud.com/public/lustre/lustre-${lustre_version}/el7/client/RPMS/x86_64/kmod-lustre-client-${lustre_version}-1.el7.x86_64.rpm"
      sudo yum -y install "https://downloads.whamcloud.com/public/lustre/lustre-${lustre_version}/el7/client/RPMS/x86_64/lustre-client-${lustre_version}-1.el7.x86_64.rpm"

      verify_lustre_kmod
    ;;

    # RHEL 7.7, 7.8, and 7.9
    # ----------------------
    7.7|7.8|7.9)
      architecture=$(uname -m)
      case $architecture in
        x86_64)
          distro_name="el"
          case $kernel_version in
            ${rhel_kernel_versions[7.7]}) replace_ver="7.7";;
            ${rhel_kernel_versions[7.8]}) replace_ver="7.8";;
            ${rhel_kernel_versions[7.9]});; # Do nothing
            *) echo "ERROR: Unsupported kernel version $kernel_version for RHEL $rhel_version"; exit 1;;
          esac
        ;;
        aarch64)
          distro_name="centos"
          case $kernel_version in
            # RHEL 7.8 for ARM-based AWS-Graviton powered instances have the 8.1 kernel version (see AWS docs)
            ${rhel_kernel_versions[8.1]}) replace_ver="7.8";;
            ${rhel_kernel_versions[8.2]});; # Do nothing
            *) echo "ERROR: Unsupported kernel version $kernel_version for RHEL $rhel_version"; exit 1;;
          esac
        ;;
        *) echo "ERROR: Unrecognized architecture: $architecture"; exit 1;;
      esac

      curl https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -o /tmp/fsx-rpm-public-key.asc
      sudo rpm --import /tmp/fsx-rpm-public-key.asc
      sudo curl "https://fsx-lustre-client-repo.s3.amazonaws.com/${distro_name}/7/fsx-lustre-client.repo" -o /etc/yum.repos.d/aws-fsx.repo
      if [[ -n "${replace_ver+x}" ]]; then
        sudo sed -i "s#7#${replace_ver}#" /etc/yum.repos.d/aws-fsx.repo
      fi

      sudo yum clean all
      sudo yum install -y kmod-lustre-client lustre-client

      verify_lustre_kmod
    ;;

    # RHEL 8.2 or newer
    # -----------------
    8.[2-9]|8.[1-9]+([0-9]))
      case $kernel_version in
        ${rhel_kernel_versions[8.2]}) replace_ver="8.2";;
        ${rhel_kernel_versions[8.3]}) replace_ver="8.3";;
        *)
          if is_kernel_version_lower "$kernel_version" "${rhel_kernel_versions[8.2]}"; then
            echo "ERROR: Kernel version ($kernel_version) is lower than the minimum required version: ${rhel_kernel_versions[8.2]}"
            exit 1
          fi
        ;;
      esac

      curl https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -o /tmp/fsx-rpm-public-key.asc
      sudo rpm --import /tmp/fsx-rpm-public-key.asc
      sudo curl https://fsx-lustre-client-repo.s3.amazonaws.com/el/8/fsx-lustre-client.repo -o /etc/yum.repos.d/aws-fsx.repo
      if [[ -n "${replace_ver+x}" ]]; then
        # Change the baseurl referenced in aws-fsx.repo so we pull the correct version of the lustre client for this kernel
        sudo sed -i "s#8#${replace_ver}#" /etc/yum.repos.d/aws-fsx.repo
      fi

      sudo yum clean all
      sudo yum install -y kmod-lustre-client lustre-client

      verify_lustre_kmod
    ;;
    *) echo "ERROR: Unsupported CentOS/RHEL version: $rhel_version"; exit 1;;
  esac
}

function install_on_ubuntu() {
  ubuntu_version=$(grep ^VERSION_ID= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
  kernel_version=$(uname -r)
  architecture=$(uname -m)

  case $ubuntu_version in
    16.04)
      code_name="xenial"
      min_version="4.4.0-1092-aws"
    ;;
    18.04)
      code_name="bionic"
      case $architecture in
        x86_64)   min_version="4.15.0-1054-aws";;
        aarch64)  min_version="5.3.0-1023-aws";;
        *) echo "ERROR: Unrecognized architecture: $architecture"; exit 1;;
      esac
    ;;
    20.04)
      code_name="focal"
      case $architecture in
        x86_64)   min_version="5.4.0-1011-aws";;
        aarch64)  min_version="5.4.0-1015-aws";;
        *) echo "ERROR: Unrecognized architecture: $architecture"; exit 1;;
      esac
    ;;
    *) echo "ERROR: Unsupported Ubuntu version: $ubuntu_version"; exit 1;;
  esac

  wget -O - https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-ubuntu-public-key.asc | sudo apt-key add -
  sudo bash -c "echo \"deb https://fsx-lustre-client-repo.s3.amazonaws.com/ubuntu $code_name main\" > /etc/apt/sources.list.d/fsxlustreclientrepo.list && apt-get update"

  if is_kernel_version_lower "$kernel_version" "$min_version"; then
    echo "ERROR: Kernel version ($kernel_version) is lower than the minimum required version: $min_version"
    exit 1
  fi

  sudo apt install -y "lustre-client-modules-${kernel_version}"
}

function install_on_suse() {
  sudo wget https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-sles-public-key.asc
  sudo rpm --import fsx-sles-public-key.asc
  sudo wget https://fsx-lustre-client-repo.s3.amazonaws.com/suse/sles-12/SLES-12/fsx-lustre-client.repo

  sudo zypper -n ar --gpgcheck-strict fsx-lustre-client.repo

  suse_version=$(grep ^VERSION_ID= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
  case $suse_version in
    12.3) sudo sed -i 's#SLES-12#SP3#' /etc/zypp/repos.d/aws-fsx.repo;;
    12.4) sudo sed -i 's#SLES-12#SP4#' /etc/zypp/repos.d/aws-fsx.repo;;
    12.5);; # Do nothing
    *)
      echo "ERROR: Unsupported SUSE Linux version: $suse_version"
      exit 1
    ;;
  esac

  sudo zypper -n refresh
  sudo zypper -n install lustre-client
}

if lustre_version=$(lfs --version); then
  echo "Lustre client already installed: $lustre_version"
  exit 0
fi

echo "Installing Lustre client..."

os_id=$(grep ^ID= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
case $os_id in
  rhel|centos)   install_on_rhel;;
  ubuntu) install_on_ubuntu;;
  sles)   install_on_suse;;
  amzn)
    amzn_version=$(uname -r | awk -F "." '{print $5}')
    case $amzn_version in
      amzn1)        install_on_al1;;
      amzn2?(int))  install_on_al2;;
      *)
        echo "WARNING: Unrecognized Amazon Linux version: $amzn_version. Assuming Amazon Linux 2..."
        install_on_al2
      ;;
    esac
  ;;
  *)
    pretty_name=$(grep ^PRETTY_NAME= /etc/os-release | awk -F "=" '{print $2}' | sed s/\"//g)
    echo "ERROR: Unsupported operating system: $os_id ($pretty_name)"
    exit 1
  ;;
esac


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Script that will mount a given EBS volume for use.
# This script will:
#   1) Attach the volume to this instance if it is not already attached.
#   2) Format the block volume to the filesystem format that's passed as an
#      argument to this script. But **ONLY IF** the filesystem has no current format.
#   3) Mount the volume to the given mount point with the given mount options.
#   4) Resize the filesystem on the volume if the volume is larger than the formatted
#      filesystem size.
#
# Note: This does **NOT** support multiple partitions on the EBS Volume.
#       It's expected that we are using the root parition as the filesystem.
#
# Script arguments:
#  $1 -- EBS Volume Identifier (ex: vol-00000000000)
#  $2 -- Filesystem format.
#  $3 -- Mount path; directory that we mount the EFS to.
#        By default, we automatically search for an available one and use the first we find.
#  $4 -- Mount options for the filesystem; passed to the mount command.
#  $5 -- (optional) The device name to attach the EBS Volume to. If empty/blank, then this
#        script will automatically find an unused device to attach the volume to.

set -xefu

if test $# -lt 4
then
    echo "Usage: $0 <ebs volume id> <filesystem format> <mount path> <mount options> [<device attachment>]"
    echo " <filesystem format> must be one of: xfs  (that is all, for now)"
    exit 1
fi

SCRIPT_LOC=$(dirname $0)

source "${SCRIPT_LOC}/metadataUtilities.sh"

function get_attached_device() {
    # If the given EBS volume is attached, then return the device name it's attached under.
    # Usage:
    #   get_attached_device <EBS volume id>
    # ex:
    #   get_attached_device vol-1234ba726

    EBS_VOL_ID=$1
    METADATA_TOKEN=$(get_metadata_token)
    INSTANCE_ID=$(get_instance_id "${METADATA_TOKEN}")
    AWS_REGION=$(get_region "${METADATA_TOKEN}")

    # Example output:
    #  aws --region us-west-2 ec2 describe-volumes --filters Name=volume-id,Values=vol-0755e90763c1948ad Name=attachment.instance-id,Values=i-0241efb9b8268eff8  --query 'Volumes[].Attachments[].Device'
    # [
    #    "/dev/xvdz"
    # ]
    # If not attached, then the output is:
    # []
    DESCRIBE_OUT=$(aws --region ${AWS_REGION} ec2 describe-volumes \
                    --filters Name=volume-id,Values=${EBS_VOL_ID} Name=attachment.instance-id,Values=${INSTANCE_ID} \
                    --query 'Volumes[].Attachments[].Device' )
    if echo ${DESCRIBE_OUT} | grep 'dev' 2>&1 > /dev/null
    then
        echo $DESCRIBE_OUT | tr -d ']["[:space:]'
    else
        echo ""
    fi
}

function find_available_device_name() {
    # To attach an EBS volume to this instance we need to attach it to a specific device name
    # This function finds an unused device name for us to attach the EBS volume to.

    for suffix in $(echo {z..b})
    do
        DEVICE="/dev/xvd${suffix}"
        if ! test -e ${DEVICE}
        then
            echo ${DEVICE}
            return 0
        fi
    done
    return 1
}

function attach_ebs_volume() {
    # Attaches the given EBS Volume to this instance, and waits until it has
    # successfully attached.
    # Usage:
    #  attach_ebs_volume <ebs volume id> <device name of EBS volume>
    # ex:
    #  attach_ebs_volume vol-134fb8343 /dev/xvdz

    EBS_VOL_ID=$1
    TARGET_DEV=$2
    METADATA_TOKEN=$(get_metadata_token)
    INSTANCE_ID=$(get_instance_id "${METADATA_TOKEN}")
    AWS_REGION=$(get_region "${METADATA_TOKEN}")

    # Attach the EBS
    aws --region "${AWS_REGION}" ec2 attach-volume --volume-id "${EBS_VOL_ID}" --instance-id "${INSTANCE_ID}" --device "${TARGET_DEV}"
    # Wait until the volume has attached
    while ! test -e "${TARGET_DEV}"
    do
        sleep 1
    done
}

function is_partition_table() {
    # Determine whether or not the given device is a partition table.
    # Usage:
    #  is_paritition_table <device name>
    #  <device name> must be a regular file (no symlinks!)
    # ex:
    #  is_paritition_table /dev/nvme1n1

    # Use blkid to determine whether it's a partition table. If it is, then there will be a PTUUID in the blkid output.
    # ex:
    # $ blkid -o full /dev/nvme0n1
    # /dev/nvme0n1: PTUUID="24f84068-53be-4ae2-a53d-cbac5515b1af" PTTYPE="gpt"

    DEVICE_NAME=$1

    sudo blkid -o full "${DEVICE_NAME}" | grep 'PTUUID=' > /dev/null
}

function identify_volume() {
    # Determine the UUID of the filesystem on the given device.
    # Requires: The device has a filesystem.
    # Usage:
    #  identify_filesystem <device name>
    #  <device name> must be a regular file (no symlinks!)
    # ex:
    #  identify_filesystem /dev/nvme0n1

    # Example 'blkid -o export' output:
    # DEVNAME=/dev/nvme1n1
    # UUID=a7786831-dd21-40b5-abc5-0c9a9f7929a4
    # TYPE=xfs

    DEVICE_NAME=$1

    sudo blkid -o export ${DEVICE_NAME} | grep '^UUID=' | cut -s -d '=' -f 2
}

function identify_filesystem() {
    # Determine what type of filesystem, if any, is present on the given device.
    # Usage:
    #  identify_filesystem <device name>
    #  <device name> must be a regular file (no symlinks!)
    # ex:
    #  identify_filesystem /dev/nvme0n1

    # Example 'blkid -o export' output:
    # DEVNAME=/dev/nvme1n1
    # UUID=a7786831-dd21-40b5-abc5-0c9a9f7929a4
    # TYPE=xfs

    # Some TYPE fields:
    # TYPE=xfs
    # TYPE=ext2
    # TYPE=ext3
    # TYPE=ext4
    # TYPE=vfat

    DEVICE_NAME=$1

    if BLKID_OUT=$( sudo blkid -o export ${DEVICE_NAME} | grep '^TYPE=' )
    then
        echo ${BLKID_OUT} | cut -s -d '=' -f 2
    else
        echo "UNFORMATTED"
    fi
}

function format_volume() {
    # When first attached the EBS volume will not have a filesystem on it
    # This function is intended to be used to format such a blank volume.
    # It *can* also be used to wipe a device and give it a new format, as well,
    # so *be careful*.
    #
    # Usage:
    #  format_volume <device name> <format type>
    #  <device name> must be a regular file (no symlinks!)
    #  <format type> must be a valid value for the -t option of mkfs
    # ex:
    #  format_volume /dev/nvme0n1

    DEVICE_NAME=$1
    FORMAT=$2

    RESERVE_BLOCK_OPTION=""
    if test "${FORMAT:0:3}" == "ext"
    then
        # The -m option for ext filesystems:
        #  Specify the percentage of the filesystem blocks reserved for the super-user. Default is 5%.
        # Set this to 0%. This volume will not be a root volume.
        RESERVE_BLOCK_OPTION="-m 0"
    fi
    sudo mkfs -t "${FORMAT}" ${RESERVE_BLOCK_OPTION} "${DEVICE_NAME}"
    # Be paranoid. Make sure the drive formatted
    if ! test "$(identify_filesystem ${DEVICE_NAME})" == "${FORMAT}"
    then
        echo "ERROR: Device ${DEVICE_NAME} failed to format"
        exit 1
    fi
}

function mount_volume() {
    # Mount the given device to a specified mount point, and set up /etc/fstab so that it is
    # remounted on reboot.
    # Usage:
    #  mount_volume <device name> <mount point> [<extra mount options>]
    #  <device name> must be a regular file (no symlinks!)
    #  <mount point> will be created if it does not already exist.
    # ex:
    #  mount_volume /dev/nvme0n1 /var/lib/mongo ro

    DEVICE_NAME=$1
    MOUNT_POINT=$2
    EXTRA_MOUNT_OPTIONS=${3:-rw}
    test -d "${MOUNT_POINT}" || sudo mkdir -p "${MOUNT_POINT}"

    VOL_UUID=$(identify_volume ${DEVICE_NAME})
    VOL_TYPE=$(identify_filesystem ${DEVICE_NAME})

    # fstab may be missing a newline at end of file.
    if test $(tail -c 1 /etc/fstab | wc -l) -eq 0
    then
        # Newline was missing, so add one.
        echo "" | sudo tee -a /etc/fstab
    fi

    echo "UUID=${VOL_UUID} ${MOUNT_POINT} ${VOL_TYPE} defaults,nofail,${EXTRA_MOUNT_OPTIONS} 0 2" | sudo tee -a /etc/fstab
    sudo mount "${MOUNT_POINT}"
}

function resize_volume_partition_if_needed() {
    # If the EBS volume is larger than the formatted disk space, then we need
    # to resize the filesystem to grow to the EBS volume size.
    # Usage:
    #  $0 <device name>
    #  <device name> must be a regular file (no symlinks!)
    # ex:
    #  resize_volume_partition_if_needed /dev/nvme1n1

    # Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/recognize-expanded-volume-linux.html

    DEVICE_NAME=$1

    FS_TYPE=$(identify_filesystem ${DEVICE_NAME})
    case "${FS_TYPE}" in
    xfs)
        # xfs_growfs handles checking whether a resize needs to happen or not automatically.
        # ex:
        # meta-data=/dev/nvme1n1           isize=512    agcount=5, agsize=655360 blks
        #          =                       sectsz=512   attr=2, projid32bit=1
        #          =                       crc=1        finobt=1 spinodes=0
        # data     =                       bsize=4096   blocks=2883584, imaxpct=25
        #          =                       sunit=0      swidth=0 blks
        # naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
        # log      =internal               bsize=4096   blocks=2560, version=2
        #          =                       sectsz=512   sunit=0 blks, lazy-count=1
        # realtime =none                   extsz=4096   blocks=0, rtextents=0
        # data size unchanged, skipping
        sudo xfs_growfs -d "${DEVICE_NAME}"
        ;;
    ext*)
        # resize2fs handles checking whether a resize needs to happen or not automatically
        # ex:
        #  resize2fs 1.42.9 (28-Dec-2013)
        #  The filesystem is already 2621440 blocks long.  Nothing to do!
        sudo resize2fs ${DEVICE_NAME}
        ;;
    *)
        echo "ERROR -- Cannot resize unknown filesystem type '${FS_TYPE}'"
        exit 1
    esac
}

VOL_ID=$1
if ! echo $VOL_ID | grep -E 'vol-[A-Fa-f0-9]+' 2>&1 > /dev/null
then
    echo "ERROR: $VOL_ID does not look like an the id for an EBS volume"
    exit 1
fi

FILESYSTEM_FORMAT=$2
MOUNT_PATH=$3
MOUNT_OPTIONS=$4
GIVEN_TARGET_DEVICE=${5:-}

# Make sure that the EC2 instance identity document is authentic before we use it to fetch
# information about the instance we're running on.
authenticate_identity_document

# If the EBS volume is already attached, then get the device
# name it's attached as.
TARGET_DEVICE=$(get_attached_device ${VOL_ID})

# If not set, fall back to $GIVEN_TARGET_DEVICE or finding a device if that's not set either.
if test "${TARGET_DEVICE}" == ""
then
    TARGET_DEVICE=${TARGET_DEVICE:-${GIVEN_TARGET_DEVICE:-$(find_available_device_name)}}
    attach_ebs_volume $VOL_ID $TARGET_DEVICE
fi

if ! test -e "${TARGET_DEVICE}"
then
    echo "ERROR -- Could not find device ${TARGET_DEVICE}"
    exit 1
fi

# Look through symlinks to the true device file.
DEVICE_NAME=$(readlink -f "${TARGET_DEVICE}")

is_partition_table "${DEVICE_NAME}" && echo "ERROR -- '${DEVICE_NAME}' is a partition table." && exit 1

if test "$(identify_filesystem ${DEVICE_NAME})" == "UNFORMATTED"
then
    format_volume "${DEVICE_NAME}" "${FILESYSTEM_FORMAT}"
fi

mount_volume "${DEVICE_NAME}" "${MOUNT_PATH}" "${MOUNT_OPTIONS}"

resize_volume_partition_if_needed $DEVICE_NAME


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script will mount an Amazon Elastic File System (EFS) to a specified mount directory on this instance,
# and set up /etc/fstab so that the EFS is re-mounted on a system reboot.
#
# Note: This script uses get_metadata_token and get_region from ./metadataUtilities.sh
#  Thus, the system must have applications pre-installed as outlined in that file.
#
# Script arguments:
#  $1 -- EFS Identifier (ex: efs-00000000000)
#  $2 -- Mount path; directory that we mount the EFS to.
#  $3 -- whether to obtain the EFS mount target's IP address using the EFS API and persist this to
#        the /etc/hosts file on the system. This allows the script to work when the mounting instance cannot resolve the
#        mount target using DNS. A value of "true" (case sensitive) will  enable this feature. Any other value will
#        is treated as being disabled.
#  $4 -- (optional) NFSv4 mount options for the EFS.

set -xeu

if test $# -lt 3
then
  echo "Usage: $0 FILE_SYSTEM_ID MOUNT_PATH RESOLVE_MOUNT_POINT_USING_API [MOUNT_OPTIONS]"
  exit 1
fi

SCRIPT_DIR=$(dirname $0)
source "${SCRIPT_DIR}/metadataUtilities.sh"

# Make sure that the EC2 instance identity document is authentic before we use it to fetch
# information about the instance we're running on.
authenticate_identity_document

METADATA_TOKEN=$(get_metadata_token)
AWS_REGION=$(get_region "${METADATA_TOKEN}")
AVAILABILITY_ZONE_NAME=$(get_availability_zone "${METADATA_TOKEN}")

FILESYSTEM_ID=$1
MOUNT_PATH=$2
RESOLVE_MOUNTPOINT_IP_VIA_API=$3
MOUNT_OPTIONS="${4:-}"

mkdir -p "${MOUNT_PATH}"

AMAZON_EFS_PACKAGE="amazon-efs-utils"
if which yum
then
  PACKAGE_MANAGER="yum"
  NFS_UTILS_PACAKGE="nfs-utils"
else
  PACKAGE_MANAGER="apt-get"
  NFS_UTILS_PACKAGE="nfs-common"
fi

function use_amazon_efs_mount() {
  test -f "/sbin/mount.efs" || "${PACKAGE_MANAGER}" install -y "${AMAZON_EFS_PACKAGE}"
  return $?
}

function use_nfs_mount() {
  test -f "/sbin/mount.nfs4" || "${PACKAGE_MANAGER}" install -y "${NFS_UTILS_PACKAGE}"
  return $?
}

function resolve_mount_target_ip_via_api() {
  local EFS_FS_ID=$1
  local MNT_TARGET_RESOURCE_ID=$2
  local AVAILABILITY_ZONE_NAME=$3
  local AWS_REGION=$4
  local MOUNT_POINT_IP=""

  local FILTER_ARGUMENT=""
  if [[ $MNT_TARGET_RESOURCE_ID == fs-* ]]
  then
    # Mounting without an access point
    FILTER_ARGUMENT="--file-system-id ${MNT_TARGET_RESOURCE_ID}"
  elif [[ $MNT_TARGET_RESOURCE_ID == fsap-* ]]
  then
    # Mounting with an access point
    FILTER_ARGUMENT="--access-point-id ${MNT_TARGET_RESOURCE_ID}"
  else
    echo "Unsupported mount target resource: ${MNT_TARGET_RESOURCE_ID}"
    return 1
  fi

  # We prioritize the mount target in the same availability zone as the mounting instance
  # jq sorts with false first then true (https://stedolan.github.io/jq/manual/#sort,sort_by(path_expression), so we
  # negate the condition in the sort_by(...) expression
  MOUNT_POINT_JSON=$(aws efs describe-mount-targets \
    --region "${AWS_REGION}"                      \
    ${FILTER_ARGUMENT}                            \
    | jq ".MountTargets | sort_by( .AvailabilityZoneName != \"${AVAILABILITY_ZONE_NAME}\" ) | .[0]"
  )

  if [[ -z "${MOUNT_POINT_JSON}" ]]
  then
    echo "Could not find mount target for ${MNT_TARGET_RESOURCE_ID}"
    return 1
  fi

  MOUNT_POINT_IP=$(echo "${MOUNT_POINT_JSON}" | jq -r .IpAddress)
  MOUNT_POINT_AZ=$(echo "${MOUNT_POINT_JSON}" | jq -r .AvailabilityZoneName )

  if [[ "${MOUNT_POINT_AZ}" != "${AVAILABILITY_ZONE_NAME}" ]]
  then
    set +x
    echo "------------------------------------------ WARNING ------------------------------------------"
    echo "Could not find mount target for ${MNT_TARGET_RESOURCE_ID} matching the current availability"
    echo "zone (${AVAILABILITY_ZONE_NAME}). Cross-AZ data charges will be applied. To reduce costs,"
    echo "add a mount target for ${MNT_TARGET_RESOURCE_ID} in ${AVAILABILITY_ZONE_NAME}."
    echo "------------------------------------------ WARNING ------------------------------------------"
    set -x
  fi

  DNS_NAME="${EFS_FS_ID}.efs.${AWS_REGION}.amazonaws.com"

  # Backup the old hosts file
  cp /etc/hosts "/etc/hosts.rfdk-backup-$(date +%Y-%m-%dT%H:%M:%S)"
  # Remove any existing entries for the target DNS name
  sed -i -e "/${DNS_NAME}/d" /etc/hosts
  # Write the resolved entry for the target DNS name
  cat >> /etc/hosts <<EOF

${MOUNT_POINT_IP} ${DNS_NAME} # Added by RFDK
EOF
}

# Optionally resolve DNS using the EFS API
if [[ $RESOLVE_MOUNTPOINT_IP_VIA_API == "true"  ]]
then
  # jq is used to query the JSON API response
  if ! where jq > /dev/null 2>&1
  then
    "${PACKAGE_MANAGER}" install -y jq
  fi

  # Get access point ID if available, otherwise file system ID
  MNT_TARGET_RESOURCE_ID=$FILESYSTEM_ID
  # The access point is supplied as in the MOUNT_OPTIONS argument, which is a list of comma-separated fstab options.
  # Here is a sample opts string containing an access point:
  #
  #   rw,iam,accesspoint=fsap-1234567890,fsc
  #
  # See https://docs.aws.amazon.com/efs/latest/ug/efs-mount-helper.html#mounting-access-points
  #
  # We extract that value from MOUNT_OPTIONS here:
  ACCESS_POINT_MOUNT_OPT=$(echo "${MOUNT_OPTIONS}" | sed -e 's#,#\n#g' | grep 'accesspoint=') || true
  if [[ ! -z "${ACCESS_POINT_MOUNT_OPT}" ]]; then
    ACCESS_POINT_ID=$(echo "${ACCESS_POINT_MOUNT_OPT}" | cut -d= -f2)
    MNT_TARGET_RESOURCE_ID="${ACCESS_POINT_ID}"
  fi

  # This feature is treated as a best-effort first choice but falls-back to a regular DNS lookup with a warning emitted
  resolve_mount_target_ip_via_api \
      "${FILESYSTEM_ID}"          \
      "${MNT_TARGET_RESOURCE_ID}" \
      "${AVAILABILITY_ZONE_NAME}" \
      "${AWS_REGION}"             \
    || echo "WARNING: Couldn't resolve EFS IP address using the EFS service API endpoint"
fi

# Attempt to mount the EFS file system

# fstab may be missing a newline at end of file.
if test $(tail -c 1 /etc/fstab | wc -l) -eq 0
then
  # Newline was missing, so add one.
  echo "" | tee -a /etc/fstab
fi

if use_amazon_efs_mount
then
  echo "${FILESYSTEM_ID}:/ ${MOUNT_PATH} efs defaults,tls,_netdev,${MOUNT_OPTIONS}" | tee -a /etc/fstab
  MOUNT_TYPE=efs
elif use_nfs_mount
then
  echo "${FILESYSTEM_ID}.efs.${AWS_REGION}.amazonaws.com:/ ${MOUNT_PATH} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev,${MOUNT_OPTIONS} 0 0" | tee -a /etc/fstab
  MOUNT_TYPE=nfs4
else
  echo "Could not find suitable mount helper to mount the Elastic File System: ${FILESYSTEM_ID}"
  exit 1
fi

# We can sometimes fail to mount the EFS with a "Connection reset by host" error, or similar.
# To counteract this, as best we can, we try to mount the EFS a handful of times and fail-out
# only if unable to mount it after that.
TRIES=0
MAX_TRIES=20
while test ${TRIES} -lt ${MAX_TRIES} && ! mount -a -t ${MOUNT_TYPE}
do
  let TRIES=TRIES+1
  sleep 2
done

# Check whether the drive as been mounted. Fail if not.
cat /proc/mounts | grep "${MOUNT_PATH}"
exit $?


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script will mount an Amazon FSx for Lustre File System to a specified mount directory on this instance,
# and set up /etc/fstab so that the file system is re-mounted on a system reboot.
#
# This script requires the Lustre client to be already installed on the instance.
# See https://docs.aws.amazon.com/fsx/latest/LustreGuide/install-lustre-client.html
#
# Note: This script uses get_metadata_token and get_region from ./metadataUtilities.sh
#  Thus, the system must have applications pre-installed as outlined in that file.
#
# Script arguments:
#  $1 -- file system Identifier (ex: fs-00000000000)
#  $2 -- Mount path; directory that we mount the file system to.
#  $3 -- Mount name
#  $4 -- (optional) Lustre mount options for the file system.

set -xeu

if test $# -lt 3
then
  echo "Usage: $0 <file system ID> <mount path> <mount name> [<mount options>]"
  exit 1
fi

SCRIPT_DIR=$(dirname $0)
source "${SCRIPT_DIR}/metadataUtilities.sh"

# Make sure that the EC2 instance identity document is authentic before we use it to fetch
# information about the instance we're running on.
authenticate_identity_document

METADATA_TOKEN=$(get_metadata_token)
AWS_REGION=$(get_region "${METADATA_TOKEN}")

FILESYSTEM_ID=$1
MOUNT_PATH=$2
MOUNT_NAME=$3
MOUNT_OPTIONS="${4:-}"

FILESYSTEM_DNS_NAME="${FILESYSTEM_ID}.fsx.${AWS_REGION}.amazonaws.com"
MOUNT_OPTIONS="defaults,noatime,flock,_netdev,${MOUNT_OPTIONS}"

sudo mkdir -p "${MOUNT_PATH}"

# Attempt to mount the FSx file system

# fstab may be missing a newline at end of file.
if test $(tail -c 1 /etc/fstab | wc -l) -eq 0
then
  # Newline was missing, so add one.
  echo "" | sudo tee -a /etc/fstab
fi

# See https://docs.aws.amazon.com/fsx/latest/LustreGuide/mount-fs-auto-mount-onreboot.html
MOUNT_TYPE=lustre
echo "${FILESYSTEM_DNS_NAME}@tcp:/${MOUNT_NAME} ${MOUNT_PATH} ${MOUNT_TYPE} ${MOUNT_OPTIONS} 0 0" | sudo tee -a /etc/fstab

# We can sometimes fail to mount the file system with a "Connection reset by host" error, or similar.
# To counteract this, as best we can, we try to mount the file system a handful of times and fail-out
# only if unable to mount it after that.
TRIES=0
MAX_TRIES=20
while test ${TRIES} -lt ${MAX_TRIES} && ! sudo mount -a -t ${MOUNT_TYPE}
do
  let TRIES=TRIES+1
  sleep 2
done

# Check whether the drive as been mounted. Fail if not.
cat /proc/mounts | grep "${MOUNT_PATH}"
exit $?


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Script to install MongoDB Community Edition v3.6 from the Mongo.org yum repository.
#
# Developer note: For legal reasons we absolutely cannot distribute MongoDB in any way.
#  This includes distributing the installers, or images with MongoDB pre-installed.
#  We *can* distribute scripting like this that facilitates the installation of
#  MongoDB from the official MongoDB repository.

set -xefuo pipefail

# Installation instructions: https://docs.mongodb.com/v3.6/tutorial/install-mongodb-on-red-hat/
# Note: There are no instructions for Amazon Linux 2, but the RedHat 7 binaries are compatible.

REPO_FILENAME=mongodb-org-3.6.repo
YUM_REPOS_DIR=/etc/yum.repos.d

cat > "/tmp/${REPO_FILENAME}" << EOF
[mongodb-org-3.6]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/7/mongodb-org/3.6/x86_64
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
EOF

sudo mv "/tmp/${REPO_FILENAME}" "${YUM_REPOS_DIR}"
# Be paranoid. Make sure the repo file is locked down to root.
sudo chown root.root "${YUM_REPOS_DIR}/${REPO_FILENAME}"
sudo chmod 600 "${YUM_REPOS_DIR}/${REPO_FILENAME}"

# Do the install
sudo yum install -y mongodb-org


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

function get_secret_string() {
  SECRET_ID=$1
  AWS_REGION=$(echo ${SECRET_ID} | cut -d: -f4)
  PYTHON_SCRIPT="import json,sys; d=json.load(sys.stdin); print d[\"SecretString\"];"
  set +x
  export RET_VALUE=$(aws --region ${AWS_REGION} secretsmanager get-secret-value --secret-id "${SECRET_ID}" | python -c "${PYTHON_SCRIPT}" )
  set -x
}


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# A script for fetching an X.509 certificate for the server from the Secrets
# that are created by the RFDK's X509CertificatePem

# Command-line arguments
#  $1 -- Certificate secret ARN
#  $2 -- Trust chain secret ARN
#  $3 -- Private key secret ARN
#  $4 -- Private key passphrase secret ARN

set -xeufo pipefail

if test $# -lt 4
then
  echo "ERROR -- Incorrect number of options for script. See script header for usage."
  exit 1
fi

if ! ( which aws && which openssl )
then
  echo "ERROR -- Need the AWS CLI and openssl to be able to run."
  exit 1
fi

SCRIPT_DIR=$(dirname $0)
source "${SCRIPT_DIR}/secretsFunction.sh"

CERT_ID=$1
CHAIN_ID=$2
KEY_ID=$3
KEY_PW_ID=$4

get_secret_string "${CERT_ID}"
printenv RET_VALUE > ./key.crt
get_secret_string "${CHAIN_ID}"
printenv RET_VALUE > ./ca.crt
get_secret_string "${KEY_ID}"
printenv RET_VALUE > ./encrypted_key.pem

# Note: We must get the private key passphrase **LAST**. We use the returned
# environment variable to securely invoke openssl to decrypt the private key.
get_secret_string "${KEY_PW_ID}"

# Decrypt the private key.
openssl rsa -in ./encrypted_key.pem -passin env:RET_VALUE -out ./decrypted_key.pem
unset RET_VALUE

cat key.crt decrypted_key.pem > key.pem

# Validate the certificate and key are valid.
echo "Validating server key"

set +x # Do not print out key modulus; it's a secret
KEY_MODULUS=$(openssl rsa -modulus -noout -in ./decrypted_key.pem | openssl md5)
CA_MODULUS=$(openssl x509 -modulus -noout -in ./key.crt | openssl md5)

test "${KEY_MODULUS}" == "${CA_MODULUS}" || exit 1
set -x

echo "Success - valid key"


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Command-line arguments:
#  $1 -- ARN of the Secret containing the admin credentials.

set -xeufo pipefail

if test $# -lt 1
then
  echo "ERROR -- Incorrect number of options for script. See script header for usage."
  exit 1
fi

function cleanup() {
  RC=$?
  # Clean up any secrets
  if test -f ./adminCredentials.js
  then
    rm -f ./adminCredentials.js
  fi
  exit ${RC}
}

trap cleanup EXIT ERR SIGQUIT SIGKILL SIGTERM SIGPIPE

SCRIPT_DIR=$(dirname $0)
source "${SCRIPT_DIR}/secretsFunction.sh"

ADMIN_CREDENTIALS_ARN=$1

echo 'var adminCredentials = JSON.parse("' > ./temp.js
get_secret_string "${ADMIN_CREDENTIALS_ARN}"
printenv RET_VALUE | sed 's/"/\\"/g' >> ./temp.js
echo '");' >> ./temp.js
cat temp.js | tr -d '\n' > ./adminCredentials.js
rm -f ./temp.js

mongo --port 27017 --host localhost ./createAdminUser.js --quiet
rm -f ./adminCredentials.js


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Set up the live/secure configuration for mongo in preparation for starting the
# service for real.

set -xeufo pipefail

cat /etc/mongod.conf | python ./setupMongodLiveConfig.py > ./mongod.conf.new
sudo mv ./mongod.conf.new /etc/mongod.conf
# Make sure mongod user can read the config file
sudo chmod 640 /etc/mongod.conf
sudo chown root.mongod /etc/mongod.conf


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Set the open files limit to 200k so we don't have dropped/refused connections.
# Per mongo, the process limit should be 50% of the open file limit too.
SERVICE_FILE="/lib/systemd/system/mongod.service"
if test -e "${SERVICE_FILE}"
then
    if grep 'LimitNOFILE' "${SERVICE_FILE}"
    then
        # Note: Only change if the values are their defaults from the MongoDB rpm install.
        #  Customer might have created a custom AMI with their own limits.
        sudo sed --in-place=.bak -e 's/^LimitNOFILE=64000$/LimitNOFILE=200000/' -e 's/^LimitNPROC=64000$/LimitNPROC=100000/' "${SERVICE_FILE}"
    else
        echo "LimitNOFILE=200000" | sudo tee -a "${SERVICE_FILE}"
        echo "LimitNPROC=100000" | sudo tee -a "${SERVICE_FILE}"
    fi
else
    echo "ERROR: Could not find systemd configuration file for mongod"
    exit 1
fi

# We changed a systemd file. Need to reload it.
sudo systemctl daemon-reload


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

cat /etc/mongod.conf | python ./setupMongodNoAuth.py > ./mongod.conf.new
sudo mv ./mongod.conf.new /etc/mongod.conf
# Make sure mongod user can read the config file
sudo chmod 640 /etc/mongod.conf
sudo chown root.mongod /etc/mongod.conf


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Command-line arguments:
#  $1 -- Storage path of the MongoDB data.

set -xeufo pipefail

if test $# -lt 1
then
  echo "ERROR -- Incorrect number of options for script. See script header for usage."
  exit 1
fi

STORAGE_PATH=$1

cat /etc/mongod.conf | python ./setupMongodStorage.py "${STORAGE_PATH}" > ./mongod.conf.new
sudo mv ./mongod.conf.new /etc/mongod.conf
# Make sure mongod user can read the config file
sudo chmod 640 /etc/mongod.conf
sudo chown root.mongod /etc/mongod.conf


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script configures any settings in the deadline.ini file for the rcs then restarts it to ensure they take effect.
#
# Arguments:
# $@ Alternating pairs of Deadline ini file setting names and values.

set -euxo pipefail

args=("$@")

# Function to check if the RCS is running and listening
function is-rcs-ready() {
    local rcs_pids="$(pgrep deadlinercs)"

    if [ -z "$rcs_pids" ]; then
        echo "RCS is not running"
        return 1
    fi

    # Replace newlines with commas as expected by the -p argument of lsof
    rcs_pids=$(echo "$rcs_pids" | paste -s -d ,)

    # Check if the RCS process has any TCP listening sockets
    lsof -iTCP -sTCP:LISTEN -p "$rcs_pids" > /dev/null
}

# Cloud-init does not load system environment variables. Cherry-pick the
# environment variable installed by the Deadline Client installer.
if [ -f "/etc/profile.d/deadlineclient.sh" ]; then
    source "/etc/profile.d/deadlineclient.sh"
fi

# Find Deadline
if [ -z "$DEADLINE_PATH" ]; then
    echo "ERROR: DEADLINE_PATH environment variable not set"
    exit 1
fi

# Find Deadline Command
deadlinecommand="$DEADLINE_PATH/deadlinecommand"
if [ ! -f "$deadlinecommand" ]; then
    echo "ERROR: deadlinecommand not found"
    exit 1
fi

sudo -u ec2-user "$deadlinecommand" -SetIniFileSetting LaunchRemoteConnectionServerAtStartup True

for (( i=0; i<${#args[@]}; i=i+2 ))
  do
    sudo -u ec2-user "$deadlinecommand" -SetIniFileSetting "${args[i]}" "${args[i+1]}"
  done

# Configure the Launcher to start the RCS and restart it
/etc/init.d/deadline10launcher restart

# Wait until the RCS is up and running
echo "Waiting for RCS to be ready"
while ! is-rcs-ready; do
    sleep 1
done
echo "RCS is ready"


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script fetches the Document DB cluster credentials and persists them in
# the local credential store for the current user.
#
# Arguments:
# $1: Path where deadline repository is installed.

set -xeo pipefail +o history

repo_path="$1"

# Cloud-init does not load system environment variables. Cherry-pick the
# environment variable installed by the Deadline Client installer.
if [ -f "/etc/profile.d/deadlineclient.sh" ]; then
    source "/etc/profile.d/deadlineclient.sh"
fi

# Find Deadline
if [ -z "$DEADLINE_PATH" ]; then
    echo "ERROR: DEADLINE_PATH environment variable not set"
    exit 1
fi

# Find Deadline Command
deadlinecommand="$DEADLINE_PATH/deadlinecommand"
if [ ! -f "$deadlinecommand" ]; then
    echo "ERROR: deadlinecommand not found"
    exit 1
fi

# Disable outputting commands so the secret is not exposed
set +x

export DB_CERT_FILE=""
export DB_CERT_PASSWORD=""
# Set the DB credentials. These are scoped to the user that runs the command, so we
configure_deadline_database "$deadlinecommand"

# Resume outputting commands
set -x

# Configure location to Deadline Repository
printenv DB_CERT_PASSWORD | sudo -u ec2-user "$deadlinecommand" -ChangeRepository Direct "$repo_path" "${DB_CERT_FILE}"
unset DB_CERT_FILE
unset DB_CERT_PASSWORD

echo "Script completed successfully"


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script configures the deadline.ini file with the Remote Server endpoints and restart the launcher service
# Arguments:
# $1: comma separated groups
# $2: comma separated pools
# $3: region
# $4: minimum supported deadline version
# $5: worker listening port
# $6: worker listening port configuration script

# exit when any command fails
set -xeuo pipefail

WORKER_GROUPS=(${1//,/ })
WORKER_POOLS=(${2//,/ })
WORKER_REGION="$3"
MINIMUM_SUPPORTED_DEADLINE_VERSION=$4
WORKER_LISTENING_PORT=$5
WORKER_LISTENING_PORT_CONFIG_SCRIPT=$6

# Cloud-init does not load system environment variables. Cherry-pick the
# environment variable installed by the Deadline Client installer.
if [ -f "/etc/profile.d/deadlineclient.sh" ]; then
    source "/etc/profile.d/deadlineclient.sh"
fi

# Find Deadline
if [ -z "$DEADLINE_PATH" ]; then
    echo "ERROR: DEADLINE_PATH environment variable not set"
    exit 1
fi

DEADLINE_COMMAND="$DEADLINE_PATH/deadlinecommand"
if [ ! -f "$DEADLINE_COMMAND" ]; then
    echo "ERROR: $DEADLINE_COMMAND not found!"
    exit 1
fi

isVersionLessThan() {
    python -c "import sys;sys.exit(0 if tuple(map(int, sys.argv[-2].split('.'))) < tuple(map(int, sys.argv[-1].split('.'))) else 1)" "$1" "$2"
}

DEADLINE_VERSION=$("$DEADLINE_COMMAND" -Version | grep -oP '[v]\K\d+\.\d+\.\d+\.\d+\b')
if [ -z "$DEADLINE_VERSION" ]; then
    echo "ERROR: Unable to identify the version of installed Deadline Client. Exiting..."
    exit 1
fi

if isVersionLessThan $DEADLINE_VERSION $MINIMUM_SUPPORTED_DEADLINE_VERSION; then
    echo "ERROR: Installed Deadline Version ($DEADLINE_VERSION) is less than the minimum supported version ($MINIMUM_SUPPORTED_DEADLINE_VERSION). Exiting..."
    exit 1
fi

# launch worker at launcher startup
"$DEADLINE_COMMAND" -SetIniFileSetting LaunchSlaveAtStartup True
# keep worker running
"$DEADLINE_COMMAND" -SetIniFileSetting KeepWorkerRunning True
# restart stalled worker
"$DEADLINE_COMMAND" -SetIniFileSetting RestartStalledSlave True
# auto update
"$DEADLINE_COMMAND" -SetIniFileSetting AutoUpdateOverride False
# Disable S3Backed Cache
"$DEADLINE_COMMAND" -SetIniFileSetting UseS3BackedCache False
# Blank the S3BackedCache Url
"$DEADLINE_COMMAND" -SetIniFileSetting S3BackedCacheUrl ""

# setting the group, pool and region for this worker

if [ -z "$WORKER_REGION" ]; then
    echo "INFO: WORKER_REGION not provided"
else
    "$DEADLINE_COMMAND" -SetIniFileSetting Region $WORKER_REGION
fi

WORKER_NAME_PREFIX=`hostname -s`

# Fetching all workers in this node
WORKER_NAMES=()
shopt -s dotglob
for file in /var/lib/Thinkbox/Deadline10/slaves/*
do
  file="${file##*/}"
  workerSuffix="${file%%.*}"
  if [[ -z "$workerSuffix" || "$workerSuffix" = "*" ]]; then
    WORKER_NAMES+=( "$WORKER_NAME_PREFIX" )
  else
    WORKER_NAMES+=( "$WORKER_NAME_PREFIX"-$workerSuffix )
  fi
done
shopt -u dotglob

# Setting Groups for all workers in this node
if [ ${#WORKER_GROUPS[@]} -gt 0 ]; then
  for group in "${WORKER_GROUPS[@]}"
  do
    existingGroups=( $("$DEADLINE_COMMAND" -GetGroupNames) )
    if [[ ! " ${existingGroups[@]} " =~ " ${group} " ]]; then
        "$DEADLINE_COMMAND" -AddGroup $group
    fi
  done
  "$DEADLINE_COMMAND" -SetGroupsForSlave $(IFS=, ; echo "${WORKER_NAMES[*]}") $(IFS=, ; echo "${WORKER_GROUPS[*]}")
fi

# Setting Pools for all workers in this node
if [ ${#WORKER_POOLS[@]} -gt 0 ]; then
  for pool in "${WORKER_POOLS[@]}"
  do
    existingPools=( $("$DEADLINE_COMMAND" -GetPoolNames) )
    if [[ ! " ${existingPools[@]} " =~ " ${pool} " ]]; then
        "$DEADLINE_COMMAND" -AddPool $pool
    fi
  done
  "$DEADLINE_COMMAND" -SetPoolsForSlave $(IFS=, ; echo "${WORKER_NAMES[*]}") $(IFS=, ; echo "${WORKER_POOLS[*]}")
fi

# Setting listening port for the workers on this node (we cannot have multiple workers listening on the same port)
port_offset=0
for worker_name in "${WORKER_NAMES[@]}"; do
  "$DEADLINE_COMMAND" -ExecuteScriptNoGui "$WORKER_LISTENING_PORT_CONFIG_SCRIPT" -n $worker_name -p $(($WORKER_LISTENING_PORT+$port_offset))
  port_offset=$((port_offset+1))
done

# Restart service, if it exists, else restart application
if service --status-all | grep -q 'Deadline 10 Launcher'; then
  service deadline10launcher stop
  sudo killall -w deadlineworker || true
  service deadline10launcher start
else
  DEADLINE_LAUNCHER="$DEADLINE_PATH/deadlinelauncher"
  "$DEADLINE_LAUNCHER" -shutdownall
  sudo killall -w deadlineworker || true
  "$DEADLINE_LAUNCHER" -nogui
fi

echo "Script completed successfully."


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script configures the deadline.ini file with the settings for the HealthMonitor
# Arguments:
# $1: healthCheckPort
# $2: minimum supported deadline version

# exit when any command fails
set -xeuo pipefail

HEALTH_CHECK_PORT="$1"
MINIMUM_SUPPORTED_DEADLINE_VERSION=$2

# Cloud-init does not load system environment variables. Cherry-pick the
# environment variable installed by the Deadline Client installer.
if [ -f "/etc/profile.d/deadlineclient.sh" ]; then
    source "/etc/profile.d/deadlineclient.sh"
fi

# Find Deadline
if [ -z "$DEADLINE_PATH" ]; then
    echo "ERROR: DEADLINE_PATH environment variable not set"
    exit 1
fi

DEADLINE_COMMAND="$DEADLINE_PATH/deadlinecommand"
if [ ! -f "$DEADLINE_COMMAND" ]; then
    echo "ERROR: $DEADLINE_COMMAND not found!"
    exit 1
fi

isVersionLessThan() {
    python -c "import sys;sys.exit(0 if tuple(map(int, sys.argv[-2].split('.'))) < tuple(map(int, sys.argv[-1].split('.'))) else 1)" "$1" "$2"
}

DEADLINE_VERSION=$("$DEADLINE_COMMAND" -Version | grep -oP '[v]\K\d+\.\d+\.\d+\.\d+\b')
if [ -z "$DEADLINE_VERSION" ]; then
    echo "ERROR: Unable to identify the version of installed Deadline Client. Exiting..."
    exit 1
fi

if isVersionLessThan $DEADLINE_VERSION $MINIMUM_SUPPORTED_DEADLINE_VERSION; then
    echo "ERROR: Installed Deadline Version ($DEADLINE_VERSION) is less than the minimum supported version ($MINIMUM_SUPPORTED_DEADLINE_VERSION). Exiting..."
    exit 1
fi

# enabling the health check port
"$DEADLINE_COMMAND" -SetIniFileSetting ResourceTrackerVersion V2
# health check port
"$DEADLINE_COMMAND" -SetIniFileSetting LauncherHealthCheckPort $HEALTH_CHECK_PORT

echo "Script completed successfully."


#!/bin/sh

# Script to install and configure cachefilesd onto a Linux host.
# This script is presently narrowly written for use on the ECS container host
# instance(s) that are running the Deadline RCS containers in the RenderQueue construct.

set -xeu

if ! test -f /sbin/cachefilesd
then
  # The yum install can fail if there is no route to the yum repository.
  # Since this is an AL2 instance, that is equivalent to requiring a route to
  # the regional S3 endpoint on port 80.
  sudo yum install -y cachefilesd || echo 'ERROR -- Failed to install cachefilesd' && exit 0

  cat << EOF | sudo tee -a /etc/cachefilesd.conf
# Allow 16k cull table entries
culltable 14
EOF

fi

# Make sure cachefilesd is running
sudo systemctl enable cachefilesd
sudo systemctl start cachefilesd


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Script to download the contents of a Secret from AWS SecretsManager, and save
# the contents to a file
#
# Arguments:
#   $1 -- The ARN of the secret to fetch
#   $2 -- The filename to save the contents as.

set -xefuo pipefail

if test $# -lt 2
then
    echo "Usage: $0 <secret arn> <filename>"
    exit 1
fi

SECRET_ARN=$1
OUTPUT_FILENAME=$2
AWS_REGION=$(echo ${SECRET_ARN} | cut -d: -f 4)

OUTPUT_DIR=$(dirname "${OUTPUT_FILENAME}")
[ -d "${OUTPUT_DIR}" ] || sudo mkdir -p "${OUTPUT_DIR}"

PY_SCRIPT="from __future__ import print_function; import json, sys; d=json.load(sys.stdin); print(d[sys.argv[1]])"

set +x
export SECRET_JSON=$(aws --region ${AWS_REGION} secretsmanager get-secret-value --secret-id ${SECRET_ARN})
set -x
if printenv SECRET_JSON | grep 'SecretString' 2>&1 > /dev/null
then
    # Secret was plain test. Just copy the contents of the SecretString into the output file
    printenv SECRET_JSON | python -c "${PY_SCRIPT}" SecretString > "${OUTPUT_FILENAME}"
else
    # Secret value is binary. The contents of SecretBinary will be the base64 encoding of the secret
    printenv SECRET_JSON | python -c "${PY_SCRIPT}" SecretBinary | base64 -w0 -i -d > "${OUTPUT_FILENAME}"
fi
unset SECRET_JSON


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# exit when any command fails
set -xeuo pipefail

MIN_DEADLINE_VERSION_REPO_NO_ROOT="10.1.18"
USAGE="Usage: $0 -i <installer-s3-path> -p <local-installer-path> -v <deadline-version>

This script downloads the deadline repository installer and executes it.

Required arguments:
  -i s3 path for the deadline repository installer.
  -p Path where deadline repository needs to be installed.
  -v Deadline Repository Version being installed.

Optional arguments
  -s Deadline Repository settings file to import.
  -o The UID[:GID] that this script will chown the Repository files for. If GID is not specified, it defults to be the same as UID.
  -c Secrets management admin credentials ARN. If this parameter is specified, secrets management will be enabled.
  -r Region where stacks are deployed. Required to get secret management credentials."

while getopts "i:p:v:s:o:c:r:" opt; do
  case $opt in
    i) S3PATH="$OPTARG"
    ;;
    p) PREFIX="$OPTARG"
    ;;
    v) DEADLINE_REPOSITORY_VERSION="$OPTARG"
    ;;
    s) DEADLINE_REPOSITORY_SETTINGS_FILE="$OPTARG"
    ;;
    o) DEADLINE_REPOSITORY_OWNER="$OPTARG"
    ;;
    c) SECRET_MANAGEMENT_ARN="$OPTARG"
    ;;
    r) AWS_REGION="$OPTARG"
    ;;
    /?)
      echo "$USAGE"
      exit 1
    ;;
  esac
done

if [ -z "${S3PATH+x}" ] || \
   [ -z "${PREFIX+x}" ] || \
   [ -z "${DEADLINE_REPOSITORY_VERSION+x}" ]; then
  echo "ERROR: Required arguments are missing."
  echo "$USAGE"
  exit 1
fi

# check if repository is already installed at the given path
REPOSITORY_FILE_PATH="$PREFIX/settings/repository.ini"
CONNECTION_FILE_PATH="$PREFIX/settings/connection.ini"

# Run the Function that the Database Connection created to set up the installer arguments.
declare -A INSTALLER_DB_ARGS
configure_database_installation_args

if test -f "$REPOSITORY_FILE_PATH"; then
    echo "File $REPOSITORY_FILE_PATH exists. Validating Database Connection"
    # File Exists

    INSTALLER_DB_HOSTNAME=${INSTALLER_DB_ARGS["--dbhost"]}
    INSTALLER_DB_PORT=${INSTALLER_DB_ARGS["--dbport"]}

    # Additionally, vadlidate the DB endpoint.
    source $CONNECTION_FILE_PATH > /dev/null 2>&1 || true
    if [ "$Hostname" != "$INSTALLER_DB_HOSTNAME" ] || [ "$Port" != "$INSTALLER_DB_PORT" ]; then
        echo "ERROR: Repository pre-exists but configured database endpoint($Hostname:$Port) does not match with provided database endpoint($INSTALLER_DB_HOSTNAME:$INSTALLER_DB_PORT)."
        exit 1
    fi
    echo "Database Connection is valid.  Validating Deadline Version."

    # Following runs the .ini file as a script while suppressing all the errors. This creates bash variables with
    # the key's name and sets its value to the value specified in .ini file.
    # This is a quick way to read the .ini values but is not a full-proof way. Since we dont have common keys in
    # multiple sections of the config files, this approach will work correctly.
    # The proper way to achieve this is to use a ini config manager tool to get the value of required key.
    source $REPOSITORY_FILE_PATH > /dev/null 2>&1 || true
    if [[ "$Version" = "$DEADLINE_REPOSITORY_VERSION" ]]; then
        echo "Repository version $DEADLINE_REPOSITORY_VERSION already exists at path $REPOSITORY_FILE_PATH."
    else
        SplitVersion=(${Version//./ })
        SplitRepoVersion=(${DEADLINE_REPOSITORY_VERSION//./ })

        if [[ ${SplitVersion[0]} != ${SplitRepoVersion[0]} ]]; then
            echo "ERROR: Repository pre-exists but configured Repository Version (${Version}) has a different Major Version than the provided installer (${DEADLINE_REPOSITORY_VERSION})."
            exit 1
        fi
    fi
fi

REPO_INSTALLER=/tmp/repo_installer.run

aws s3 cp $S3PATH $REPO_INSTALLER
chmod +x $REPO_INSTALLER

set +x

REPO_ARGS=()

for key in "${!INSTALLER_DB_ARGS[@]}"; do
  REPO_ARGS+=("${key}" "${INSTALLER_DB_ARGS[$key]}")
done

if [ ! -z "${DEADLINE_REPOSITORY_SETTINGS_FILE+x}" ]; then
  if [ ! -f "$DEADLINE_REPOSITORY_SETTINGS_FILE" ]; then
    echo "ERROR: Repository settings file was specified but is not a file: $DEADLINE_REPOSITORY_SETTINGS_FILE."
    exit 1
  else
    REPO_ARGS+=("--importrepositorysettings" "true" "--repositorysettingsimportoperation" "append" "--repositorysettingsimportfile" "$DEADLINE_REPOSITORY_SETTINGS_FILE")
  fi
fi

if [ ! -z "${SECRET_MANAGEMENT_ARN+x}" ]; then
  sudo yum install -y jq
  SM_SECRET_VALUE=$(aws secretsmanager get-secret-value --secret-id=$SECRET_MANAGEMENT_ARN --region=$AWS_REGION)
  SM_SECRET_STRING=$(jq -r '.SecretString' <<< "$SM_SECRET_VALUE")
  SECRET_MANAGEMENT_USER=$(jq -r '.username' <<< "$SM_SECRET_STRING")
  SECRET_MANAGEMENT_PASSWORD=$(jq -r '.password' <<< "$SM_SECRET_STRING")
  if !([[ ${#SECRET_MANAGEMENT_PASSWORD} -ge 8 ]] &&
    echo $SECRET_MANAGEMENT_PASSWORD | grep -q [0-9] &&
    echo $SECRET_MANAGEMENT_PASSWORD | grep -q [a-z] &&
    echo $SECRET_MANAGEMENT_PASSWORD | grep -q [A-Z] &&
    echo $SECRET_MANAGEMENT_PASSWORD | grep -q [^[:alnum:]])
  then
    echo "ERROR: Admin password is too weak. It must be at least 8 characters long and contain at least one lowercase letter, one uppercase letter, one symbol and one digit."
    exit 1
  fi
  echo "Secrets management is enabled. Credentials are stored in secret: $SECRET_MANAGEMENT_ARN"
  REPO_ARGS+=("--installSecretsManagement" "true" "--secretsAdminName" "$SECRET_MANAGEMENT_USER" "--secretsAdminPassword" "$SECRET_MANAGEMENT_PASSWORD")
else
  echo "Secrets management is not enabled."
fi

INSTALL_AS_NON_ROOT_CMD=""
if [[ -n "${DEADLINE_REPOSITORY_OWNER+x}" ]]; then
  if [[ ! "$DEADLINE_REPOSITORY_OWNER" =~ ^[0-9]+(:[0-9]+)?$ ]]; then
    echo "ERROR: Deadline Repository owner is invalid: ${DEADLINE_REPOSITORY_OWNER}"
    exit 1
  fi
  REPOSITORY_OWNER_UID="${DEADLINE_REPOSITORY_OWNER%:*}"
  REPOSITORY_OWNER_GID="${DEADLINE_REPOSITORY_OWNER#*:}"

  if [[ -z $REPOSITORY_OWNER_GID ]]; then
    echo "Repository owner GID not specified. Defaulting to UID $REPOSITORY_OWNER_UID"
    REPOSITORY_OWNER_GID=$REPOSITORY_OWNER_UID
  fi

  EXISTING_GROUP=$(id -g $REPOSITORY_OWNER_UID)
  if [[ $? -eq 0 ]]; then
    # UID already taken, make sure the GID matches
    if [[ ! $EXISTING_GROUP -eq $REPOSITORY_OWNER_GID ]]; then
      echo "ERROR: Deadline Repository owner UID $REPOSITORY_OWNER_UID is already in use and has incorrect GID. Got GID $EXISTING_GROUP, expected $REPOSITORY_OWNER_GID"
      exit 1
    fi
  else
    # Create the group
    groupadd deadline-rcs-user -g $REPOSITORY_OWNER_GID

    # Create the user
    useradd deadline-rcs-user -u $REPOSITORY_OWNER_UID -g $REPOSITORY_OWNER_GID
  fi

  # Determine whether we can run the installer as the user that will own the repository
  VERSION_COMPONENTS=(${DEADLINE_REPOSITORY_VERSION//./ })
  MIN_VERSION_COMPONENTS=(${MIN_DEADLINE_VERSION_REPO_NO_ROOT//./ })
  if !([[ ${VERSION_COMPONENTS[0]} -lt ${MIN_VERSION_COMPONENTS[0]} ]] || \
       [[ ${VERSION_COMPONENTS[1]} -lt ${MIN_VERSION_COMPONENTS[1]} ]] || \
       [[ ${VERSION_COMPONENTS[2]} -lt ${MIN_VERSION_COMPONENTS[2]} ]])
  then
    echo "Deadline Repository installer will be run as UID=$REPOSITORY_OWNER_UID"
    INSTALL_AS_NON_ROOT_CMD="sudo -u #$REPOSITORY_OWNER_UID"
  fi
fi

# The syntax ${array[@]+"${array[@]}"} is a way to get around the expansion of an empty array raising an unbound variable error since this script
# sets the "u" shell option above. This is a use of the ${parameter+word} shell expansion. If the value of "parameter" is unset, nothing will be
# substituted in its place. If "parameter" is set, then the value of "word" is used, which is the expansion of the populated array.
# Since bash treats the expansion of an empty array as an unset variable, we can use this pattern expand the array only if it is populated.
$INSTALL_AS_NON_ROOT_CMD $REPO_INSTALLER --mode unattended --setpermissions false --prefix "$PREFIX" --installmongodb false --backuprepo false ${REPO_ARGS[@]+"${REPO_ARGS[@]}"}

if [[ -z "$INSTALL_AS_NON_ROOT_CMD" ]] && [[ -n "${REPOSITORY_OWNER_UID+x}" ]]; then
  echo "Changing ownership of Deadline Repository files to UID=$REPOSITORY_OWNER_UID GID=$REPOSITORY_OWNER_GID"
  sudo chown -R "$REPOSITORY_OWNER_UID:$REPOSITORY_OWNER_GID" "$PREFIX"
fi

set -x

echo "Script completed successfully."


#!/bin/bash
node_modules/.bin/tsc -b "$@"


#!/bin/bash
# Script to clean stale .js and .d.ts files (that don't have a corresponding .ts
# file).

for filename in $(find . \
     -not \( -name node_modules -prune \) \
     -not \( -name coverage -prune \) \
     -type f \
     -name \*.js -o -name \*.d.ts | git check-ignore --stdin); do

    if [[ $filename == *.d.ts ]]; then
        source=${filename%.d.ts}.ts
    else
        source=${filename%.*}.ts
    fi

    if [[ ! -f $source ]]; then
        rm $filename
        echo Removed $filename
    fi
done


#!/bin/bash
set -euxo pipefail

if [ ! -f lerna.json ]; then
  echo "This script should be run from the root of the repo."
  exit 1
fi

# first, we need to make sure that all existing peer dependencies are aligned to the "dependency" version
find . -name package.json | grep -v node_modules | xargs node scripts/sync-peer-deps.js

# must build first so .jsii is aligned
/bin/bash ./build.sh --skip-tests

# now, run jsii-fix-peers to add all missing peers based on the jsii spec
npx lerna exec "$PWD/tools/cdk-build-tools/node_modules/.bin/jsii-fix-peers 2>/dev/null || true"


#!/bin/bash
# --------------------------------------------------------------------------------------------------
#
# this wonderful tool allows you to execute a command for all modules in this repo
# in topological order, but has the incredible property of being stateful.
# this means that if a command fails, you can fix the issue and resume from where
# you left off.
#
# to start a session, run:
#     foreach.sh COMMAND
#
# this will execute "COMMAND" for each module in the repo (cwd will be the directory of the module).
# if a task fails, it will stop, and then to resume, simply run `foreach.sh` again (with or without the same command).
#
# to reset the session (either when all tasks finished or if you wish to run a different session), run:
#     foreach.sh --reset
#
# to run the command only against the current module and its dependencies:
#     foreach.sh --up COMMAND
#
# --------------------------------------------------------------------------------------------------
set -euo pipefail
scriptdir=$(cd $(dirname $0) && pwd)
statedir="${scriptdir}"
statefile="${statedir}/.foreach.state"
commandfile="${statedir}/.foreach.command"
base=$PWD

function heading {
  printf "\e[38;5;81m$@\e[0m\n"
}

function error {
  printf "\e[91;5;81m$@\e[0m\n"
}

function success {
  printf "\e[32;5;81m$@\e[0m\n"
}

if [[ "${1:-}" == "--reset" ]]; then
    rm -f "${statedir}/.foreach."*
    success "state cleared. you are free to start a new command."
    exit 0
fi

up=""
up_desc=""
if [[ "${1:-}" == "--up" ]]; then
    if [ ! -f package.json ]; then
      echo "--up can only be executed from within a module directory (looking for package.json)"
      exit 1
    fi

    scope=$(node -p "require('./package.json').name")
    up=" --scope ${scope} --include-dependencies"
    up_desc="('${scope}' and its dependencies)"
    shift
fi

command_arg="${@:-}"

if [ -f "${statefile}" ] && [ -f "${commandfile}" ]; then
  command="$(cat ${commandfile})"
  if [ ! -z "${command_arg}" ] && [ "${command}" != "${command_arg}" ]; then
    error "error: there is still an active session for: \"${command}\". to reset:"
    error "   $0 --reset"
    exit 1
  fi
fi

if [ ! -f "${statefile}" ] && [ ! -f "${commandfile}" ]; then
  if [ ! -z "${command_arg}" ]; then
    command="${command_arg}"
    success "starting new session ${up_desc}"
    ${scriptdir}/../node_modules/.bin/lerna ls --all ${up} --toposort -p > ${statefile}
    echo "${command}" > ${commandfile}
  else
    error "no active session, use \"$(basename $0) COMMAND\" to start a new session"
    exit 0
  fi
fi

next="$(head -n1 ${statefile})"
if [ -z "${next}" ]; then
  success "done (queue is empty). to reset:"
  success "   $0 --reset"
  exit 0
fi

remaining=$(cat ${statefile} | wc -l | xargs -n1)

heading "---------------------------------------------------------------------------------"
heading "${next}: ${command} (${remaining} remaining)"

(
  cd ${next}

  # special-case "npm run" or "yarn run" - skip any modules that simply don't have
  # that script (similar to how "lerna run" behaves)
  if [[ "${command}" == "npm run "* ]] || [[ "${command}" == "yarn run "* ]]; then
    script="$(echo ${command} | cut -d" " -f3)"
    exists=$(node -pe "(require('./package.json').scripts && require('./package.json').scripts['${script}']) || ''")
    if [ -z "${exists}" ]; then
      echo "skipping (no "${script}" script in package.json)"
      exit 0
    fi
  fi

  sh -c "${command}" &> /tmp/foreach.stdio || {
    cd ${base}
    cat /tmp/foreach.stdio | ${scriptdir}/path-prefix ${next}
    error "error: last command failed. fix problem and resume by executing: $0"
    error "directory:    ${next}"
    exit 1
  }
)

tail -n +2 "${statefile}" > "${statefile}.tmp"
cp "${statefile}.tmp" "${statefile}"
exec $0


#!/bin/bash
# Generate an aggregate tsconfig.json with references to all projects in the
# repository.
prefix="$(pwd)/"

echo '{'
echo '    "__comment__": "This file is necessary to make transitive Project References in TypeScript work",'
echo '    "files": [],'
echo '    "references": ['

# set the comma to nothing at first.
# if we have more than one package,
# we set $comma to an actual comma
comma='  '
for package in $(node_modules/.bin/lerna ls -ap --ignore 'all-in-farm**'); do
    relpath=${package#"$prefix"}
    echo '  '"$comma"'{ "path": "'"$relpath"'" }'
    comma=', '
done
echo '    ]'
echo '}'


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script is meant to perform the steps necessary to prepare a merge request for a release.
# - Enable the docker Daemon
# - Build and Publish all Lambda Layers
# - Run the Bump script
#
# This script is meant to be run by the RFDK team on their internal pipeline

set -euxo pipefail

SCRIPT_DIR=$(dirname "$0")
SCRIPT_DIR=$(readlink -f "$SCRIPT_DIR")
ROOT_DIR=$(readlink -f "${SCRIPT_DIR}/..")
TESTS_DIR=$(readlink -f "$ROOT_DIR/integ")

# Determine the ECR region we want to use
set +e
# First attempt to use the AWS_REGION environment variable which is set by CodeBuild
# Source: https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
if [ -z ${AWS_REGION+x} ]; then
    # Not running on CodeBuild, so fallback to getting the region from AWS CLI configuration
    echo "could not get region from AWS_REGION environment variable. Attempting AWS configuration..."
    ECR_REGION="$(aws configure get region)"
    if [ "$?" -ne 0 ] || [ -z "${ECR_REGION}" ]; then
        echo "ERROR: Could not determine region"
        exit 1
    fi
else
    ECR_REGION="${AWS_REGION}"
fi
set -e
echo "ECR_REGION=${ECR_REGION}"

# Ensure that the docker daemon is running in the background
# These commands are currently being done here instead of in buildspec due to the following issue: https://github.com/awslabs/aws-delivlib/issues/448
# These commands come from the Codebuild sample for running docker on a custom image: https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker-custom-image.html#sample-docker-custom-image-files
docker info || nohup /usr/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 &
timeout 15 sh -c "until docker info; do echo .; sleep 1; done"

# Pull amazonlinux image locally from ECR. This is done to avoid pulling from DockerHub both for egress and rate
# limiting.
PULL_AL_FROM_ECR_ARGS=(
    # Region of ECR repo
    "${ECR_REGION}"
    # Image versions to pull
    "latest" # required for building and publishing lambda layers
    "2"      # required for building Deadline docker images for running integration tests
)
/bin/bash ${SCRIPT_DIR}/pull_amazonlinux_from_ecr.sh "${PULL_AL_FROM_ECR_ARGS[@]}"

# Run integ tests
/bin/bash ${ROOT_DIR}/build.sh
pushd $TESTS_DIR
yarn run e2e-automated
popd

# Build and publish lambda layers
/bin/bash ${SCRIPT_DIR}/publish-all-lambda-layers.sh

# Perform the bump
/bin/bash ${ROOT_DIR}/bump.sh


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This script is meant to build and publish all Lambda Layers using Docker. Its usage is:
#   publish-all-lambda-layers.sh

set -euo pipefail

SCRIPT_DIR=$(dirname $0)

# Switch to the lambda layers directory
cd "$SCRIPT_DIR/../lambda-layers"

# install and build node packages
yarn
yarn build

# Find all layers
LAYER_NAMES=$(find ./layers -mindepth 1 -maxdepth 1 -printf "%f\n" -type d)

# Switch to the bin directory
cd bin
for LAYER in "${LAYER_NAMES[@]}"
do
    ./build-layer.sh "${LAYER}"
done

for LAYER in "${LAYER_NAMES[@]}"
do
    node ./publish.js "${LAYER}"
done

node ./write-ts.js "${LAYER_NAMES[@]}"


#!/bin/bash

# Fetches the amazonlinux Docker image from the official regional ECR and tags
# it as-if it were fetched from DockerHub. This avoids any egress to the
# internet when pulling images from AWS and also can be used to avoid DockerHub
# rate limits.
#
# This assumes that the AWS CLI is configured to use AWS credentials with
# sufficient access to query and pull images from the amazon linux ECR.
#
# For more information, see:
# https://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html
# https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazonelasticcontainerregistry.html
#
# USAGE
#
#   pull_amazonlinux_from_ecr.sh REGION [VERSION ...]
#
# ARGUMENTS
#
#   REGION
#     The AWS region of the ECR repository to pull from
#
#   VERSION
#     One or more Docker version tags to pull. If not specified, the "latest"
#     tag will be pulled
#
# EXAMPLES
#
#   # Pulls the "latest" version from the us-east-1 ECR repo
#   pull_amazonlinux_from_ecr.sh us-east-1
#
#   # Pulls the "amazonlinux:2" from the us-west-2 ECR repo
#   pull_amazonlinux_from_ecr.sh us-west-2 2

set -euo pipefail

# The AWS account that contains the regional amazonlinux ECRs
AWS_AL_ACCOUNT_ID=137112412989

if [ "$#" -lt 1 ]; then
    echo "ERROR: No region specified"
    exit 1
fi

# Extract the AWS region from the first argument
AWS_REGION="$1"; shift

# Remaining arguments are the image version tags. If not specified, "latest" is
# used.
if [ "$#" -gt 0 ]; then
    TAG_VERSIONS=( "$@" )
else
    TAG_VERSIONS=( "latest" )
fi

# Compute the ECR URI for the specified region
AWS_AL_URI="${AWS_AL_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/amazonlinux"
aws ecr get-login-password --region "${AWS_REGION}" | docker login --username AWS --password-stdin "${AWS_AL_URI}"

for TAG_VERSION in "${TAG_VERSIONS[@]}"; do
    echo "Pulling amazonlinux:${TAG_VERSION}..."
    docker pull "${AWS_AL_URI}:${TAG_VERSION}"
    echo "Tagging amazonlinux:${TAG_VERSION}..."
    docker tag "${AWS_AL_URI}:${TAG_VERSION}" "amazonlinux:${TAG_VERSION}"
    echo "done"
done


#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# This is a helper script for entering a docker build environment suitable for
# building the RFDK. To use: Run this script from the root directory of the RFDK
# repository.

# Make sure we're running from the root of the CDK repo
if ! test -f package.json || ! grep '"name": "aws-rfdk",' package.json > /dev/null || ! grep '"private": true,' package.json > /dev/null
then
    echo "Usage: Run from the root of the RFDK repository"
    exit 1
fi

echo "Entering jsii/superchain docker container so you can interactively build/test RFDK."

USER_OPT="-u $(id -u):$(id -g)"
USERFILE_MOUNTS="-v /etc/passwd:/etc/passwd:ro -v /etc/shadow:/etc/shadow:ro -v /etc/group:/etc/group:ro"

# Share the config directories for language tools in the container.
OTHER_MOUNTS=""
for dir in "${HOME}/.npm" "${HOME}/.dotnet" "${HOME}/.templateengine" "${HOME}/.yarn" "${HOME}/.jsii-cache"
do
  test -d ${dir} || mkdir ${dir}
  OTHER_MOUNTS="${OTHER_MOUNTS} -v ${dir}:${dir}:rw"
done
for file in "${HOME}/.yarnrc"
do
  test -f ${file} || touch ${file}
  OTHER_MOUNTS="${OTHER_MOUNTS} -v ${file}:${file}:rw"
done

# Add the user's ~/.gitconfig if there is one.
test -f "${HOME}/.gitconfig" && OTHER_MOUNTS="${OTHER_MOUNTS} -v ${HOME}/.gitconfig:${HOME}/.gitconfig:ro"

docker run --rm \
    ${USERFILE_MOUNTS} \
    ${OTHER_MOUNTS} \
    -v ${PWD}:${PWD} -w ${PWD} \
    ${USER_OPT} \
    --net=host -it \
    --env DOTNET_CLI_TELEMETRY_OPTOUT=1 \
    jsii/superchain:1-buster-slim-node14


VERSION=0.0.4

build () {
    GOOS=$1 GOARCH=$2 go build -ldflags "-X aws-sagemaker-edge-quick-device-setup/distinfo.OS=$1 -X aws-sagemaker-edge-quick-device-setup/distinfo.ARCH=$2 -X aws-sagemaker-edge-quick-device-setup/distinfo.VERSION=$VERSION" -o ./bin/aws-sagemaker-edge-quick-device-setup-$1-$2 main.go
}

if [ $1-$2 != "linux-amd64" -a $1-$2 != "linux-arm64" ]; then
    echo "USAGE: bash build.sh OS ARCH"
    echo "Supported operating system and architecture combinations"
    echo "- linux amd64"
    echo "- linux arm64"
    exit 1
fi

build $1 $2
for algo in sha1sum sha224sum sha256sum sha384sum sha512sum; do
    ${algo} ./bin/aws-sagemaker-edge-quick-device-setup-$1-$2 > ./bin/aws-sagemaker-edge-quick-device-setup-$1-$2.${algo}
done