#!/bin/bash

# report all lines
set -x

AZURE_HOME_DIR=/home/$ADMIN_USER_NAME

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 yum -y install wget unzip git nfs-utils tmux unbound
}

function configure_grid() {
    # instructions from https://docs.microsoft.com/en-us/azure/virtual-machines/linux/n-series-driver-setup#install-grid-drivers-on-nv-or-nvv3-series-vms
    NVIDIA_RUN_FILE=/opt/nvidia.run
    # get pre-reqs
    retrycmd_if_failure 12 5 yum -y install gcc
    # unable to do a retry because of the quotes
    yum -y install "kernel-devel-uname-r == $(uname -r)"
    retrycmd_if_failure 12 5 rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    retrycmd_if_failure 12 5 yum -y install dkms
    retrycmd_if_failure 12 5 yum -y install hyperv-daemons

    # download
    mkdir -p /opt && curl -L --retry 5 --retry-delay 5 -o $NVIDIA_RUN_FILE  https://go.microsoft.com/fwlink/?linkid=874272

    chmod +x $NVIDIA_RUN_FILE
    $NVIDIA_RUN_FILE -s
}

function configure_gnome() {
    retrycmd_if_failure 12 5 yum -y groups install 'GNOME Desktop'
}

function configure_teradici() {
    # downloads.terradici.com will eventually be deprecated
    retrycmd_if_failure 12 5 yum -y install https://downloads.teradici.com/rhel/teradici-repo-latest.noarch.rpm

    retrycmd_if_failure 12 5 yum -y install epel-release

    retrycmd_if_failure 12 5 yum -y install usb-vhci

    retrycmd_if_failure 12 5 yum -y install pcoip-agent-graphics
}

function configure_teradici_license() {
    # run the following on the machine after the install
    if [[ ! -z "$TERADICI_KEY" ]]; then
        REGISTER_PATH=$(which pcoip-register-host 2> /dev/null)
        if [[ -x "$REGISTER_PATH" ]] ; then
            pcoip-register-host --registration-code=$TERADICI_KEY
        fi
    fi
}

function update_search_domain() {
    if [[ ! -z "$SEARCH_DOMAIN" ]]; then
        NETWORK_FILE=/etc/sysconfig/network-scripts/ifcfg-eth0
        if grep --quiet "DOMAIN=" $NETWORK_FILE; then
            sed -i 's/^#\s*DOMAIN=/DOMAIN=/g' $NETWORK_FILE
            sed -i "s/^DOMAIN=.*$/DOMAIN=\"${SEARCH_DOMAIN}\"/g"  $NETWORK_FILE
        else
            echo "DOMAIN=\"${SEARCH_DOMAIN}\"" >> $NETWORK_FILE
        fi
        # restart network to take effect
        systemctl restart network
    fi
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "configure GNOME Desktop"
    configure_gnome

    if [[ "true" == "$INSTALL_PCOIP" ]]; then
        echo "configure grid"
        configure_grid

        echo "configure Teradici"
        configure_teradici
    else
        echo "not installing pcoip"
    fi

    echo "configure Teradici License"
    configure_teradici_license

    echo "update search domain"
    update_search_domain

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash -x

set -x

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function yum_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        yum install -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo "failed"
            touch /opt/installcycle.failed
            exit 1
        else
            sleep $wait_sleep
        fi
    done
    echo "completed"
    echo Executed yum install -y \"$@\" $i times;
}

function config_linux() {
    # try for 20 minutes
    yum_install 120 10 180 nfs-utils wget unzip git tmux
}

# export the ephemeral disk as specified by $EXPORT_PATH
function configure_cyclecloud() {
    echo "configure_cyclecloud"
    cat > /etc/yum.repos.d/cyclecloud.repo <<EOF
[cyclecloud]
name=cyclecloud
baseurl=https://packages.microsoft.com/yumrepos/cyclecloud
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
EOF

    yum_install 12 10 180 cyclecloud8
}

function install_az_cli() {
    retrycmd_if_failure 12 5 rpm --import https://packages.microsoft.com/keys/microsoft.asc
    sh -c 'echo -e "[azure-cli]
name=Azure CLI
baseurl=https://packages.microsoft.com/yumrepos/azure-cli
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azure-cli.repo'
    retrycmd_if_failure 12 5 yum -y install azure-cli
}

function wait_az_login() {
    # wait for RBAC assignments to be applied
    # unfortunately, the RBAC assignments take undetermined time past their associated resource completions to be assigned.
    if ! retrycmd_if_failure 120 5 az login --identity ; then
        echo "MANAGED IDENTITY FAILURE: failed to login after waiting 10 minutes, this is managed identity bug"
        exit 1
    fi
    if ! retrycmd_if_failure 12 5 az account set --subscription $SUBSCRIPTION_ID ; then
        echo "MANAGED IDENTITY FAILURE: failed to set subscription"
        exit 1
    fi
}

function main() {
    mkdir -p /opt

    if [ "${USE_MARKETPLACE}" = "false" ]; then

        echo "config Linux"
        config_linux

        echo "setup CycleCloud"
        configure_cyclecloud
    fi

    echo "install az cli"
    install_az_cli

    echo "wait az login"
    wait_az_login

    echo "installation complete"

    touch /opt/installcycle.complete
}

main


#!/bin/bash

# report all lines, and exit on error
set -x
set -e

AZURE_HOME_DIR=/home/$ADMIN_USER_NAME

function retrycmd_if_failure() {
    set +e
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            set -e
            return 1
        else
            sleep $wait_sleep
        fi
    done
    set -e
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 yum -y install wget unzip git nfs-utils tmux unbound
}

