2019-09-19 14:08:23 -07:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
# |source| this file
|
|
|
|
#
|
|
|
|
# Utilities for working with Colo instances
|
|
|
|
#
|
|
|
|
|
2019-11-08 15:41:36 -08:00
|
|
|
# COLO_PARALLELIZE is not ready for use, disable it
|
|
|
|
declare COLO_PARALLELIZE=false
|
2019-09-19 14:08:23 -07:00
|
|
|
|
|
|
|
__cloud_colo_here="$(dirname "${BASH_SOURCE[0]}")"
|
|
|
|
# shellcheck source=net/scripts/colo-utils.sh
|
|
|
|
source "${__cloud_colo_here}/colo-utils.sh"
|
|
|
|
|
|
|
|
# Default zone
|
|
|
|
cloud_DefaultZone() {
|
|
|
|
echo "Denver"
|
|
|
|
}
|
|
|
|
|
2021-01-05 20:26:49 -08:00
|
|
|
cloud_DefaultCustomMemoryGB() {
|
|
|
|
: # Not implemented
|
|
|
|
}
|
|
|
|
|
2019-10-14 23:11:29 -07:00
|
|
|
cloud_RestartPreemptedInstances() {
|
|
|
|
: # Not implemented
|
|
|
|
}
|
|
|
|
|
2019-09-19 14:08:23 -07:00
|
|
|
#
|
|
|
|
# __cloud_FindInstances
|
|
|
|
#
|
|
|
|
# Find instances matching the specified pattern.
|
|
|
|
#
|
|
|
|
# For each matching instance, an entry in the `instances` array will be added with the
|
|
|
|
# following information about the instance:
|
|
|
|
# "name:zone:public IP:private IP"
|
|
|
|
#
|
|
|
|
# filter - The instances to filter on
|
|
|
|
#
|
|
|
|
# examples:
|
|
|
|
# $ __cloud_FindInstances "name=exact-machine-name"
|
|
|
|
# $ __cloud_FindInstances "name~^all-machines-with-a-common-machine-prefix"
|
|
|
|
#
|
|
|
|
__cloud_FindInstances() {
|
|
|
|
declare HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME INSTANCES_TEXT
|
2019-11-25 09:32:17 -08:00
|
|
|
declare filter=${1}
|
2020-03-10 11:25:44 -07:00
|
|
|
declare onlyPreemptible=${2}
|
2019-09-19 14:08:23 -07:00
|
|
|
instances=()
|
|
|
|
|
2019-11-25 09:32:17 -08:00
|
|
|
if ! ${COLO_PARALLELIZE}; then
|
2019-09-19 14:08:23 -07:00
|
|
|
colo_load_resources
|
|
|
|
colo_load_availability false
|
|
|
|
fi
|
|
|
|
INSTANCES_TEXT="$(
|
|
|
|
for AVAIL in "${COLO_RES_AVAILABILITY[@]}"; do
|
2020-03-26 23:01:42 -07:00
|
|
|
IFS=$'\x1f' read -r HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME PREEMPTIBLE <<<"${AVAIL}"
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ ${INSTNAME} =~ ${filter} ]]; then
|
2020-03-10 11:25:44 -07:00
|
|
|
if [[ -n $onlyPreemptible && $PREEMPTIBLE == "false" ]]; then
|
|
|
|
continue
|
|
|
|
else
|
|
|
|
printf "%-40s | publicIp=%-16s privateIp=%s zone=%s preemptible=%s\n" "${INSTNAME}" "${IP}" "${PRIV_IP}" "${ZONE}" "${PREEMPTIBLE}" 1>&2
|
|
|
|
echo -e "${INSTNAME}:${IP}:${PRIV_IP}:${ZONE}"
|
|
|
|
fi
|
2019-09-19 14:08:23 -07:00
|
|
|
fi
|
2020-03-26 23:01:42 -07:00
|
|
|
done | sort -t $'\x1f' -k1
|
2019-09-19 14:08:23 -07:00
|
|
|
)"
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ -n "${INSTANCES_TEXT}" ]]; then
|
2019-09-19 14:08:23 -07:00
|
|
|
while read -r LINE; do
|
2019-11-25 09:32:17 -08:00
|
|
|
instances+=( "${LINE}" )
|
|
|
|
done <<<"${INSTANCES_TEXT}"
|
2019-09-19 14:08:23 -07:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_FindInstances [namePrefix]
|
|
|
|
#
|
|
|
|
# Find instances with names matching the specified prefix
|
|
|
|
#
|
|
|
|
# For each matching instance, an entry in the `instances` array will be added with the
|
|
|
|
# following information about the instance:
|
|
|
|
# "name:public IP:private IP"
|
|
|
|
#
|
|
|
|
# namePrefix - The instance name prefix to look for
|
|
|
|
#
|
|
|
|
# examples:
|
|
|
|
# $ cloud_FindInstances all-machines-with-a-common-machine-prefix
|
|
|
|
#
|
|
|
|
cloud_FindInstances() {
|
|
|
|
declare filter="^${1}.*"
|
2020-03-10 11:25:44 -07:00
|
|
|
declare onlyPreemptible="${2}"
|
|
|
|
__cloud_FindInstances "${filter}" "${onlyPreemptible}"
|
2019-09-19 14:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_FindInstance [name]
|
|
|
|
#
|
|
|
|
# Find an instance with a name matching the exact pattern.
|
|
|
|
#
|
|
|
|
# For each matching instance, an entry in the `instances` array will be added with the
|
|
|
|
# following information about the instance:
|
|
|
|
# "name:public IP:private IP"
|
|
|
|
#
|
|
|
|
# name - The instance name to look for
|
|
|
|
#
|
|
|
|
# examples:
|
|
|
|
# $ cloud_FindInstance exact-machine-name
|
|
|
|
#
|
|
|
|
cloud_FindInstance() {
|
|
|
|
declare name="^${1}$"
|
2020-03-10 11:25:44 -07:00
|
|
|
declare onlyPreemptible="${2}"
|
|
|
|
__cloud_FindInstances "${name}" "${onlyPreemptible}"
|
2019-09-19 14:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_Initialize [networkName]
|
|
|
|
#
|
|
|
|
# Perform one-time initialization that may be required for the given testnet.
|
|
|
|
#
|
|
|
|
# networkName - unique name of this testnet
|
|
|
|
#
|
|
|
|
# This function will be called before |cloud_CreateInstances|
|
|
|
|
cloud_Initialize() {
|
2019-11-25 09:32:17 -08:00
|
|
|
# networkName=${1} # unused
|
|
|
|
# zone=${2} #unused
|
2019-09-19 14:08:23 -07:00
|
|
|
colo_load_resources
|
2019-11-25 09:32:17 -08:00
|
|
|
if ${COLO_PARALLELIZE}; then
|
2019-09-19 14:08:23 -07:00
|
|
|
colo_load_availability
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
2022-05-27 09:34:41 -07:00
|
|
|
# cloud_CreateInstances [networkName] [namePrefix] [numNodes]
|
|
|
|
# [enableGpu] [machineType] [zone]
|
|
|
|
# [bootDiskSize] [startupScript] [address]
|
|
|
|
# [bootDiskType] [additionalDiskSize] [preemptible]
|
2019-09-19 14:08:23 -07:00
|
|
|
#
|
|
|
|
# Creates one more identical instances.
|
|
|
|
#
|
|
|
|
# networkName - unique name of this testnet
|
|
|
|
# namePrefix - unique string to prefix all the instance names with
|
|
|
|
# numNodes - number of instances to create
|
2022-05-27 09:34:41 -07:00
|
|
|
# enableGpu - Optionally enable GPU, use the value "true" to enable
|
|
|
|
# eg, request 4 K80 GPUs with "count=4,type=nvidia-tesla-k80"
|
2019-09-19 14:08:23 -07:00
|
|
|
# machineType - GCE machine type. Note that this may also include an
|
|
|
|
# `--accelerator=` or other |gcloud compute instances create|
|
|
|
|
# options
|
2022-05-27 09:34:41 -07:00
|
|
|
# zone - cloud zone
|
2019-09-19 14:08:23 -07:00
|
|
|
# bootDiskSize - Optional size of the boot disk in GB
|
|
|
|
# startupScript - Optional startup script to execute when the instance boots
|
|
|
|
# address - Optional name of the GCE static IP address to attach to the
|
|
|
|
# instance. Requires that |numNodes| = 1 and that addressName
|
2022-05-27 09:34:41 -07:00
|
|
|
# has been provisioned in the GCE region that is hosting `$zone`
|
2019-09-19 14:08:23 -07:00
|
|
|
# bootDiskType - Optional specify SSD or HDD boot disk
|
|
|
|
# additionalDiskSize - Optional specify size of additional storage volume
|
2022-05-27 09:34:41 -07:00
|
|
|
# preemptible - Optionally request a preemptible instance ("true")
|
2019-09-19 14:08:23 -07:00
|
|
|
#
|
|
|
|
# Tip: use cloud_FindInstances to locate the instances once this function
|
|
|
|
# returns
|
|
|
|
cloud_CreateInstances() {
|
2019-11-25 09:32:17 -08:00
|
|
|
#declare networkName="${1}" # unused
|
|
|
|
declare namePrefix="${2}"
|
|
|
|
declare numNodes="${3}"
|
|
|
|
#declare enableGpu="${4}" # unused
|
|
|
|
declare machineType="${5}"
|
|
|
|
# declare zone="${6}" # unused
|
|
|
|
#declare optionalBootDiskSize="${7}" # unused
|
|
|
|
#declare optionalStartupScript="${8}" # unused
|
|
|
|
#declare optionalAddress="${9}" # unused
|
2019-09-19 14:08:23 -07:00
|
|
|
#declare optionalBootDiskType="${10}" # unused
|
|
|
|
#declare optionalAdditionalDiskSize="${11}" # unused
|
2020-03-10 11:25:44 -07:00
|
|
|
declare optionalPreemptible="${12}"
|
2019-10-14 23:11:29 -07:00
|
|
|
declare sshPrivateKey="${13}"
|
2019-09-19 14:08:23 -07:00
|
|
|
|
|
|
|
declare -a nodes
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ ${numNodes} = 1 ]]; then
|
|
|
|
nodes=("${namePrefix}")
|
2019-09-19 14:08:23 -07:00
|
|
|
else
|
2019-11-25 09:32:17 -08:00
|
|
|
for node in $(seq -f "${namePrefix}%0${#numNodes}g" 1 "${numNodes}"); do
|
|
|
|
nodes+=("${node}")
|
2019-09-19 14:08:23 -07:00
|
|
|
done
|
|
|
|
fi
|
|
|
|
|
2019-11-25 09:32:17 -08:00
|
|
|
if ${COLO_PARALLELIZE}; then
|
2019-09-19 14:08:23 -07:00
|
|
|
declare HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME INDEX RES LINE
|
|
|
|
declare -a AVAILABLE
|
|
|
|
declare AVAILABLE_TEXT
|
|
|
|
AVAILABLE_TEXT="$(
|
|
|
|
for RES in "${COLO_RES_AVAILABILITY[@]}"; do
|
2020-03-26 23:01:42 -07:00
|
|
|
IFS=$'\x1f' read -r HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME <<<"${RES}"
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ "FREE" = "${STATUS}" ]]; then
|
|
|
|
INDEX=$(colo_res_index_from_ip "${IP}")
|
|
|
|
RES_MACH="${COLO_RES_MACHINE[${INDEX}]}"
|
|
|
|
if colo_machine_types_compatible "${RES_MACH}" "${machineType}"; then
|
|
|
|
if ! colo_node_is_requisitioned "${INDEX}" "${COLO_RES_REQUISITIONED[*]}"; then
|
2020-03-26 23:01:42 -07:00
|
|
|
echo -e "${RES_MACH}\x1f${IP}"
|
2019-09-19 14:08:23 -07:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
2020-03-26 23:01:42 -07:00
|
|
|
done | sort -nt $'\x1f' -k1,1
|
2019-09-19 14:08:23 -07:00
|
|
|
)"
|
|
|
|
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ -n "${AVAILABLE_TEXT}" ]]; then
|
2019-09-19 14:08:23 -07:00
|
|
|
while read -r LINE; do
|
2019-11-25 09:32:17 -08:00
|
|
|
AVAILABLE+=("${LINE}")
|
|
|
|
done <<<"${AVAILABLE_TEXT}"
|
2019-09-19 14:08:23 -07:00
|
|
|
fi
|
|
|
|
|
2019-11-25 09:32:17 -08:00
|
|
|
if [[ ${#AVAILABLE[@]} -lt ${numNodes} ]]; then
|
|
|
|
echo "Insufficient resources available to allocate ${numNodes} ${namePrefix}" 1>&2
|
2019-09-19 14:08:23 -07:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
declare node
|
|
|
|
declare AI=0
|
|
|
|
for node in "${nodes[@]}"; do
|
2020-03-26 23:01:42 -07:00
|
|
|
IFS=$'\x1f' read -r _ IP <<<"${AVAILABLE[${AI}]}"
|
2019-11-25 09:32:17 -08:00
|
|
|
colo_node_requisition "${IP}" "${node}" >/dev/null
|
2019-09-19 14:08:23 -07:00
|
|
|
AI=$((AI+1))
|
|
|
|
done
|
|
|
|
else
|
|
|
|
declare RES_MACH node
|
|
|
|
declare RI=0
|
|
|
|
declare NI=0
|
2019-11-25 09:32:17 -08:00
|
|
|
while [[ ${NI} -lt ${numNodes} && ${RI} -lt ${COLO_RES_N} ]]; do
|
|
|
|
node="${nodes[${NI}]}"
|
|
|
|
RES_MACH="${COLO_RES_MACHINE[${RI}]}"
|
|
|
|
IP="${COLO_RES_IP[${RI}]}"
|
|
|
|
if colo_machine_types_compatible "${RES_MACH}" "${machineType}"; then
|
2020-03-10 11:25:44 -07:00
|
|
|
if colo_node_requisition "${IP}" "${node}" "${sshPrivateKey}" "${optionalPreemptible}" >/dev/null; then
|
2019-09-19 14:08:23 -07:00
|
|
|
NI=$((NI+1))
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
RI=$((RI+1))
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_DeleteInstances
|
|
|
|
#
|
|
|
|
# Deletes all the instances listed in the `instances` array
|
|
|
|
#
|
|
|
|
cloud_DeleteInstances() {
|
2020-03-10 11:25:44 -07:00
|
|
|
declare forceDelete="${1}"
|
2019-09-19 14:08:23 -07:00
|
|
|
declare _ IP _ _
|
|
|
|
for instance in "${instances[@]}"; do
|
2019-11-25 09:32:17 -08:00
|
|
|
IFS=':' read -r _ IP _ _ <<< "${instance}"
|
2020-03-10 11:25:44 -07:00
|
|
|
colo_node_free "${IP}" "${forceDelete}" >/dev/null
|
2019-09-19 14:08:23 -07:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_WaitForInstanceReady [instanceName] [instanceIp] [instanceZone] [timeout]
|
|
|
|
#
|
|
|
|
# Return once the newly created VM instance is responding. This function is cloud-provider specific.
|
|
|
|
#
|
|
|
|
cloud_WaitForInstanceReady() {
|
2019-11-25 09:32:17 -08:00
|
|
|
#declare instanceName="${1}" # unused
|
|
|
|
#declare instanceIp="${2}" # unused
|
|
|
|
#declare timeout="${4}" # unused
|
2019-09-19 14:08:23 -07:00
|
|
|
|
2019-10-09 15:17:24 -07:00
|
|
|
true
|
2019-09-19 14:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_FetchFile [instanceName] [publicIp] [remoteFile] [localFile]
|
|
|
|
#
|
|
|
|
# Fetch a file from the given instance. This function uses a cloud-specific
|
|
|
|
# mechanism to fetch the file
|
|
|
|
#
|
|
|
|
cloud_FetchFile() {
|
2019-11-25 09:32:17 -08:00
|
|
|
#declare instanceName="${1}" # unused
|
|
|
|
declare publicIp="${2}"
|
|
|
|
declare remoteFile="${3}"
|
|
|
|
declare localFile="${4}"
|
|
|
|
#declare zone="${5}" # unused
|
2019-09-19 14:08:23 -07:00
|
|
|
scp \
|
|
|
|
-o "StrictHostKeyChecking=no" \
|
|
|
|
-o "UserKnownHostsFile=/dev/null" \
|
|
|
|
-o "User=solana" \
|
|
|
|
-o "LogLevel=ERROR" \
|
|
|
|
-F /dev/null \
|
2019-11-25 09:32:17 -08:00
|
|
|
"solana@${publicIp}:${remoteFile}" "${localFile}"
|
2019-09-19 14:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
cloud_StatusAll() {
|
2020-03-10 11:25:44 -07:00
|
|
|
declare HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME PREEMPTIBLE
|
2019-11-25 09:32:17 -08:00
|
|
|
if ! ${COLO_PARALLELIZE}; then
|
2019-09-19 14:08:23 -07:00
|
|
|
colo_load_resources
|
|
|
|
colo_load_availability false
|
|
|
|
fi
|
|
|
|
for AVAIL in "${COLO_RES_AVAILABILITY[@]}"; do
|
2020-03-26 23:01:42 -07:00
|
|
|
IFS=$'\x1f' read -r HOST_NAME IP PRIV_IP STATUS ZONE LOCK_USER INSTNAME PREEMPTIBLE <<<"${AVAIL}"
|
2020-03-10 11:25:44 -07:00
|
|
|
printf "%-30s | publicIp=%-16s privateIp=%s status=%s who=%s zone=%s inst=%s preemptible=%s\n" "${HOST_NAME}" "${IP}" "${PRIV_IP}" "${STATUS}" "${LOCK_USER}" "${ZONE}" "${INSTNAME}" "${PREEMPTIBLE}"
|
2019-09-19 14:08:23 -07:00
|
|
|
done
|
|
|
|
}
|