function configure_unbound() {
    UNBOUND_CONF_FILE=/etc/unbound/unbound.conf
    cp $UNBOUND_CONF_FILE $UNBOUND_CONF_FILE.bak
    cp /opt/unbound.conf $UNBOUND_CONF_FILE

    systemctl start unbound
    systemctl enable unbound
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "configure unbound"
    configure_unbound

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash

# report all lines, and exit on error
set -x
set -e

AZURE_HOME_DIR=/home/$ADMIN_USER_NAME

function retrycmd_if_failure() {
    set +e
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            set -e
            return 1
        else
            sleep $wait_sleep
        fi
    done
    set -e
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 apt update -y
    retrycmd_if_failure 12 5 apt install -y unbound
}

function configure_unbound() {
    # first disable systemd-resolved
    systemctl stop systemd-resolved
    systemctl disable systemd-resolved
    ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

    UNBOUND_CONF_FILE=/etc/unbound/unbound.conf
    cp $UNBOUND_CONF_FILE $UNBOUND_CONF_FILE.bak
    cp /opt/unbound.conf $UNBOUND_CONF_FILE

    systemctl restart unbound
    systemctl enable unbound
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "configure unbound"
    configure_unbound

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash

# report all lines, and exit on error
set -x
set -e

AZURE_HOME_DIR=/home/$ADMIN_USER_NAME

function retrycmd_if_failure() {
    set +e
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            set -e
            return 1
        else
            sleep $wait_sleep
        fi
    done
    set -e
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 yum -y install wget unzip git nfs-utils tmux nc jq
    retrycmd_if_failure 12 5 yum -y install epel-release
    retrycmd_if_failure 12 5 yum -y install python-pip
    #retrycmd_if_failure 3 5 pip install hstk
}

function install_golang() {
    cd $AZURE_HOME_DIR
    GO_DL_FILE=go1.16.6.linux-amd64.tar.gz
    wget --tries=12 --wait=5 https://dl.google.com/go/$GO_DL_FILE
    sudo tar -C /usr/local -xzf $GO_DL_FILE
    rm -f $GO_DL_FILE
    #echo "export GOPATH=$AZURE_HOME_DIR/gopath" >> $AZURE_HOME_DIR/.profile
    echo "export PATH=$PATH:/usr/local/go/bin" >> $AZURE_HOME_DIR/.profile
}

function pull_avere_github() {
    # use workaround set home for go to work, bug here: https://github.com/golang/go/issues/43938
    OLD_HOME=$HOME
    export HOME=$AZURE_HOME_DIR

    # best effort to build the github content
    set +e
    RELEASE_DIR=$AZURE_HOME_DIR/releases
    mkdir -p $RELEASE_DIR
    source $AZURE_HOME_DIR/.profile
    cd $AZURE_HOME_DIR
    git clone https://github.com/Azure/Avere.git

    # build the provider
    cd $AZURE_HOME_DIR/Avere/src/terraform/providers/terraform-provider-avere
    go build
    GOOS=windows GOARCH=amd64 go build
    mv terraform-provider-avere* $RELEASE_DIR/.

    # build the cachewarmer
    cd $AZURE_HOME_DIR/Avere/src/go/cmd/cachewarmer/cachewarmer-jobsubmitter
    go build
    mv cachewarmer-jobsubmitter $RELEASE_DIR/.
    cd $AZURE_HOME_DIR/Avere/src/go/cmd/cachewarmer/cachewarmer-manager
    go build
    mv cachewarmer-manager $RELEASE_DIR/.
    cd $AZURE_HOME_DIR/Avere/src/go/cmd/cachewarmer/cachewarmer-worker
    go build
    mv cachewarmer-worker $RELEASE_DIR/.

    cd $RELEASE_DIR/.
    ls -lh

    # install provider
    version=$(curl -s https://api.github.com/repos/Azure/Avere/releases/latest | jq -r .tag_name | sed -e 's/[^0-9]*\([0-9].*\)$/\1/')
    echo $version
    mkdir -p $AZURE_HOME_DIR/.terraform.d/plugins/registry.terraform.io/hashicorp/avere/$version/linux_amd64
    cp $RELEASE_DIR/terraform-provider-avere $AZURE_HOME_DIR/.terraform.d/plugins/registry.terraform.io/hashicorp/avere/$version/linux_amd64

    # restore HOME
    export HOME=$OLD_HOME

    # re-enable exit on error
    set -e
}

function install_az_cli() {
    retrycmd_if_failure 12 5 rpm --import https://packages.microsoft.com/keys/microsoft.asc
    sh -c 'echo -e "[azure-cli]
name=Azure CLI
baseurl=https://packages.microsoft.com/yumrepos/azure-cli
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azure-cli.repo'
    retrycmd_if_failure 12 5 yum -y install azure-cli
}

function install_terraform() {
    cd $AZURE_HOME_DIR/.
    wget --tries=12 --wait=5 https://releases.hashicorp.com/terraform/1.0.2/terraform_1.0.2_linux_amd64.zip
    unzip terraform_1.0.2_linux_amd64.zip -d /usr/local/bin
    rm terraform_1.0.2_linux_amd64.zip
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    if [ "${BUILD_VFXT_PROVIDER}" = "true" ]; then
        echo "install golang"
        install_golang

        echo "pull and build the Avere github project"
        pull_avere_github
    fi

    echo "install az cli"
    install_az_cli

    echo "install terraform"
    install_terraform

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash

# report all lines
set -x

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 apt update
    retrycmd_if_failure 12 5 apt install -y unzip nfs-kernel-server iotop iperf3 bwm-ng
    retrycmd_if_failure 12 5 apt install -y unison
}

function configure_sync() {
    # installing per https://docs.microsoft.com/en-us/azure/avere-vfxt/avere-vfxt-data-ingest#use-the-msrsync-utility
    curl --retry 5 --retry-delay 5 -o /usr/bin/prime.py https://raw.githubusercontent.com/Azure/Avere/main/src/clientapps/dataingestor/prime.py
    sed -i 's:^#!/usr/bin/env python$:#!/usr/bin/env python2:' /usr/bin/prime.py
    chmod +x /usr/bin/prime.py

    curl --retry 5 --retry-delay 5 -o /usr/bin/msrsync https://raw.githubusercontent.com/jbd/msrsync/master/msrsync
    chmod +x /usr/bin/msrsync

    # unison - popular two-way synchronization - https://github.com/bcpierce00/unison
    #retrycmd_if_failure 12 5 yum -y install epel-release
    #retrycmd_if_failure 12 5 yum -y install unison

    # here are some other choices that have not been installed
    #  syncthing - modern, actively developed, open, 2-way synchronization tool, syncthing does not preserve uid/gid
    #  https://dirsyncpro.org/index.html - for syncing two directories

    # download syncthing: https://computingforgeeks.com/install-and-configure-syncthing-on-centos-linux/
    # syncthing does not preserve uid/gid
    #mkdir -p /opt
    #cd /opt
    #curl -s https://api.github.com/repos/syncthing/syncthing/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi -
    #tar xvf syncthing-linux-amd64*.tar.gz
    #cp syncthing-linux-amd64-*/syncthing  /bin/.
    #chmod +x /bin/syncthing
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "configure sync"
    configure_sync

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash -x

# variables that must be set beforehand
# EXPORT_PATH=/data
# EXPORT_OPTIONS="*(rw,sync,no_root_squash)"
#
# called like this:
#  sudo EXPORT_PATH=/data EXPORT_OPTIONS="*(rw,sync,no_root_squash)" ./installnfs.sh
#

# terraform variables: tf_env_variables

set -x

function yum_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        yum install -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo "failed"
            touch /opt/installnfs.failed
            exit 1
        else
            sleep $wait_sleep
        fi
    done
    echo "completed"
    echo Executed yum install -y \"$@\" $i times;

    yum install -y nfs-utils
}

function config_linux() {
    # try for 20 minutes
    yum_install 120 10 180 nfs-utils
}

function config_ephemeral_nvme {
    RAIDDISK=/dev/md0
    DISKS=($(ls /dev/nvme*n*))
    DISKCOUNT=${#DISKS[@]}
    if [ "$DISKCOUNT" -eq "1" ] ; then
        DISK_DEVICE=${DISKS[0]}
    else
        udevadm control --stop-exec-queue
        echo "yes" | mdadm --create $RAIDDISK --level=0 --raid-devices=$DISKCOUNT ${DISKS[@]}
        udevadm control --start-exec-queue
        mkdir -p /etc/mdadm
        mdadm --detail --verbose --scan > /etc/mdadm/mdadm.conf
        # log the details of the mount to STDOUT
        mdadm --detail --verbose --scan
        cat /proc/mdstat
        DISK_DEVICE=$RAIDDISK
    fi

    # add the ext4 filesystem
    mkfs.ext4 -F $DISK_DEVICE

    read UUID FS_TYPE < <(blkid -u filesystem $DISK_DEVICE|awk -F "[= ]" '{print $3" "$5}'|tr -d "\"")
    echo -e "UUID=\"${UUID}\"\t$EXPORT_PATH\t$FS_TYPE\tnoatime,nodiratime,nodev,noexec,nosuid,nofail\t1 2" >> /etc/fstab
    mount $EXPORT_PATH
}

function config_ephemeral_ssd {
    grep -e "/mnt\s" /etc/fstab > /dev/null 2>&1
    if [ $? = "0" ]; then
        # this is managed by the new cloud init

        # export the ephemeral disk
        EPHEMERAL_DISK_PATH="/mnt"
        umount $EPHEMERAL_DISK_PATH
        sed -i "s:${EPHEMERAL_DISK_PATH}:${EXPORT_PATH}:g" /etc/fstab
        mount ${EXPORT_PATH}
    else
        grep -e "cloud-init.service" /etc/fstab > /dev/null 2>&1
        if [ $? = "0" ]; then
            # export the ephemeral disk
            EPHEMERAL_DISK_PATH="/mnt/resource"
            umount $EPHEMERAL_DISK_PATH
            sed -i "s:${EPHEMERAL_DISK_PATH}:${EXPORT_PATH}:g" /etc/fstab
            mount ${EXPORT_PATH}
        else
            # this is managed by older waagent

            # export the ephemeral disk
            EPHEMERAL_DISK_PATH="/mnt/resource"
            # move the ephemeral mount to the mount chosen by the customer
            # we cannot do the symbolic link because it is not supported by nfsv4
            umount $EPHEMERAL_DISK_PATH
            sed -i "s:${EPHEMERAL_DISK_PATH}:${EXPORT_PATH}:g" /etc/waagent.conf
            # restart waagent to mount the new share
            systemctl restart waagent
        fi
    fi
}

function config_ephemeral_disk {
    mkdir -p $EXPORT_PATH
    grep nfsnobody /etc/passwd > /dev/null 2>&1
    if [ $? = "0" ]; then
        chown nfsnobody:nfsnobody $EXPORT_PATH
    else
        chown nobody:nogroup $EXPORT_PATH
    fi

    ls -1 /dev/nvme*
    if [ $? = "0" ]; then
        config_ephemeral_nvme
    else
        config_ephemeral_ssd
    fi
    chmod 777 $EXPORT_PATH
}

# export the ephemeral disk as specified by $EXPORT_PATH
function configure_nfs() {
    # enable the nfs service
    systemctl enable nfs-server rpcbind

    # stop the nfs service
    systemctl stop nfs-server rpcbind

    # configure NFS export for the export path
    grep "^${EXPORT_PATH}" /etc/exports > /dev/null 2>&1
    if [ $? = "0" ]; then
        echo "${EXPORT_PATH} is already exported. Returning..."
    else
        echo -e "\n${EXPORT_PATH}   ${EXPORT_OPTIONS}" >> /etc/exports
    fi

    # update to use 64 threads to get most performance
    sed -i 's/^.*RPCNFSDCOUNT=.*$/RPCNFSDCOUNT=64/g' /etc/sysconfig/nfs

    # start the nfs service
    systemctl start nfs-server rpcbind
}

function main() {
    mkdir -p /opt

    if [ -z "$EXPORT_PATH" ]; then
        echo "env var EXPORT_PATH is not defined, please define"
        touch /opt/installnfs.failed
        exit 1
    fi

    if [ -z "$EXPORT_OPTIONS" ]; then
        echo "env var EXPORT_OPTIONS is not defined, please define"
        touch /opt/installnfs.failed
        exit 1
    fi

    echo "config Linux"
    config_linux

    echo "config Ephemeral Disk"
    config_ephemeral_disk

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"

    touch /opt/installnfs.complete
}

main


#!/bin/bash -x

# variables that must be set beforehand
# EXPORT_PATH=/data
#
# called like this:
#  sudo EXPORT_PATH=/data ./installnfs.sh
#

set -x

MOUNT_OPTIONS="noatime,nodiratime,nodev,noexec,nosuid,nofail"

function apt_get_update() {
    retries=10
    apt_update_output=/tmp/apt-get-update.out
    for i in $(seq 1 $retries); do
        timeout 120 apt-get update 2>&1 | tee $apt_update_output | grep -E "^([WE]:.*)|([eE]rr.*)$"
        [ $? -ne 0  ] && cat $apt_update_output && break || \
        cat $apt_update_output
        if [ $i -eq $retries ]; then
            return 1
        else sleep 30
        fi
    done
    echo Executed apt-get update $i times
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        # timeout occasionally freezes
        #echo "timeout $timeout apt-get install --no-install-recommends -y ${@}"
        #timeout $timeout apt-get install --no-install-recommends -y ${@}
        apt-get install --no-install-recommends -y ${@}
        echo "completed"
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            return 1
        else
            sleep $wait_sleep
            apt_get_update
        fi
    done
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function config_linux() {
	export DEBIAN_FRONTEND=noninteractive
    add-apt-repository universe
	apt_get_update
	apt_get_install 20 10 180 nfs-ganesha nfs-ganesha-vfs
    # perf diagnostic tools
    if [ ! -z "$PERF_DIAG_TOOLS" ]; then
        apt_get_install 20 10 180 iotop iperf3 bwm-ng
    fi
    # enable root login, sometimes useful for rsync
    if [ ! -z "$ALLOW_ROOT_LOGIN" ]; then
        sed -i 's/.* ssh-rsa/ssh-rsa/' /root/.ssh/authorized_keys
        sed -i 's/^#PermitRootLogin.*$/PermitRootLogin yes/' /etc/ssh/sshd_config
        systemctl restart sshd
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function is_partitioned() {
    OUTPUT=$(partx -s ${1} 2>&1)
    egrep "partition table does not contains usable partitions|failed to read partition table" <<< "${OUTPUT}" >/dev/null 2>&1
    if [ ${?} -eq 0 ]; then
        return 1
    else
        return 0
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function has_filesystem() {
    DEVICE=${1}
    OUTPUT=$(file -L -s ${DEVICE})
    grep filesystem <<< "${OUTPUT}" > /dev/null 2>&1
    return ${?}
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_for_new_disks() {
    # Looks for unpartitioned disks
    declare -a RET
    DEVS=($(ls -1 /dev/sd*|egrep -v "[0-9]$"))
    for DEV in "${DEVS[@]}";
    do
        # The disk will be considered a candidate for partitioning
        # and formatting if it does not have a sd?1 entry or
        # if it does have an sd?1 entry and does not contain a filesystem
        is_partitioned "${DEV}"
        if [ ${?} -eq 0 ];
        then
            has_filesystem "${DEV}1"
            if [ ${?} -ne 0 ];
            then
                RET+=" ${DEV}"
            fi
        else
            RET+=" ${DEV}"
        fi
    done
    echo "${RET}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function add_to_fstab() {
    UUID=${1}
    MOUNTPOINT=${2}
    grep "${UUID}" /etc/fstab >/dev/null 2>&1
    if [ ${?} -eq 0 ];
    then
        echo "Not adding ${UUID} to fstab again (it's already there!)"
    else
        LINE="UUID=\"${UUID}\"\t${MOUNTPOINT}\text4\t${MOUNT_OPTIONS}\t1 2"
        echo -e "${LINE}" >> /etc/fstab
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function do_partition() {
    # This function creates one (1) primary partition on the
    # disk, using all available space
    _disk=${1}
    _type=${2}
    if [ -z "${_type}" ]; then
        # default to Linux partition type (ie, ext3/ext4/xfs)
        _type=8300
    fi
    echo "n
1

${_type}
w
y"| gdisk "${_disk}"

    #
    # Use the bash-specific $PIPESTATUS to ensure we get the correct exit code
    # from gdisk and not from echo
    if [ ${PIPESTATUS[1]} -ne 0 ];
    then
        echo "An error occurred partitioning ${_disk}" >&2
        echo "I cannot continue" >&2
        exit 2
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_partition_format()
{
    echo "Begin scanning and formatting data disks"

    DISKS=($(scan_for_new_disks))

    if [ "${#DISKS[@]}" -eq 0 ];
    then
        echo "No unpartitioned disks without filesystems detected"
        return
    fi
    if [ "${#DISKS[@]}" -gt 1 ];
    then
        echo "WARNING: there are ${#DISKS[@]} unformatted disks, only the first disk will be mounted"
    fi
    echo "Disks are ${DISKS[@]}"
    DISK=${DISKS[0]}

    echo "Working on ${DISK}"
    is_partitioned ${DISK}
    if [ ${?} -ne 0 ];
    then
        echo "${DISK} is not partitioned, partitioning"
        do_partition ${DISK}
    fi
    PARTITION_NUM=$(gdisk -l ${DISK}|grep -A 1 Number|tail -n 1|awk '{print $1}')
    PARTITION=${DISK}${PARTITION_NUM}
    has_filesystem ${PARTITION}
    if [ ${?} -ne 0 ];
    then
        echo "Creating filesystem on ${PARTITION}."
        mkfs -j -t ext4 ${PARTITION}
    fi
}

function get_unmounted_disk()
{
    DEVS=($(ls -1 /dev/sd*|egrep "[a-z][0-9]$"))
    TARGET_PARTITION=""
    for DEV in "${DEVS[@]}";
    do
        if ! mount | grep -F --quiet "$DEV"; then
            TARGET_PARTITION=$DEV
            break
        fi
    done
    echo "$TARGET_PARTITION"
}

function mount_disk() {
    PARTITION=$1; shift

    MOUNTPOINT=$EXPORT_PATH
    echo "mount point is ${MOUNTPOINT}"
    if [ ! -d "${MOUNTPOINT}" ];
    then
        mkdir -p "${MOUNTPOINT}"
        chown nobody:nogroup "${MOUNTPOINT}"
        chmod 777 "${MOUNTPOINT}"
        ls -l "${MOUNTPOINT}"
    fi
    read UUID FS_TYPE < <(blkid -u filesystem ${PARTITION}|awk -F "[= ]" '{print $3" "$5}'|tr -d "\"")
    add_to_fstab "${UUID}" "${MOUNTPOINT}"
    echo "Mounting disk ${PARTITION} on ${MOUNTPOINT}"
    mount "${MOUNTPOINT}"
}

function wait_for_disk_attach() {
    retries=$1; wait_sleep=$2; shift && shift

    for i in $(seq 1 $retries); do
        DISKS=($(scan_for_new_disks))
        if [ "${#DISKS[@]}" -gt 0 ]; then
            echo "new disk found!"
            return
        fi

        PARTITION=$(get_unmounted_disk)

        if [ ${#PARTITION} -gt 0 ]; then
            echo "unattached disk found!"
            return
        fi

        echo "no disks found, sleeping for $wait_sleep seconds"
        sleep $wait_sleep
    done
}

# export the ephemeral disk as specified by $EXPORT_PATH
function configure_nfs() {
    # enable the nfs service
    systemctl enable nfs-ganesha

    # stop the nfs service
    systemctl stop nfs-ganesha

    cp /etc/ganesha/ganesha.conf /etc/ganesha/ganesha.conf.bak

    echo "EXPORT
{
        # Export Id (mandatory, each EXPORT must have a unique Export_Id)
        Export_Id = 87;

        # Exported path (mandatory)
        Path = ${EXPORT_PATH};

        # Pseudo Path (required for NFS v4)
        Pseudo = ${EXPORT_PATH};

        # Required for access (default is None)
        # Could use CLIENT blocks instead
        Access_Type = RW;

        # Exporting FSAL
        FSAL {
                Name = VFS;
        }
        CLIENT {
                Access_Type=RW;
                Anonymous_gid=4294967294;
                Anonymous_uid=4294967294;
                Clients=*;
                Delegations=none;
                Manage_Gids=FALSE;
                NFS_Commit=FALSE;
                PrivilegedPort=FALSE;
                Protocols= 3,4;
                SecType=NONE,SYS;
                Squash=NO_ROOT_SQUASH;
                Transports=UDP,TCP;
        }
}" > /etc/ganesha/ganesha.conf

    # start the nfs service
    systemctl start nfs-ganesha
}

function main() {
    mkdir -p /opt

    if [ -z "$EXPORT_PATH" ]; then
        echo "env var EXPORT_PATH is not defined, please define"
        touch /opt/installnfs.failed
        touch /opt/installnfs.complete
        exit 1
    fi

    echo "config Linux"
    config_linux

    # wait 10 minutes for a disk to show up
    wait_for_disk_attach 60 10

    echo "scan_partition_format"
    scan_partition_format

    echo "mount_unmounted_disk"
    PARTITION=$(get_unmounted_disk)

    if [ ${#PARTITION} -eq 0 ]; then
        echo "no unmounted file system exists"
        touch /opt/installnfs.failed
        touch /opt/installnfs.complete
        return 1
    fi

    mount_disk $PARTITION

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"
    touch /opt/installnfs.complete
}

main


#!/bin/bash -x

# variables that must be set beforehand
# EXPORT_PATH=/data
# EXPORT_OPTIONS="*(rw,sync,no_root_squash)"
#
# called like this:
#  sudo EXPORT_PATH=/data EXPORT_OPTIONS="*(rw,sync,no_root_squash)" ./installnfs.sh
#

set -x

MOUNT_OPTIONS="noatime,nodiratime,nodev,noexec,nosuid,nofail"

function yum_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        yum install -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo "failed"
            touch /opt/installnfs.failed
            exit 1
        else
            sleep $wait_sleep
        fi
    done
    echo "completed"
    echo Executed yum install -y \"$@\" $i times;
}

function config_linux() {
    # try for 20 minutes
    yum_install 120 10 180 nfs-utils
    # perf diagnostic tools
    if [ ! -z "$PERF_DIAG_TOOLS" ]; then
        yum_install 120 10 180 iotop iperf3
        yum_install 120 10 180 epel-release
        yum_install 120 10 180 bwm-ng
    fi
    # enable root login, sometimes useful for rsync
    if [ ! -z "$ALLOW_ROOT_LOGIN" ]; then
        sed -i 's/.* ssh-rsa/ssh-rsa/' /root/.ssh/authorized_keys
        sed -i 's/^#PermitRootLogin.*$/PermitRootLogin yes/' /etc/ssh/sshd_config
        systemctl restart sshd
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function is_partitioned() {
    OUTPUT=$(partx -s ${1} 2>&1)
    egrep "partition table does not contains usable partitions|failed to read partition table" <<< "${OUTPUT}" >/dev/null 2>&1
    if [ ${?} -eq 0 ]; then
        return 1
    else
        return 0
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function has_filesystem() {
    DEVICE=${1}
    OUTPUT=$(file -L -s ${DEVICE})
    grep filesystem <<< "${OUTPUT}" > /dev/null 2>&1
    return ${?}
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_for_new_disks() {
    # Looks for unpartitioned disks
    declare -a RET
    DEVS=($(ls -1 /dev/sd*|egrep -v "[0-9]$"))
    for DEV in "${DEVS[@]}";
    do
        # The disk will be considered a candidate for partitioning
        # and formatting if it does not have a sd?1 entry or
        # if it does have an sd?1 entry and does not contain a filesystem
        is_partitioned "${DEV}"
        if [ ${?} -eq 0 ];
        then
            has_filesystem "${DEV}1"
            if [ ${?} -ne 0 ];
            then
                RET+=" ${DEV}"
            fi
        else
            RET+=" ${DEV}"
        fi
    done
    echo "${RET}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function add_to_fstab() {
    UUID=${1}
    MOUNTPOINT=${2}
    grep "${UUID}" /etc/fstab >/dev/null 2>&1
    if [ ${?} -eq 0 ];
    then
        echo "Not adding ${UUID} to fstab again (it's already there!)"
    else
        LINE="UUID=\"${UUID}\"\t${MOUNTPOINT}\text4\t${MOUNT_OPTIONS}\t1 2"
        echo -e "${LINE}" >> /etc/fstab
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function do_partition() {
    # This function creates one (1) primary partition on the
    # disk, using all available space
    _disk=${1}
    _type=${2}
    if [ -z "${_type}" ]; then
        # default to Linux partition type (ie, ext3/ext4/xfs)
        _type=8300
    fi
    echo "n
1

${_type}
w
y"| gdisk "${_disk}"

    #
    # Use the bash-specific $PIPESTATUS to ensure we get the correct exit code
    # from gdisk and not from echo
    if [ ${PIPESTATUS[1]} -ne 0 ];
    then
        echo "An error occurred partitioning ${_disk}" >&2
        echo "I cannot continue" >&2
        exit 2
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_partition_format()
{
    echo "Begin scanning and formatting data disks"

    DISKS=($(scan_for_new_disks))

    if [ "${#DISKS[@]}" -eq 0 ];
    then
        echo "No unpartitioned disks without filesystems detected"
        return
    fi
    if [ "${#DISKS[@]}" -gt 1 ];
    then
        echo "WARNING: there are ${#DISKS[@]} unformatted disks, only the first disk will be mounted"
    fi
    echo "Disks are ${DISKS[@]}"
    DISK=${DISKS[0]}

    echo "Working on ${DISK}"
    is_partitioned ${DISK}
    if [ ${?} -ne 0 ];
    then
        echo "${DISK} is not partitioned, partitioning"
        do_partition ${DISK}
    fi
    PARTITION_NUM=$(gdisk -l ${DISK}|grep -A 1 Number|tail -n 1|awk '{print $1}')
    PARTITION=${DISK}${PARTITION_NUM}
    has_filesystem ${PARTITION}
    if [ ${?} -ne 0 ];
    then
        echo "Creating filesystem on ${PARTITION}."
        mkfs -j -t ext4 ${PARTITION}
    fi
}

function get_unmounted_disk()
{
    DEVS=($(ls -1 /dev/sd*|egrep "[0-9]$"))
    TARGET_PARTITION=""
    for DEV in "${DEVS[@]}";
    do
        if ! mount | grep -F --quiet "$DEV"; then
            TARGET_PARTITION=$DEV
            break
        fi
    done
    echo "$TARGET_PARTITION"
}

function mount_disk() {
    PARTITION=$1; shift

    MOUNTPOINT=$EXPORT_PATH
    echo "mount point is ${MOUNTPOINT}"
    if [ ! -d "${MOUNTPOINT}" ];
    then
        mkdir -p "${MOUNTPOINT}"
        chown nfsnobody:nfsnobody "${MOUNTPOINT}"
        chmod 777 "${MOUNTPOINT}"
        ls -l "${MOUNTPOINT}"
    fi
    read UUID FS_TYPE < <(blkid -u filesystem ${PARTITION}|awk -F "[= ]" '{print $3" "$5}'|tr -d "\"")
    add_to_fstab "${UUID}" "${MOUNTPOINT}"
    echo "Mounting disk ${PARTITION} on ${MOUNTPOINT}"
    mount "${MOUNTPOINT}"
}

function wait_for_disk_attach() {
    retries=$1; wait_sleep=$2; shift && shift

    for i in $(seq 1 $retries); do
        DISKS=($(scan_for_new_disks))
        if [ "${#DISKS[@]}" -gt 0 ]; then
            echo "new disk found!"
            return
        fi

        PARTITION=$(get_unmounted_disk)

        if [ ${#PARTITION} -gt 0 ]; then
            echo "unattached disk found!"
            return
        fi

        echo "no disks found, sleeping for $wait_sleep seconds"
        sleep $wait_sleep
    done
}

# export the ephemeral disk as specified by $EXPORT_PATH
function configure_nfs() {
    # enable the nfs service
    systemctl enable nfs-server rpcbind

    # stop the nfs service
    systemctl stop nfs-server rpcbind

    # configure NFS export for the export path
    grep "^${EXPORT_PATH}" /etc/exports > /dev/null 2>&1
    if [ $? = "0" ]; then
        echo "${EXPORT_PATH} is already exported. Returning..."
    else
        echo -e "\n${EXPORT_PATH}   ${EXPORT_OPTIONS}" >> /etc/exports
    fi

    # update to use 64 threads to get most performance
    sed -i 's/^.*RPCNFSDCOUNT=.*$/RPCNFSDCOUNT=64/g' /etc/sysconfig/nfs

    # start the nfs service
    systemctl start nfs-server rpcbind
}

function main() {
    mkdir -p /opt

    if [ -z "$EXPORT_PATH" ]; then
        echo "env var EXPORT_PATH is not defined, please define"
        touch /opt/installnfs.failed
        touch /opt/installnfs.complete
        exit 1
    fi

    if [ -z "$EXPORT_OPTIONS" ]; then
        echo "env var EXPORT_OPTIONS is not defined, please define"
        touch /opt/installnfs.failed
        touch /opt/installnfs.complete
        exit 1
    fi

    echo "config Linux"
    config_linux

    # wait 10 minutes for a disk to show up
    wait_for_disk_attach 60 10

    echo "scan_partition_format"
    scan_partition_format

    echo "mount_unmounted_disk"
    PARTITION=$(get_unmounted_disk)

    if [ ${#PARTITION} -eq 0 ]; then
        echo "no unmounted file system exists"
        touch /opt/installnfs.failed
        touch /opt/installnfs.complete
        return 1
    fi

    mount_disk $PARTITION

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"
    touch /opt/installnfs.complete
}

main


#!/bin/bash

# report all lines, and exit on error
set -x
set -e

AZURE_HOME_DIR=/home/$ADMIN_USER_NAME

function retrycmd_if_failure() {
    set +e
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            set -e
            return 1
        else
            sleep $wait_sleep
        fi
    done
    set -e
    echo Executed \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 yum -y install wget unzip git nfs-utils tmux squid
}

function start_squid() {
    systemctl start squid
    systemctl enable squid
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "start squid"
    start_squid

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash

# report all lines
set -x

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            return 1
        else
            sleep $wait_sleep
            retrycmd_if_failure 12 5 apt-get update
        fi
    done
    echo "completed"
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 apt-get update
    apt_get_install 180 10 nfs-common
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/vbash

# use /bin/vbash as stated in the vyos documentation

# report all lines
set -x

# required to get all the VyOS alias definitions
source /opt/vyatta/etc/functions/script-template

# variables passed in
# ONPREM_VTI_DUMMY_ADDRESS
# VYOS_ADDRESS
# VYOS_BGP_ADDRESS
# CLOUD_ADDRESS
# CLOUD_BGP_ADDRESS
# PRE_SHARED_KEY
# VYOS_ASN
# CLOUD_ASN

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function configure_vyos() {
    # The below configuration was based on the following VyOS documentation
    # 1. https://docs.vyos.io/en/equuleus/automation/command-scripting.html
    # 2. https://docs.vyos.io/en/equuleus/configexamples/azure-vpn-bgp.html
    echo "enter configure"
    configure
    echo "inside configure"
    set vpn ipsec esp-group AZURE compression 'disable'
    set vpn ipsec esp-group AZURE lifetime '3600'
    set vpn ipsec esp-group AZURE mode 'tunnel'
    set vpn ipsec esp-group AZURE pfs 'dh-group2'
    set vpn ipsec esp-group AZURE proposal 1 encryption 'aes256'
    set vpn ipsec esp-group AZURE proposal 1 hash 'sha1'
    set vpn ipsec ike-group AZURE dead-peer-detection action 'restart'
    set vpn ipsec ike-group AZURE dead-peer-detection interval '15'
    set vpn ipsec ike-group AZURE dead-peer-detection timeout '30'
    set vpn ipsec ike-group AZURE ikev2-reauth 'yes'
    set vpn ipsec ike-group AZURE key-exchange 'ikev2'
    set vpn ipsec ike-group AZURE lifetime '28800'
    set vpn ipsec ike-group AZURE proposal 1 dh-group '2'
    set vpn ipsec ike-group AZURE proposal 1 encryption 'aes256'
    set vpn ipsec ike-group AZURE proposal 1 hash 'sha1'
    set vpn ipsec ipsec-interfaces interface 'eth0'
    set interfaces vti vti1 address $ONPREM_VTI_DUMMY_ADDRESS/32
    set interfaces vti vti1 description 'Azure Tunnel'
    set firewall options interface vti1 adjust-mss 1350
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS authentication id $VYOS_ADDRESS
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS authentication mode 'pre-shared-secret'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS authentication pre-shared-secret $PRE_SHARED_KEY
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS authentication remote-id $CLOUD_ADDRESS
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS connection-type 'respond'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS description 'AZURE PRIMARY TUNNEL'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS ike-group 'AZURE'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS ikev2-reauth 'inherit'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS local-address $VYOS_BGP_ADDRESS
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS vti bind 'vti1'
    set vpn ipsec site-to-site peer $CLOUD_ADDRESS vti esp-group 'AZURE'
    set protocols static interface-route $CLOUD_BGP_ADDRESS/32 next-hop-interface vti1
    set protocols bgp $VYOS_ASN neighbor $CLOUD_BGP_ADDRESS remote-as $CLOUD_ASN
    set protocols bgp $VYOS_ASN neighbor $CLOUD_BGP_ADDRESS address-family ipv4-unicast soft-reconfiguration 'inbound'
    set protocols bgp $VYOS_ASN neighbor $CLOUD_BGP_ADDRESS timers holdtime '30'
    set protocols bgp $VYOS_ASN neighbor $CLOUD_BGP_ADDRESS timers keepalive '10'
    set protocols bgp $VYOS_ASN neighbor $CLOUD_BGP_ADDRESS disable-connected-check
    echo "start commit"
    # add some retries for commit as there can be temporary locks on config
    commit || (sleep 10 && commit) || (sleep 10 && commit) || (sleep 10 && commit) || (sleep 10 && commit)
    echo "start save"
    save
    echo "finish save"
    exit
    echo "successful exit"
}

function main() {
    touch /opt/install.started

    echo "configure VyOS VPN Connection"
    configure_vyos

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash

# report all lines
set -x

# the following variables are set and used in this script
#    PRIVATE_KEY
#    PEER_PUBLIC_KEY
#    PEER_PUBLIC_ADDRESS
#    PEER_ADDRESS_SPACE_CSV
#    TUNNEL_SIDE
#    DUMMY_IP_PREFIX
#    TUNNEL_COUNT
#    BASE_UDP_PORT

function retrycmd_if_failure() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $wait_sleep
        fi
    done
    echo Executed \"$@\" $i times;
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            return 1
        else
            sleep $wait_sleep
            retrycmd_if_failure 12 5 apt-get update
        fi
    done
    echo "completed"
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function update_linux() {
    retrycmd_if_failure 12 5 apt-get update
    apt_get_install 12 5 nfs-kernel-server iotop iperf3 bwm-ng wireguard
}

function configure_wireguard() {
    # add ECMP script for the wireguard interfaces
    /bin/cat <<EOM >/usr/bin/wg-ecmp
#!/bin/bash
set -x

PEER_ADDRESS_SPACE_CSV="$PEER_ADDRESS_SPACE_CSV"
WG_INTERFACES=\$(wg | grep interface | awk '{ print \$2 }')
WGARR=(\$WG_INTERFACES)
WGCOUNT=\${#WGARR[@]}

if [ \$WGCOUNT -gt 0 ] ; then
    for AddressSpace in \$(echo \$PEER_ADDRESS_SPACE_CSV | sed "s/,/ /g"); do
        ecmpCmd="ip route change \$AddressSpace"
        for wg in \$WG_INTERFACES; do
            ecmpCmd="\$ecmpCmd nexthop dev \$wg weight 1"
        done
        \$(\$ecmpCmd)
    done
fi
EOM
    chmod +x /usr/bin/wg-ecmp

    PRIMARY="primary"
    SECONDARY="secondary"
    START_OCTET4=0
    if [ "$TUNNEL_SIDE" == "$SECONDARY" ]; then
        START_OCTET4=1
    fi

    for i in $(seq 0 $(expr ${TUNNEL_COUNT} - 1)); do
        WGIFACE="wg$i"
        PORT=$(expr ${BASE_UDP_PORT} + $i)
        BASE_OCTET4=$(expr $i \* 2)
        OCTET4=$(expr ${START_OCTET4} + $i \* 2)
        # avoid printing secrets
        set +x
        /bin/cat <<EOM >/etc/wireguard/${WGIFACE}.conf
[Interface]
PrivateKey = ${PRIVATE_KEY}
ListenPort = ${PORT}
Address = ${DUMMY_IP_PREFIX}.${OCTET4}/31
EOM
        set -x

        # add Table = off, to avoid adding routes on all but first tunnel, per guidance https://blog.muthuraj.in/2020/06/high-throughput-site-to-site-vpn-using.html?m=1
        if [ $i -eq 0 ]; then
            /bin/cat <<EOM >>/etc/wireguard/${WGIFACE}.conf
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
EOM
        else
            /bin/cat <<EOM >>/etc/wireguard/${WGIFACE}.conf
Table = off
PostUp = /usr/bin/wg-ecmp
PostDown = /usr/bin/wg-ecmp
EOM
        fi

/bin/cat <<EOM >>/etc/wireguard/${WGIFACE}.conf

[Peer]
PublicKey = ${PEER_PUBLIC_KEY}
AllowedIPs = ${DUMMY_IP_PREFIX}.${BASE_OCTET4}/31,${PEER_ADDRESS_SPACE_CSV}
Endpoint= ${PEER_PUBLIC_ADDRESS}:${PORT}
PersistentKeepalive = 10
EOM
        sudo systemctl enable wg-quick@${WGIFACE}.service
        sudo systemctl daemon-reload
        sudo systemctl start wg-quick@${WGIFACE}
    done

    # enable IP forwarding, and make persistent after boot
    sed -i 's/^#\s*net.ipv4.ip_forward\s*=.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
    sysctl --system
}

function main() {
    touch /opt/install.started

    echo "update linux"
    update_linux

    echo "install wireguard"
    configure_wireguard

    echo "installation complete"
    touch /opt/install.completed
}

main


#!/bin/bash
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.

#
# The following script mounts a default round robin's across the
# vFXT ip addresses.
#
# Save this script to any Avere vFXT volume, for example:
#     /bootstrap/centosbootstrap.sh
#
# The following environment variables must be set:
#     NFS_IP_CSV="172.16.0.22,172.16.0.23,172.16.0.24"
#     NFS_PATH=/msazure
#     BASE_DIR=/avere
#     BOOTSTRAP_PATH=/b
#     BOOTSTRAP_SCRIPT=/b/bootstrap/centosbootstrap.sh
#     BOOTSTRAP_NFS_IP=172.16.0.22
#     BOOTSTRAP_NFS_PATH=msazure
#
# This is executed as a startup task from batch, using the
# following command line:
#
#     bash -c 'sudo yum -y install nfs-utils && sudo mkdir -p $BOOTSTRAP_PATH && sudo mount ${BOOTSTRAP_NFS_IP}:/${BOOTSTRAP_NFS_PATH} $BOOTSTRAP_PATH && sudo -E /bin/bash $BOOTSTRAP_SCRIPT 2>&1 | sudo tee -a /var/log/bootstrap.log && sudo umount $BOOTSTRAP_PATH && sudo rmdir $BOOTSTRAP_PATH'
#

function retrycmd_if_failure() {
    retries=$1; max_wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $(($RANDOM % $max_wait_sleep))
        fi
    done
    echo Executed \"$@\" $i times;
}

function mount_round_robin() {
    # to ensure the nodes are spread out somewhat evenly the default
    # mount point is based on this node's IP octet4 % vFXT node count.
    declare -a AVEREVFXT_NODES="($(echo ${NFS_IP_CSV} | sed "s/,/ /g"))"
    OCTET4=$((`hostname -i | sed -e 's/^.*\.\([0-9]*\)/\1/'  | sed 's/[^0-9]*//g'`))
    DEFAULT_MOUNT_INDEX=$((${OCTET4} % ${#AVEREVFXT_NODES[@]}))
    ROUND_ROBIN_IP=${AVEREVFXT_NODES[${DEFAULT_MOUNT_INDEX}]}

    DEFAULT_MOUNT_POINT="${BASE_DIR}/default"

    # no need to write again if it is already there
    if ! grep --quiet "${DEFAULT_MOUNT_POINT}" /etc/fstab; then
        echo "${ROUND_ROBIN_IP}:${NFS_PATH}    ${DEFAULT_MOUNT_POINT}    nfs hard,nointr,proto=tcp,mountproto=tcp,retry=30 0 0" >> /etc/fstab
        mkdir -p "${DEFAULT_MOUNT_POINT}"
        chown nfsnobody:nfsnobody "${DEFAULT_MOUNT_POINT}"
    fi
    if ! grep -qs "${DEFAULT_MOUNT_POINT} " /proc/mounts; then
        retrycmd_if_failure 12 20 mount "${DEFAULT_MOUNT_POINT}" || exit 1
    fi
}

function main() {
    echo "mount round robin default path"
    mount_round_robin

    # add extra bootstrap code here
}

main


#!/bin/bash -ex
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.

#
# The following script render a generic maya scene.
#
# Save this script to any Avere vFXT volume, for example:
#     /src/render.sh
#
# The following environment variables must be set:
#     FRAME_START=1
#     FRAME_END=1
#     MAYA_PROJECT_PATH=/nfs/default/demoscene
#     SCENE_FILE=/nfs/default/demoscene/kongSkeleton_walk.ma
#     IMAGES_OUTPUT_BASE_PATH=/nfs/default/images
#     ADDITIONAL_FLAGS=" -of png "
#
# This is executed as the render job from batch, using the
# following command line:
#
#     /bin/bash -c '/bin/bash [parameters('renderScriptPath')] ; err=$? ; exit $err'
#

# if doing real work, remove or set to false
IS_DEMO=true

function render_scene() {
    if [ "${IS_DEMO}" = true ] ; then
        # clear client caches - good for demo, but not good for real job
        echo     3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
    fi

    # render the scene
    echo "running command: /bin/maya2018.sh -r sw ${ADDITIONAL_FLAGS} -proj ${MAYA_PROJECT_PATH} -rd ${IMAGES_OUTPUT_BASE_PATH}/${AZ_BATCH_JOB_ID} -s ${FRAME_START} -e ${FRAME_END} ${SCENE_FILE}"
    /bin/maya2018.sh -r sw ${ADDITIONAL_FLAGS} -proj ${MAYA_PROJECT_PATH} -rd ${IMAGES_OUTPUT_BASE_PATH}/${AZ_BATCH_JOB_ID} -s ${FRAME_START} -e ${FRAME_END} ${SCENE_FILE}
}

function main() {
    render_scene

    # add extra render code here
}

main


#!/bin/bash -ex
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.
#
# Save this script to any Avere vFXT volume, for example:
#     /src/render8gb.sh
#
# The following environment variables must be set:
#     FRAME_START=1
#     FRAME_END=1
#     MAYA_PROJECT_PATH=/nfs/default/scenes/8gbscene
#     SCENE_FILE=/nfs/default/scenes/8gbscene/scenes/SEQ001/SHOT001/anim/versions/SEQ001_SHOT001_anim_v010_Imported.ma
#     IMAGES_OUTPUT_BASE_PATH=/nfs/default/images
#     DEBUG_PATH=/nfs/default/debug
#     ADDITIONAL_FLAGS=" -of png "
#
# This is executed as the render job from batch, using the
# following command line:
#
#     /bin/bash -c '/bin/bash [parameters('renderScriptPath')] ; err=$? ; exit $err'
#

# if doing real work, remove or set to false
IS_DEMO=true

function log_debug_info() {
    set
    mount
    whoami

    # add empty file named after this machine's ip to the mount folder for the job
    MOUNT_POINT=`mount | grep default | sed -e 's/^\([^:]*\):.*/\1/'`
    THIS_HOST=`hostname -i`
    DEBUG_TARGET_DIR=${DEBUG_PATH}/${AZ_BATCH_JOB_ID}/${MOUNT_POINT}
    mkdir -p ${DEBUG_TARGET_DIR}
    touch ${DEBUG_TARGET_DIR}/${THIS_HOST}
}

function stagger_on_first_task_round_algorithm1() {
    # stagger the first round of jobs over 6 minutes, but only for the first set of tasks
    TASK_COUNT_FOR_NODE=`find ${AZ_BATCH_NODE_ROOT_DIR}/workitems/${AZ_BATCH_JOB_ID}/. -maxdepth 3 -type d | grep wd | wc -l`
    if [ "${TASK_COUNT_FOR_NODE}" -le "${MAX_TASKS_PER_NODE}" ] ; then
        SLEEP_TIME=$(($RANDOM % 360))
        echo "staggering by sleeping for ${SLEEP_TIME} seconds (${TASK_COUNT_FOR_NODE} < ${MAX_TASKS_PER_NODE})"
        sleep ${SLEEP_TIME}
    else
        echo "no stagger because ${TASK_COUNT_FOR_NODE} >= ${MAX_TASKS_PER_NODE}"
    fi
}

function stagger_on_first_task_round_algorithm2() {
    # stagger the first round of jobs over 6 minutes, but only for the first set of tasks
    TASK_COUNT_FOR_NODE=`find ${AZ_BATCH_NODE_ROOT_DIR}/workitems/${AZ_BATCH_JOB_ID}/. -maxdepth 3 -type d | grep wd | wc -l`
    if [ "${TASK_COUNT_FOR_NODE}" -le "${MAX_TASKS_PER_NODE}" ] ; then
        NODE_ID=`echo $AZ_BATCH_NODE_ID | sed -e 's/^.*_\([0-9]*\)-.*/\1/'`
        SLEEP_TIME=$((($NODE_ID/5)*7))
        echo "staggering by sleeping for ${SLEEP_TIME} seconds (${TASK_COUNT_FOR_NODE} < ${MAX_TASKS_PER_NODE})"
        sleep ${SLEEP_TIME}
    else
        echo "no stagger because ${TASK_COUNT_FOR_NODE} >= ${MAX_TASKS_PER_NODE}"
    fi
}

function run_demo_code() {
    # clear client caches - good for demo, but not good for real job
    echo "clearing client cache by running '3 | sudo tee /proc/sys/vm/drop_caches > /dev/null'"
    echo     3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
}

function render_scene() {
    # render the scene
    echo "running command: /bin/maya2018.sh -r sw ${ADDITIONAL_FLAGS} -proj ${MAYA_PROJECT_PATH} -rd ${IMAGES_OUTPUT_BASE_PATH}/${AZ_BATCH_JOB_ID} -s ${FRAME_START} -e ${FRAME_END} ${SCENE_FILE}"
    /bin/maya2018.sh -r sw ${ADDITIONAL_FLAGS} -proj ${MAYA_PROJECT_PATH} -rd ${IMAGES_OUTPUT_BASE_PATH}/${AZ_BATCH_JOB_ID} -s ${FRAME_START} -e ${FRAME_END} ${SCENE_FILE}
}

function main() {

    log_debug_info

    #stagger_on_first_task_round_algorithm1
    stagger_on_first_task_round_algorithm2

    if [ "${IS_DEMO}" = true ] ; then
        run_demo_code
    fi

    render_scene

    # add extra render code here
}

main


#!/bin/bash -x

# variables that must be set beforehand
# EXPORT_PATH=/data
# EXPORT_OPTIONS="*(rw,sync,no_root_squash)"
#
# called like this:
#  sudo EXPORT_PATH=/data EXPORT_OPTIONS="*(rw,sync,no_root_squash)" ./installnfs.sh
#

# terraform variables: tf_env_variables

set -x

function yum_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        yum install -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo "failed"
            touch /opt/installnfs.failed
            exit 1
        else
            sleep $wait_sleep
        fi
    done
    echo "completed"
    echo Executed yum install -y \"$@\" $i times;

    yum install -y nfs-utils
}

function config_linux() {
	yum_install 20 10 180 nfs-utils
}

# export the ephemeral disk as specified by $EXPORT_PATH
function configure_nfs() {
    # enable the nfs service
    systemctl enable nfs-server rpcbind

    # stop the nfs service
    systemctl stop nfs-server rpcbind

    mkdir -p $EXPORT_PATH

    grep -e "/mnt\s" /etc/fstab > /dev/null 2>&1
    if [ $? = "0" ]; then
        # this is managed by the new cloud init

        # export the ephemeral disk
        EPHEMERAL_DISK_PATH="/mnt"
        umount $EPHEMERAL_DISK_PATH
        sed -i "s:${EPHEMERAL_DISK_PATH}:${EXPORT_PATH}:g" /etc/fstab
        mount ${EXPORT_PATH}
    else
        # this is managed by older waagent

        # export the ephemeral disk
        EPHEMERAL_DISK_PATH="/mnt/resource"
        # move the ephemeral mount to the mount chosen by the customer
        # we cannot do the symbolic link because it is not supported by nfsv4
        umount $EPHEMERAL_DISK_PATH
        sed -i "s:${EPHEMERAL_DISK_PATH}:${EXPORT_PATH}:g" /etc/waagent.conf
        # restart waagent to mount the new share
        systemctl restart waagent
    fi

    # configure NFS export for the export path
    grep "^${EXPORT_PATH}" /etc/exports > /dev/null 2>&1
    if [ $? = "0" ]; then
        echo "${EXPORT_PATH} is already exported. Returning..."
    else
        echo -e "\n${EXPORT_PATH}   ${EXPORT_OPTIONS}" >> /etc/exports
    fi

    # update to use 64 threads to get most performance
    sed -i 's/^.*RPCNFSDCOUNT=.*$/RPCNFSDCOUNT=64/g' /etc/sysconfig/nfs

    # start the nfs service
    systemctl start nfs-server rpcbind
}

function main() {
    mkdir -p /opt

    if [ -z "$EXPORT_PATH" ]; then
        echo "env var EXPORT_PATH is not defined, please define"
        touch /opt/installnfs.failed
        exit 1
    fi

    if [ -z "$EXPORT_OPTIONS" ]; then
        echo "env var EXPORT_OPTIONS is not defined, please define"
        touch /opt/installnfs.failed
        exit 1
    fi

    echo "config Linux"
    config_linux

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"

    touch /opt/installnfs.complete
}

main


#!/bin/bash -x

# variables that must be set beforehand
# DATA_BASE=/datadisks
#
# called like this:
#  sudo DATA_BASE=/datadisks ./installnfs.sh
#

MOUNT_OPTIONS="noatime,nodiratime,nodev,noexec,nosuid,nofail"

function apt_get_update() {
    retries=10
    apt_update_output=/tmp/apt-get-update.out
    for i in $(seq 1 $retries); do
        timeout 120 apt-get update 2>&1 | tee $apt_update_output | grep -E "^([WE]:.*)|([eE]rr.*)$"
        [ $? -ne 0  ] && cat $apt_update_output && break || \
        cat $apt_update_output
        if [ $i -eq $retries ]; then
            return 1
        else sleep 30
        fi
    done
    echo Executed apt-get update $i times
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        # timeout occasionally freezes
        #echo "timeout $timeout apt-get install --no-install-recommends -y ${@}"
        #timeout $timeout apt-get install --no-install-recommends -y ${@}
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            return 1
        else
            sleep $wait_sleep
            apt_get_update
        fi
    done
    echo "completed"
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function config_linux() {
	#hostname=`hostname -s`
	#sudo sed -ie "s/127.0.0.1 localhost/127.0.0.1 localhost ${hostname}/" /etc/hosts
	export DEBIAN_FRONTEND=noninteractive
	apt_get_update
	apt_get_install 20 10 180 nfs-kernel-server nfs-common
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function is_partitioned() {
    OUTPUT=$(partx -s ${1} 2>&1)
    egrep "partition table does not contains usable partitions|failed to read partition table" <<< "${OUTPUT}" >/dev/null 2>&1
    if [ ${?} -eq 0 ]; then
        return 1
    else
        return 0
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function has_filesystem() {
    DEVICE=${1}
    OUTPUT=$(file -L -s ${DEVICE})
    grep filesystem <<< "${OUTPUT}" > /dev/null 2>&1
    return ${?}
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_for_new_disks() {
    # Looks for unpartitioned disks
    declare -a RET
    DEVS=($(ls -1 /dev/sd*|egrep -v "[0-9]$"))
    for DEV in "${DEVS[@]}";
    do
        # The disk will be considered a candidate for partitioning
        # and formatting if it does not have a sd?1 entry or
        # if it does have an sd?1 entry and does not contain a filesystem
        is_partitioned "${DEV}"
        if [ ${?} -eq 0 ];
        then
            has_filesystem "${DEV}1"
            if [ ${?} -ne 0 ];
            then
                RET+=" ${DEV}"
            fi
        else
            RET+=" ${DEV}"
        fi
    done
    echo "${RET}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
add_to_fstab() {
    UUID=${1}
    MOUNTPOINT=${2}
    grep "${UUID}" /etc/fstab >/dev/null 2>&1
    if [ ${?} -eq 0 ];
    then
        echo "Not adding ${UUID} to fstab again (it's already there!)"
    else
        LINE="UUID=\"${UUID}\"\t${MOUNTPOINT}\text4\t${MOUNT_OPTIONS}\t1 2"
        echo -e "${LINE}" >> /etc/fstab
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function do_partition() {
    # This function creates one (1) primary partition on the
    # disk, using all available space
    _disk=${1}
    _type=${2}
    if [ -z "${_type}" ]; then
        # default to Linux partition type (ie, ext3/ext4/xfs)
        _type=83
    fi
    echo "n
p
1

t
${_type}
w"| fdisk "${_disk}"

    #
    # Use the bash-specific $PIPESTATUS to ensure we get the correct exit code
    # from fdisk and not from echo
    if [ ${PIPESTATUS[1]} -ne 0 ];
    then
        echo "An error occurred partitioning ${_disk}" >&2
        echo "I cannot continue" >&2
        exit 2
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
get_next_mountpoint() {
    DIRS=$(ls -1d ${DATA_BASE}/disk* 2>/dev/null| sort --version-sort)
    MAX=$(echo "${DIRS}"|tail -n 1 | tr -d "[a-zA-Z/]")
    if [ -z "${MAX}" ];
    then
        echo "${DATA_BASE}/disk1"
        return
    fi
    IDX=1
    while [ "${IDX}" -lt "${MAX}" ];
    do
        NEXT_DIR="${DATA_BASE}/disk${IDX}"
        if [ ! -d "${NEXT_DIR}" ];
        then
            echo "${NEXT_DIR}"
            return
        fi
        IDX=$(( ${IDX} + 1 ))
    done
    IDX=$(( ${MAX} + 1))
    echo "${DATA_BASE}/disk${IDX}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_partition_format()
{
    echo "Begin scanning and formatting data disks"

    DISKS=($(scan_for_new_disks))

	if [ "${#DISKS}" -eq 0 ];
	then
	    echo "No unpartitioned disks without filesystems detected"
	    return
	fi
	echo "Disks are ${DISKS[@]}"
	for DISK in "${DISKS[@]}";
	do
	    echo "Working on ${DISK}"
	    is_partitioned ${DISK}
	    if [ ${?} -ne 0 ];
	    then
	        echo "${DISK} is not partitioned, partitioning"
	        do_partition ${DISK}
	    fi
	    PARTITION=$(fdisk -l ${DISK}|grep -A 1 Device|tail -n 1|awk '{print $1}')
	    has_filesystem ${PARTITION}
	    if [ ${?} -ne 0 ];
	    then
	        echo "Creating filesystem on ${PARTITION}."
	        mkfs -j -t ext4 ${PARTITION}
	    fi
	    MOUNTPOINT=$(get_next_mountpoint)
	    echo "Next mount point appears to be ${MOUNTPOINT}"
	    if [ ! -d "${MOUNTPOINT}" ];
        then
            mkdir -p "${MOUNTPOINT}"
            chown nobody:nogroup "${MOUNTPOINT}"
            chmod 777 "${MOUNTPOINT}"
            ls -l "${MOUNTPOINT}"
        fi
	    read UUID FS_TYPE < <(blkid -u filesystem ${PARTITION}|awk -F "[= ]" '{print $3" "$5}'|tr -d "\"")
	    add_to_fstab "${UUID}" "${MOUNTPOINT}"
	    echo "Mounting disk ${PARTITION} on ${MOUNTPOINT}"
	    mount "${MOUNTPOINT}"
	done
}

# export all the disks under ${DATA_BASE} for NFS
function configure_nfs() {
    DIRS=$(ls -1d ${DATA_BASE}/disk* 2>/dev/null| sort --version-sort)
    for MOUNTPOINT in "${DIRS[@]}";
	do
        # configure NFS export for the disk
        grep "^${MOUNTPOINT}" /etc/exports > /dev/null 2>&1
        if [ $? = "0" ]; then
            echo "${MOUNTPOINT} is already exported. Returning..."
        else
            echo -e "\n${MOUNTPOINT}   *(rw,sync,no_root_squash)" >> /etc/exports
        fi
    done

    systemctl enable nfs-kernel-server.service
    systemctl restart nfs-kernel-server.service
}

function main() {
    echo "config Linux"
    config_linux

    echo "scan_partition_format"
    scan_partition_format

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"
}

main


#!/bin/bash -x
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.
#
# The following script mounts a default round robin's across the
# vFXT ip addresses.
#

# the comma separated Avere vFXT vServer IP addresses
export NFS_IP_CSV="10.0.0.22,10.0.0.23,10.0.0.24"
export TARGET_IP_EASTUS=192.168.255.4
export TARGET_IP_WESTUS=192.168.255.20
export TARGET_IP_WESTINDIA=192.168.255.52
export TARGET_IP_SOUTHEASTASIA=192.168.255.36

function retrycmd_if_failure() {
    retries=$1; max_wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $(($RANDOM % $max_wait_sleep))
        fi
    done
    echo Executed \"$@\" $i times;
}

function mount_target() {
    NFS_PATH=$1
    TARGET_MOUNT_POINT=$2
    TARGET_IP=$3
    if ! grep --quiet "${TARGET_IP}:${NFS_PATH}" /etc/fstab; then
        echo "${TARGET_IP}:${NFS_PATH}    ${TARGET_MOUNT_POINT}    nfs hard,nointr,proto=tcp,mountproto=tcp,retry=30 0 0" >> /etc/fstab
        mkdir -p "${TARGET_MOUNT_POINT}"
        chown nfsnobody:nfsnobody "${TARGET_MOUNT_POINT}"
    fi
    if ! grep -qs "${TARGET_MOUNT_POINT} " /proc/mounts; then
        retrycmd_if_failure 12 20 mount "${TARGET_MOUNT_POINT}" || exit 1
    fi
}

function mount_round_robin_e32() {
    # to ensure the nodes are spread out somewhat evenly the default
    # mount point is based on this node's IP octet4 % vFXT node count.
    declare -a AVEREVFXT_NODES="($(echo ${NFS_IP_CSV} | sed "s/,/ /g"))"
    OCTET4=$((`hostname -i | sed -e 's/^.*\.\([0-9]*\)/\1/'  | sed 's/[^0-9]*//g'`))
    DEFAULT_MOUNT_INDEX=$((${OCTET4} % ${#AVEREVFXT_NODES[@]}))
    ROUND_ROBIN_IP=${AVEREVFXT_NODES[${DEFAULT_MOUNT_INDEX}]}

    NFS_PATH="/eastus"
    TARGET_MOUNT_POINT="/nfs/${NFS_PATH}vfxt"
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $ROUND_ROBIN_IP

    NFS_PATH="/westus"
    TARGET_MOUNT_POINT="/nfs/${NFS_PATH}vfxt"
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $ROUND_ROBIN_IP

    NFS_PATH="/westindia"
    TARGET_MOUNT_POINT="/nfs/${NFS_PATH}vfxt"
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $ROUND_ROBIN_IP

    NFS_PATH="/southeastasia"
    TARGET_MOUNT_POINT="/nfs/${NFS_PATH}vfxt"
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $ROUND_ROBIN_IP
}

function mount_regional_cluster() {
    # no need to write again if it is already there
    NFS_PATH=/datadisks/disk1

    TARGET_MOUNT_POINT=/nfs/eastus
    TARGET_IP=$TARGET_IP_EASTUS
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $TARGET_IP

    TARGET_MOUNT_POINT=/nfs/westus
    TARGET_IP=$TARGET_IP_WESTUS
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $TARGET_IP

    TARGET_MOUNT_POINT=/nfs/westindia
    TARGET_IP=$TARGET_IP_WESTINDIA
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $TARGET_IP

    TARGET_MOUNT_POINT=/nfs/southeastasia
    TARGET_IP=$TARGET_IP_SOUTHEASTASIA
    mount_target $NFS_PATH $TARGET_MOUNT_POINT $TARGET_IP
}

function main() {
    echo "mount the regional cluster"
    mount_regional_cluster

    echo "mount round robin the e32 vfxt default path"
    mount_round_robin_e32

    # add extra bootstrap code here
}

main


#!/bin/bash
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.

set -x

function wait_vfxt_log() {
    mountpoint=$1
    while :
    do

        if timeout 5 ls $mountpoint; then
            echo "mount is live"
            break
        fi
        echo "$(date) mount is frozen"
    done
}

export DstSub="b52fce95-de5f-4b37-afca-db203a5d0b6a"
export DstResourceGroupName="avereeastusbatch"
export DstLocation="eastus"
export BatchAccountName="avereeastusbatch"
az account set --subscription $DstSub
az batch account login --resource-group $DstResourceGroupName --name $BatchAccountName
wait_vfxt_log "/nfs/node0"


#!/bin/bash -x

# variables that must be set beforehand
# DATA_BASE=/datadisks
#
# called like this:
#  sudo DATA_BASE=/datadisks ./installnfs.sh
#

MOUNT_OPTIONS="noatime,nodiratime,nodev,noexec,nosuid,nofail"

function apt_get_update() {
    retries=10
    apt_update_output=/tmp/apt-get-update.out
    for i in $(seq 1 $retries); do
        timeout 120 apt-get update 2>&1 | tee $apt_update_output | grep -E "^([WE]:.*)|([eE]rr.*)$"
        [ $? -ne 0  ] && cat $apt_update_output && break || \
        cat $apt_update_output
        if [ $i -eq $retries ]; then
            return 1
        else sleep 30
        fi
    done
    echo Executed apt-get update $i times
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        # timeout occasionally freezes
        #echo "timeout $timeout apt-get install --no-install-recommends -y ${@}"
        #timeout $timeout apt-get install --no-install-recommends -y ${@}
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo "failed"
            return 1
        else
            sleep $wait_sleep
            apt_get_update
        fi
    done
    echo "completed"
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function config_linux() {
	#hostname=`hostname -s`
	#sudo sed -ie "s/127.0.0.1 localhost/127.0.0.1 localhost ${hostname}/" /etc/hosts
	export DEBIAN_FRONTEND=noninteractive
	apt_get_update
	apt_get_install 20 10 180 nfs-kernel-server nfs-common
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function is_partitioned() {
    OUTPUT=$(partx -s ${1} 2>&1)
    egrep "partition table does not contains usable partitions|failed to read partition table" <<< "${OUTPUT}" >/dev/null 2>&1
    if [ ${?} -eq 0 ]; then
        return 1
    else
        return 0
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function has_filesystem() {
    DEVICE=${1}
    OUTPUT=$(file -L -s ${DEVICE})
    grep filesystem <<< "${OUTPUT}" > /dev/null 2>&1
    return ${?}
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_for_new_disks() {
    # Looks for unpartitioned disks
    declare -a RET
    DEVS=($(ls -1 /dev/sd*|egrep -v "[0-9]$"))
    for DEV in "${DEVS[@]}";
    do
        # The disk will be considered a candidate for partitioning
        # and formatting if it does not have a sd?1 entry or
        # if it does have an sd?1 entry and does not contain a filesystem
        is_partitioned "${DEV}"
        if [ ${?} -eq 0 ];
        then
            has_filesystem "${DEV}1"
            if [ ${?} -ne 0 ];
            then
                RET+=" ${DEV}"
            fi
        else
            RET+=" ${DEV}"
        fi
    done
    echo "${RET}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
add_to_fstab() {
    UUID=${1}
    MOUNTPOINT=${2}
    grep "${UUID}" /etc/fstab >/dev/null 2>&1
    if [ ${?} -eq 0 ];
    then
        echo "Not adding ${UUID} to fstab again (it's already there!)"
    else
        LINE="UUID=\"${UUID}\"\t${MOUNTPOINT}\text4\t${MOUNT_OPTIONS}\t1 2"
        echo -e "${LINE}" >> /etc/fstab
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function do_partition() {
    # This function creates one (1) primary partition on the
    # disk, using all available space
    _disk=${1}
    _type=${2}
    if [ -z "${_type}" ]; then
        # default to Linux partition type (ie, ext3/ext4/xfs)
        _type=83
    fi
    echo "n
p
1

t
${_type}
w"| fdisk "${_disk}"

    #
    # Use the bash-specific $PIPESTATUS to ensure we get the correct exit code
    # from fdisk and not from echo
    if [ ${PIPESTATUS[1]} -ne 0 ];
    then
        echo "An error occurred partitioning ${_disk}" >&2
        echo "I cannot continue" >&2
        exit 2
    fi
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
get_next_mountpoint() {
    DIRS=$(ls -1d ${DATA_BASE}/disk* 2>/dev/null| sort --version-sort)
    MAX=$(echo "${DIRS}"|tail -n 1 | tr -d "[a-zA-Z/]")
    if [ -z "${MAX}" ];
    then
        echo "${DATA_BASE}/disk1"
        return
    fi
    IDX=1
    while [ "${IDX}" -lt "${MAX}" ];
    do
        NEXT_DIR="${DATA_BASE}/disk${IDX}"
        if [ ! -d "${NEXT_DIR}" ];
        then
            echo "${NEXT_DIR}"
            return
        fi
        IDX=$(( ${IDX} + 1 ))
    done
    IDX=$(( ${MAX} + 1))
    echo "${DATA_BASE}/disk${IDX}"
}

# source from https://github.com/Azure/azure-quickstart-templates/blob/master/shared_scripts/ubuntu/vm-disk-utils-0.1.sh
function scan_partition_format()
{
    echo "Begin scanning and formatting data disks"

    DISKS=($(scan_for_new_disks))

	if [ "${#DISKS}" -eq 0 ];
	then
	    echo "No unpartitioned disks without filesystems detected"
	    return
	fi
	echo "Disks are ${DISKS[@]}"
	for DISK in "${DISKS[@]}";
	do
	    echo "Working on ${DISK}"
	    is_partitioned ${DISK}
	    if [ ${?} -ne 0 ];
	    then
	        echo "${DISK} is not partitioned, partitioning"
	        do_partition ${DISK}
	    fi
	    PARTITION=$(fdisk -l ${DISK}|grep -A 1 Device|tail -n 1|awk '{print $1}')
	    has_filesystem ${PARTITION}
	    if [ ${?} -ne 0 ];
	    then
	        echo "Creating filesystem on ${PARTITION}."
	        mkfs -j -t ext4 ${PARTITION}
	    fi
	    MOUNTPOINT=$(get_next_mountpoint)
	    echo "Next mount point appears to be ${MOUNTPOINT}"
	    if [ ! -d "${MOUNTPOINT}" ];
        then
            mkdir -p "${MOUNTPOINT}"
            chown nobody:nogroup "${MOUNTPOINT}"
            chmod 777 "${MOUNTPOINT}"
            ls -l "${MOUNTPOINT}"
        fi
	    read UUID FS_TYPE < <(blkid -u filesystem ${PARTITION}|awk -F "[= ]" '{print $3" "$5}'|tr -d "\"")
	    add_to_fstab "${UUID}" "${MOUNTPOINT}"
	    echo "Mounting disk ${PARTITION} on ${MOUNTPOINT}"
	    mount "${MOUNTPOINT}"
	done
}

# export all the disks under ${DATA_BASE} for NFS
function configure_nfs() {
    DIRS=$(ls -1d ${DATA_BASE}/disk* 2>/dev/null| sort --version-sort)
    for MOUNTPOINT in "${DIRS[@]}";
	do
        # configure NFS export for the disk
        grep "^${MOUNTPOINT}" /etc/exports > /dev/null 2>&1
        if [ $? = "0" ]; then
            echo "${MOUNTPOINT} is already exported. Returning..."
        else
            echo -e "\n${MOUNTPOINT}   *(rw,sync,no_root_squash)" >> /etc/exports
        fi
    done

    systemctl enable nfs-kernel-server.service
    systemctl restart nfs-kernel-server.service
}

function main() {
    echo "config Linux"
    config_linux

    echo "scan_partition_format"
    scan_partition_format

    echo "setup NFS Server"
    configure_nfs

    echo "installation complete"
}

main


#!/bin/bash

###########################################################
#
# Watch vfxt.log and enable cloud trace after the
# management IP is received, and disable cloud trace after
# the script has finished.  The purpose of cloud trace is
# for additional debugging information during installation.
#
# Ensure completion by stopping if the vfxt.log file does
# not show up or if the installation script stops, and
# vfxt.log stops being updated.
#
###########################################################

# report all lines, and exit on error
set -x

# this script will handle all its errors, so don't set -e
# set -e

AZURE_HOME_DIR=/home/$CONTROLLER_ADMIN_USER_NAME
VFXT_LOG_FILE=$AZURE_HOME_DIR/vfxt.log
WAIT_SECONDS=300
RPC_ENABLE="enable"
RPC_DISABLE="disable"

function sendRPC() {
    set +x
    ipaddress=$1; action=$2

    AVERECMD="averecmd --raw --no-check-certificate --user admin --password $ADMIN_PASSWORD --server $ipaddress"
    if [ "$action" == "$RPC_ENABLE" ] ; then
        echo "send 'support.acceptTerms yes' to ${ipaddress}"
        $AVERECMD support.acceptTerms yes
        result=$?

        echo "send ${action} to ${ipaddress}"
        $AVERECMD support.modify "{'traceLevel': '0xE00000000100', 'rollingTrace': 'yes', 'statsMonitor': 'yes', 'memoryDebugging': 'yes'}"
        result=$((result+$?))
    elif [ "$action" == "$RPC_DISABLE" ] ; then
        echo "send ${action} to ${ipaddress}"
        $AVERECMD support.modify "{'traceLevel': '0x1', 'rollingTrace': 'no', 'statsMonitor': 'no', 'memoryDebugging': 'no'}"
        result=$?
    else
        echo "ERROR: bad action"
        result=1
    fi

    set -x
    return $result
}

function check_halted_vfxt() {
    now=$(date +%s)
    filemtime=$(stat -c %Y $VFXT_LOG_FILE)
    difference=$(($now-$filemtime))
    if [ "$difference" -gt "$WAIT_SECONDS" ] ; then
        echo "FATAL: the log file ${VFXT_LOG_FILE} has halted"
        exit 1
    fi
}

function wait_vfxt_log() {
    counter=0
    while [ ! -f $VFXT_LOG_FILE ]; do
        sleep 1
        counter=$((counter + 1))
        if [ $counter -ge $WAIT_SECONDS ]; then
            echo "file '${VFXT_LOG_FILE}' did not appear after ${WAIT_SECONDS} seconds"
            exit 1
        fi
    done
}

function wait_management_ip() {
    while :
    do
        ipaddress=$(egrep "^address=([0-9]{1,3}\.){3}[0-9]{1,3}" ${VFXT_LOG_FILE} | awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/); ip = substr($0,RSTART,RLENGTH); print ip}')
        if [ "${#ipaddress}" -gt "0" ]
        then
            echo "${ipaddress}"
            break
        fi
        check_halted_vfxt
        sleep 1
    done
}

function wait_complete_message() {
    while :
    do
        if grep --quiet "vfxt:INFO - Complete" ${VFXT_LOG_FILE}; then
            echo "vfxt has completed installation"
            break
        elif grep --quiet "vfxt:ERROR - Failed to create cluster" ${VFXT_LOG_FILE}; then
            echo "vfxt installation failed"
            break
        fi
        check_halted_vfxt
        sleep 1
    done
}

function enable_cloud_trace() {
    ipaddress=$1
    echo "trying to enable cloud trace "

    while :
    do
        # retry forever until we reach the mgmt ip or the vfxt.log stops
        if sendRPC $ipaddress $RPC_ENABLE ; then
            echo "sendRPC success"
            break
        fi

        check_halted_vfxt
        sleep 5
    done

    echo "cloud trace enabled"
}

function disable_cloud_trace() {
    ipaddress=$1
    echo "trying to disable cloud trace "

    while :
    do
        # retry forever until we reach the mgmt ip or the vfxt.log stops
        if sendRPC $ipaddress $RPC_DISABLE ; then
            echo "sendRPC success"
            break
        fi

        check_halted_vfxt
        sleep 5
    done

    echo "cloud trace disabled"
}

function main() {
    echo "wait for vfxt log file to appear"
    wait_vfxt_log

    MGMT_IP=$(wait_management_ip)

    enable_cloud_trace $MGMT_IP

    wait_complete_message

    disable_cloud_trace $MGMT_IP
}

main


#!/bin/bash

# report all lines, and exit on error
set -x
set -e

ARM_TRUE="True"
WAIT_SECONDS=600
AZURE_HOME_DIR=/home/$CONTROLLER_ADMIN_USER_NAME
VFXT_INSTALL_TEMPLATE=$AZURE_HOME_DIR/vfxtinstall
CLOUD_BACKED_TEMPLATE=/create-cloudbacked-cluster
MINIMAL_TEMPLATE=/create-minimal-cluster
VFXT_LOG_FILE=$AZURE_HOME_DIR/vfxt.log
ARM_ENDPOINT=https://management.azure.com/metadata/endpoints?api-version=2017-12-01

function retrycmd_if_failure() {
    set +e
    retries=$1; wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            set -e
            return 1
        else
            sleep $wait_sleep
        fi
    done
    set -e
    echo Executed \"$@\" $i times;
}

function wait_azure_home_dir() {
    counter=0
    while [ ! -d $AZURE_HOME_DIR ]; do
        sleep 1
        counter=$((counter + 1))
        if [ $counter -ge $WAIT_SECONDS ]; then
            echo "directory $AZURE_HOME_DIR not available after waiting $WAIT_SECONDS seconds"
            exit 1
        fi
    done
}

function wait_arm_endpoint() {
    # ensure the arm endpoint is reachable
    # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service#getting-azure-environment-where-the-vm-is-running
    if ! retrycmd_if_failure 24 5 curl -m 5 -o /dev/null $ARM_ENDPOINT ; then
        echo "no internet! arm endpoint $ARM_ENDPOINT not reachable.  Please see https://github.com/Azure/Avere/tree/main/src/vfxt#internet-access on how to configure firewall, dns, or proxy."
        exit 1
    fi
}

function wait_az_login_and_vnet() {
    # wait for RBAC assignments to be applied
    # unfortunately, the RBAC assignments take undetermined time past their associated resource completions to be assigned.
    if ! retrycmd_if_failure 120 5 az login --identity ; then
        echo "MANAGED IDENTITY FAILURE: failed to login after waiting 10 minutes, this is managed identity bug"
        exit 1
    fi
    if ! retrycmd_if_failure 12 5 az account set --subscription $SUBSCRIPTION_ID ; then
        echo "MANAGED IDENTITY FAILURE: failed to set subscription"
        exit 1
    fi
    if ! retrycmd_if_failure 120 5 az network vnet subnet list -g $NETWORK_RESOURCE_GROUP --vnet-name $NETWORK ; then
        echo "RBAC ASSIGNMENT FAILURE: failed to list vnet after waiting 10 minutes, this is rbac assignment bug"
        exit 1
    fi
}

function configure_vfxt_template() {
    if [ "$CREATE_CLOUD_BACKED_CLUSTER" == "$ARM_TRUE" ]; then
        cp $CLOUD_BACKED_TEMPLATE $VFXT_INSTALL_TEMPLATE
    else
        cp $MINIMAL_TEMPLATE $VFXT_INSTALL_TEMPLATE
    fi

    # update the internal variables
    sed -i 's/^RESOURCE_GROUP/#RESOURCE_GROUP/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^LOCATION/#LOCATION/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^NETWORK/#NETWORK/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^SUBNET/#SUBNET/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^AVERE_CLUSTER_ROLE/#AVERE_CLUSTER_ROLE/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^STORAGE_ACCOUNT/#STORAGE_ACCOUNT/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^CACHE_SIZE/#CACHE_SIZE/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^CLUSTER_NAME/#CLUSTER_NAME/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^ADMIN_PASSWORD/#ADMIN_PASSWORD/g' $VFXT_INSTALL_TEMPLATE
    sed -i 's/^INSTANCE_TYPE/#INSTANCE_TYPE/g' $VFXT_INSTALL_TEMPLATE
    # replace "--from-environment" with "--on-instance" since we are using
    sed -i 's/ --from-environment / --on-instance /g' $VFXT_INSTALL_TEMPLATE
    sed -i "s:~/vfxt.log:$VFXT_LOG_FILE:g"  $VFXT_INSTALL_TEMPLATE
    # do not trace password in log, instead the command is captured in file ~/create_cluster_command.log, with password correctly redacted
    sed -i "s/^set -exu/set -eu/g"  $VFXT_INSTALL_TEMPLATE
}

function create_vfxt() {
    #######################################################
    # do not trace passwords
    #######################################################
    set -x
    #######################################################

    cd $AZURE_HOME_DIR
    # enable cloud trace during installation
    if [ "${ENABLE_CLOUD_TRACE_DEBUG}" == "${ARM_TRUE}" ] ; then
        nohup /bin/bash /opt/avere/enablecloudtrace.sh > $AZURE_HOME_DIR/enablecloudtrace.log 2>&1 &
    fi
    # ensure the create cluster command is recorded for the future
    sleep 2 && ps -a -x -o cmd | egrep '[v]fxt.py' |  sed 's/--admin-password [^ ]*/--admin-password ***/' > create_cluster_command.log &
    $VFXT_INSTALL_TEMPLATE

    #######################################################
    # re-enable tracing
    #######################################################
    set +x
    #######################################################
}

function print_vfxt_vars() {
    echo "VSERVER_IPS=$(sed -n "s/^.*Creating vserver vserver (\(.*\)\/255.255.255.255).*$/\1/p" $VFXT_LOG_FILE)"
    echo "MGMT_IP=$(sed -n "s/^.*management address: \(.*\)/\1/p" $VFXT_LOG_FILE)"
}

function dump_env_vars() {
    echo "start env dump"
    echo $(pwd)
    echo "export RESOURCE_GROUP=$RESOURCE_GROUP"
    echo "export LOCATION=$LOCATION"
    echo "export NETWORK_RESOURCE_GROUP=$NETWORK_RESOURCE_GROUP"
    echo "export NETWORK=$NETWORK"
    echo "export SUBNET=$SUBNET"
    echo "export AVERE_CLUSTER_ROLE=$AVERE_CLUSTER_ROLE"
    echo "export CREATE_CLOUD_BACKED_CLUSTER=$CREATE_CLOUD_BACKED_CLUSTER"
    echo "export STORAGE_ACCOUNT=$STORAGE_ACCOUNT"
    echo "export CACHE_SIZE=$CACHE_SIZE"
    echo "export CLUSTER_NAME=$CLUSTER_NAME"
    echo "export INSTANCE_TYPE=$INSTANCE_TYPE"
    echo "export ADMIN_PASSWORD=$ADMIN_PASSWORD"
    echo "finish env dump"
}

function apt_get_update() {
    set +e
    retries=10
    apt_update_output=/tmp/apt-get-update.out
    for i in $(seq 1 $retries); do
        timeout 300 apt-get update 2>&1
        [ $? -eq 0  ] && break
        if [ $i -eq $retries ]; then
            set -e
            return 1
        else sleep 30
        fi
    done
    set +e
    echo Executed apt-get update $i times
}

function apt_get_install() {
    set +e
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        # timeout occasionally freezes
        #echo "timeout $timeout apt-get install --no-install-recommends -y ${@}"
        #timeout $timeout apt-get install --no-install-recommends -y ${@}
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            set -e
            return 1
        else
            sleep $wait_sleep
            apt_get_update
        fi
    done
    set -e
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function main() {
    # ensure waagent upgrade does not interrupt this CSE
    retrycmd_if_failure 240 5 apt-mark hold walinuxagent

    echo "wait arm endpoint"
    wait_arm_endpoint

    echo "wait azure home dir"
    wait_azure_home_dir

    echo "wait az login"
    wait_az_login_and_vnet

    #echo "dump env vars for debugging"
    #dump_env_vars

    echo "configure vfxt install template"
    configure_vfxt_template

    echo "create_vfxt"
    create_vfxt

    echo "print vfxt vars"
    print_vfxt_vars

    # ensure waagent upgrade can proceed
    retrycmd_if_failure 300 15 apt-mark unhold walinuxagent

    echo "installation complete"
}

main


#!/bin/bash

NODE_MOUNT_PREFIX="/node"

function retrycmd_if_failure() {
    retries=$1; max_wait_sleep=$2; shift && shift
    for i in $(seq 1 $retries); do
        ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            echo Executed \"$@\" $i times;
            return 1
        else
            sleep $(($RANDOM % $max_wait_sleep))
        fi
    done
    echo Executed \"$@\" $i times;
}

function apt_get_update() {
    retries=10
    apt_update_output=/tmp/apt-get-update.out
    for i in $(seq 1 $retries); do
        timeout 120 apt-get update 2>&1 | tee $apt_update_output | grep -E "^([WE]:.*)|([eE]rr.*)$"
        [ $? -ne 0  ] && cat $apt_update_output && break || \
        cat $apt_update_output
        if [ $i -eq $retries ]; then
            return 1
        else sleep 30
        fi
    done
    echo Executed apt-get update $i times
}

function apt_get_install() {
    retries=$1; wait_sleep=$2; timeout=$3; shift && shift && shift
    for i in $(seq 1 $retries); do
        apt-get install --no-install-recommends -y ${@}
        [ $? -eq 0  ] && break || \
        if [ $i -eq $retries ]; then
            return 1
        else
            sleep $wait_sleep
            apt_get_update
        fi
    done
    echo "completed"
    echo Executed apt-get install --no-install-recommends -y \"$@\" $i times;
}

function config_linux() {
    export DEBIAN_FRONTEND=noninteractive
    apt_get_update
    apt_get_install 20 10 180 default-jre zip csh unzip
}

function mount_avere() {
    COUNTER=0
    for VFXT in $(echo $NFS_IP_CSV | sed "s/,/ /g")
    do
        MOUNT_POINT="${BASE_DIR}${NODE_MOUNT_PREFIX}${COUNTER}"
        echo "Mounting to ${VFXT}:${NFS_PATH} to ${MOUNT_POINT}"
        mkdir -p $MOUNT_POINT
        # no need to write again if it is already there
        if grep -F --quiet "${VFXT}:${NFS_PATH}    ${MOUNT_POINT}" /etc/fstab; then
            echo "not updating file, already there"
        else
            echo "${VFXT}:${NFS_PATH}    ${MOUNT_POINT}    nfs hard,nointr,proto=tcp,mountproto=tcp,retry=30 0 0" >> /etc/fstab
            mount ${MOUNT_POINT}
        fi
        COUNTER=$(($COUNTER + 1))
    done
}

function setup_staf_server() {
    # Install Docker and Blobfuse.
    wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
    sudo dpkg -i packages-microsoft-prod.deb
    sudo apt update
    sudo apt install docker.io blobfuse -y

    # Configure blobfuse.
    sudo mkdir /mnt/resource/blobfusetmp -p
    sudo chown $LINUX_USER /mnt/resource/blobfusetmp
    mkdir -p blobmnt
    echo "accountName <pipelines_sa>"         >  fuse_connection.cfg
    echo "accountKey <pipelines_sa_key>"      >> fuse_connection.cfg
    echo "containerName vfxt-pipelines-blob"  >> fuse_connection.cfg
    chmod 600 fuse_connection.cfg

    # Mount the Azure blob to blobmnt.
    blobfuse blobmnt \
        --tmp-path=/mnt/resource/blobfusetmp \
        --config-file=fuse_connection.cfg \
        --file-cache-timeout-in-seconds=0 \
        -o attr_timeout=240 \
        -o entry_timeout=240 \
        -o negative_timeout=120

    # Copy Azure blob contents.
    cp -r blobmnt/docker-staf .

    # Unmount the Azure blob and clean up.
    sudo umount blobmnt
    sudo rm -r blobmnt /mnt/resource/blobfusetmp

    # Build Docker STAF image.
    sudo docker build -t azpipelines/staf docker-staf/.

    # Run Docker STAF image.
    sudo docker run -d -p 6500:6500 -p 6550:6550 -t azpipelines/staf
}

function setup_sv_virtualenv() {
    # Install Ansible.
    sudo apt install ansible -y

    # Clone Avre-ansible and Avere-sv repos.
    GIT_USERNAME="<git_username>"
    GIT_PASSWORD="<git_password>"
    git clone https://${GIT_USERNAME}:${GIT_PASSWORD}@msazure.visualstudio.com/DefaultCollection/One/_git/Avere-ansible
    git clone https://${GIT_USERNAME}:${GIT_PASSWORD}@msazure.visualstudio.com/DefaultCollection/One/_git/Avere-sv

    # Copy requirements.txt (needed for Ansible playbooks).
    cp Avere-sv/requirements.txt /tmp/requirements.sv
    cp Avere-sv/requirements.txt /tmp/requirements.ats

    # Copy pip.conf to a few places.
    PIP_CONF_FILE=$(find /nfs -name pip.conf -print -quit)
    sudo cp -v $PIP_CONF_FILE /etc/.
    sudo cp -v $PIP_CONF_FILE /etc/default/.

    # Run Ansible playbooks.
    ansible-playbook Avere-ansible/ansible/ats_venv/ats_venv.yml
    ansible-playbook Avere-ansible/ansible/sv_venv/sv_venv.yml

    # Set ownership of $LINUX_USER's homedir and make Python dir writeable.
    chown -R $LINUX_USER /home/$LINUX_USER
    chmod -R 777 /usr/sv/env/lib/python2.7

    # Virtual env setup.
    cd Avere-sv
    source /usr/sv/env/bin/activate
    export PYTHONPATH=~/Avere-sv:~/Avere-sv/averesv:$PYTHONPATH:$PATH
    python setup.py develop
    cd ..
}

function setup_staf_client() {
    # Install Blobfuse.
    wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
    sudo dpkg -i packages-microsoft-prod.deb
    sudo apt update
    sudo apt install blobfuse -y

    # Configure blobfuse.
    sudo mkdir /mnt/resource/blobfusetmp -p
    sudo chown $LINUX_USER /mnt/resource/blobfusetmp
    mkdir -p blobmnt
    echo "accountName <pipelines_sa>"         >  fuse_connection.cfg
    echo "accountKey <pipelines_sa_key>"      >> fuse_connection.cfg
    echo "containerName vfxt-pipelines-blob"  >> fuse_connection.cfg
    chmod 600 fuse_connection.cfg

    # Mount the Azure blob to blobmnt.
    blobfuse blobmnt \
        --tmp-path=/mnt/resource/blobfusetmp \
        --config-file=fuse_connection.cfg \
        --file-cache-timeout-in-seconds=0 \
        -o attr_timeout=240 \
        -o entry_timeout=240 \
        -o negative_timeout=120

    # Copy Azure blob contents (STAF tarball).
    cp blobmnt/STAF*.tar.gz /tmp

    # Unmount the Azure blob and clean up.
    sudo umount blobmnt
    sudo rm -r blobmnt /mnt/resource/blobfusetmp

    # Run Ansible playbook.
    ansible-playbook Avere-ansible/ansible/staf/staf.yml

    # Set STAF envars to load on login.
    sudo sed -i '1isource /usr/local/staf/STAFEnv.sh' ~/.bashrc
}

function main() {
    echo "STEP: config_linux"
    config_linux

    echo "STEP: mount_avere"
    mount_avere

    # $HOME isn't set at this point in the VM's lifecycle. Set it and go there.
    ORIG_DIR=$(pwd)
    export HOME=/home/$LINUX_USER
    cd $HOME

    set -e
    if [ "$REG_CLIENT_TYPE" == "SERVER" ]; then
        echo "STEP: setup_staf_server"
        setup_staf_server
    fi

    echo "STEP: setup_sv_virtualenv"
    setup_sv_virtualenv

    if [ "$REG_CLIENT_TYPE" == "CLIENT" ]; then
        echo "STEP: setup_staf_client"
        setup_staf_client
    fi

    # Set ownership of $LINUX_USER's homedir and make Python dir writeable.
    chown -R $LINUX_USER /home/$LINUX_USER

    set +e

    cd $ORIG_DIR

    echo "DONE: installation complete"
}

main


#!/bin/bash
# Copyright (C) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE-CODE in the project root for license information.

# Simple file operations check for a vFXT controller that has mounted three
# vFXT nodes. These checks do operations such as writing a file in one mount,
# then checking to see if a different mount sees the file, etc.

set -e
set -x

TOP_DIR_PFX="/nfs/node"

DIR0=${TOP_DIR_PFX}0
DIR1=${TOP_DIR_PFX}1
DIR2=${TOP_DIR_PFX}2

SUBDIRS='lvl_1/lvl.2/lvl-3'
FILE1='file01.txt'
FILE2='file02.md'

# Operations on node0's mount.
cd $DIR0
rm -rf $SUBDIRS || true
mkdir -p $SUBDIRS
cd $SUBDIRS
pwd
dd if=/dev/urandom of=$FILE1 bs=1024 count=512
ls -l $FILE1

# Operations on node1's mount.
mv $FILE1 $DIR1/$SUBDIRS/..
cd $DIR1/$SUBDIRS/..
pwd
ls -l $FILE1
mv $FILE1 $FILE2
ls -l $FILE2
dd if=/dev/urandom of=$FILE2 bs=1024 count=1024
ls -l $FILE2
cp $FILE2 $DIR2/$SUBDIRS
diff $FILE2 $DIR2/$SUBDIRS

# Operations on node2's mount.
cd $DIR2/$SUBDIRS/..
pwd
ls
ls -l $FILE2
cp $FILE2 $FILE1
ls -l $FILE1
chmod -r $FILE2
[[ ! -r $FILE2 ]]
rm $FILE2
[[ ! -e $FILE2 ]]

# Cleanup.
cd $DIR0
rm -rf $SUBDIRS
[[ ! -e $SUBDIRS ]]


#!/bin/bash
# Copyright (C) Microsoft Corporation. All rights reserved.
#
# Evaluate if a given exit code indicates success (0) or failure.
#
# If failure, output an error message in Azure DevOps Pipelines format.
# Additionally, output the "current task failed" Pipelines string.
#
# PARAMETERS:
#   This script takes two positional parameters:
#     $1: exit code to evaluate (usually called as $?)
#     $2: a string describing the activity whose exit code is being checked
#
# SAMPLE USAGE:
#   * Check the previous command.
#     check_rc.sh $? "resource group creation"
#   * Check the previous command and exit if failed.
#     check_rc.sh $? "resource group creation" || exit 1
#   * Check the previous command. If failed, tag the build and exit.
#     check_rc.sh $? "resource group creation" || (echo "##vso[build.addbuildtag]FAIL RG_create" && exit 1)

if [ "$#" -lt 2 ]; then
    >&2 echo "ERROR: At least two positional parameters are required."
    cat <<EOI
    USAGE: $0 <rc> <activity_msg>
        <rc>: The return (exit) code being checked.
        <activity_msg>: The activity being tested (e.g., "resource group creation")
EOI
    exit 1
fi

rc=$1
shift
activity=$*

nowstr="[$(date -u '+%F %T %Z')]"
if [ "${rc}" -ne 0 ]; then
    >&2 echo "${nowstr}: ERROR: FAILED: ${activity}."
    echo "##vso[task.logissue type=error;]FAILED: ${activity}. See log for details."
    echo "##vso[task.complete result=Failed;]"
    exit ${rc}
else
    echo "${nowstr}: INFO: SUCCESS: ${activity}."
fi


#!/bin/bash
set -e
ANSIBLE_VERSION_UBUNTU=5.8.0
ANSIBLE_VERSION_CENTOS=4.10.0

os_release=$(cat /etc/os-release | grep "^ID\=" | cut -d'=' -f 2 | xargs)
os_release=${os_release^^}

THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

if [[ `pip3 list pypsrp` == *"pypsrp"* ]]; then
  echo pypsrp is already installed
else
  pip3 install pypsrp
fi
if [[ `pip3 list PySocks` == *"PySocks"* ]]; then
  echo PySocks is already installed
else
  pip3 install PySocks
fi
if [[ `pip3 list netaddr` == *"netaddr"* ]]; then
  echo netaddr is already installed
else
  pip3 install netaddr
fi

ansible-galaxy collection install ansible.windows
ansible-galaxy collection install community.windows
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general

# This is to fix an issue when using delegate_to
if [ -f /usr/bin/python3 ] && [ ! -f /usr/bin/python ]; then
  sudo ln --symbolic /usr/bin/python3 /usr/bin/python;
fi

# Test if the ood-ansible repo has been pulled
OOD_ANSIBLE=$THIS_DIR/playbooks/roles/ood-ansible
if [ "$(ls -A $OOD_ANSIBLE)" ]; then
     echo "OOD Ansible playbook has been pulled"
else
    echo "$OOD_ANSIBLE is empty. Please git clone this repo using the --recursive option or run 'git submodule init && git submodule update'"
    exit 1
fi

ansible --version
pip3 list | grep ansible
version=$(pip3 list | grep ansible | sort | head -n 1 | xargs | cut -d' ' -f 2)
ANSIBLE_VERSION="ANSIBLE_VERSION_$os_release"
if [ "$version" != ${!ANSIBLE_VERSION} ]; then
  echo "Ansible version is ${!ANSIBLE_VERSION}. Please run ./toolset/scripts/install.sh to install the correct version of Ansible"
  exit 1
fi