2018-09-16 14:46:08 -07:00
|
|
|
# |source| this file
|
|
|
|
#
|
|
|
|
# Utilities for working with GCE instances
|
|
|
|
#
|
|
|
|
|
|
|
|
# Default zone
|
2019-03-27 15:19:55 -07:00
|
|
|
cloud_DefaultZone() {
|
|
|
|
echo "us-west1-b"
|
2018-09-16 14:46:08 -07:00
|
|
|
}
|
|
|
|
|
2021-01-05 20:26:49 -08:00
|
|
|
cloud_DefaultCustomMemoryGB() {
|
|
|
|
echo 64
|
|
|
|
}
|
|
|
|
|
2019-10-14 23:11:29 -07:00
|
|
|
#
|
|
|
|
# cloud_RestartPreemptedInstances [namePrefix]
|
|
|
|
#
|
|
|
|
# Restart any preempted instances matching the specified prefix
|
|
|
|
#
|
|
|
|
# namePrefix - The instance name prefix of the preempted instances
|
|
|
|
#
|
|
|
|
cloud_RestartPreemptedInstances() {
|
|
|
|
declare filter="$1"
|
|
|
|
|
|
|
|
declare name status zone
|
|
|
|
while read -r name status zone; do
|
|
|
|
echo "Starting $status instance: $name"
|
|
|
|
(
|
|
|
|
set -x
|
|
|
|
gcloud compute instances start --zone "$zone" "$name"
|
|
|
|
)
|
|
|
|
done < <(gcloud compute instances list \
|
|
|
|
--filter "$filter" \
|
|
|
|
--format 'value(name,status,zone)' \
|
|
|
|
| grep TERMINATED)
|
|
|
|
}
|
|
|
|
|
2018-09-16 14:46:08 -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 filter="$1"
|
|
|
|
instances=()
|
|
|
|
|
|
|
|
declare name zone publicIp privateIp status
|
2019-03-27 15:19:55 -07:00
|
|
|
while read -r name publicIp privateIp status zone; do
|
|
|
|
printf "%-30s | publicIp=%-16s privateIp=%s status=%s zone=%s\n" "$name" "$publicIp" "$privateIp" "$status" "$zone"
|
2018-09-16 14:46:08 -07:00
|
|
|
|
2019-03-27 15:19:55 -07:00
|
|
|
instances+=("$name:$publicIp:$privateIp:$zone")
|
2018-09-16 14:46:08 -07:00
|
|
|
done < <(gcloud compute instances list \
|
2018-09-17 08:25:10 -07:00
|
|
|
--filter "$filter" \
|
2019-04-29 21:38:03 -07:00
|
|
|
--format 'value(name,networkInterfaces[0].accessConfigs[0].natIP,networkInterfaces[0].networkIP,status,zone)' \
|
|
|
|
| grep RUNNING)
|
2019-08-12 08:28:58 -07:00
|
|
|
|
|
|
|
while read -r name status zone; do
|
|
|
|
privateIp=TERMINATED
|
|
|
|
publicIp=TERMINATED
|
|
|
|
printf "%-30s | publicIp=%-16s privateIp=%s status=%s zone=%s\n" "$name" "$publicIp" "$privateIp" "$status" "$zone"
|
|
|
|
|
|
|
|
instances+=("$name:$publicIp:$privateIp:$zone")
|
|
|
|
done < <(gcloud compute instances list \
|
|
|
|
--filter "$filter" \
|
|
|
|
--format 'value(name,status,zone)' \
|
|
|
|
| grep TERMINATED)
|
2018-09-16 14:46:08 -07:00
|
|
|
}
|
2019-04-29 21:38:03 -07:00
|
|
|
|
2018-09-16 14:46:08 -07:00
|
|
|
#
|
|
|
|
# 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 namePrefix="$1"
|
|
|
|
__cloud_FindInstances "name~^$namePrefix"
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# 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"
|
|
|
|
__cloud_FindInstances "name=$name"
|
|
|
|
}
|
|
|
|
|
2019-02-18 17:43:03 -08: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() {
|
|
|
|
declare networkName="$1"
|
2019-02-18 17:58:04 -08:00
|
|
|
# ec2-provider.sh creates firewall rules programmatically, should do the same
|
2019-02-18 17:43:03 -08:00
|
|
|
# here.
|
2019-10-21 22:25:06 -07:00
|
|
|
echo "Note: one day create $networkName firewall rules programmatically instead of assuming the 'testnet' tag exists"
|
2019-02-18 17:43:03 -08:00
|
|
|
}
|
|
|
|
|
2018-09-16 14:46:08 -07:00
|
|
|
#
|
2022-05-27 09:34:41 -07:00
|
|
|
# cloud_CreateInstances [networkName] [namePrefix] [numNodes]
|
|
|
|
# [enableGpu] [machineType] [zone]
|
|
|
|
# [bootDiskSize] [startupScript] [address]
|
|
|
|
# [bootDiskType] [additionalDiskSize] [preemptible]
|
2018-09-16 14:46:08 -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"
|
2018-09-17 08:25:10 -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
|
2018-09-16 14:46:08 -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
|
|
|
|
# has been provisioned in the GCE region that is hosting `$zone`
|
2019-09-19 13:28:25 -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")
|
2018-09-16 14:46:08 -07:00
|
|
|
#
|
|
|
|
# Tip: use cloud_FindInstances to locate the instances once this function
|
|
|
|
# returns
|
|
|
|
cloud_CreateInstances() {
|
|
|
|
declare networkName="$1"
|
|
|
|
declare namePrefix="$2"
|
|
|
|
declare numNodes="$3"
|
2019-03-27 15:19:55 -07:00
|
|
|
declare enableGpu="$4"
|
2018-09-16 14:46:08 -07:00
|
|
|
declare machineType="$5"
|
2019-03-27 15:19:55 -07:00
|
|
|
declare zone="$6"
|
|
|
|
declare optionalBootDiskSize="$7"
|
|
|
|
declare optionalStartupScript="$8"
|
|
|
|
declare optionalAddress="$9"
|
2020-12-17 12:49:54 -08:00
|
|
|
declare optionalBootDiskType="${10:-pd-ssd}"
|
2019-07-11 15:23:32 -07:00
|
|
|
declare optionalAdditionalDiskSize="${11}"
|
2019-10-14 23:11:29 -07:00
|
|
|
declare optionalPreemptible="${12}"
|
|
|
|
#declare sshPrivateKey="${13}" # unused
|
2019-03-27 15:19:55 -07:00
|
|
|
|
|
|
|
if $enableGpu; then
|
2021-02-24 16:03:31 -08:00
|
|
|
# Custom Ubuntu 20.04 LTS image with CUDA 10.2 installed
|
2019-03-27 15:19:55 -07:00
|
|
|
#
|
2019-10-21 22:25:06 -07:00
|
|
|
# Unfortunately this image is not public. When this becomes an issue, use
|
2021-02-24 16:03:31 -08:00
|
|
|
# the stock Ubuntu 20.04 image and programmatically install CUDA after the
|
2019-03-27 15:19:55 -07:00
|
|
|
# instance boots
|
|
|
|
#
|
2020-12-17 12:50:21 -08:00
|
|
|
imageName="ubuntu-2004-focal-v20201211-with-cuda-10-2 --image-project principal-lane-200702"
|
2019-03-27 15:19:55 -07:00
|
|
|
else
|
2020-12-17 12:50:21 -08:00
|
|
|
# Upstream Ubuntu 20.04 LTS image
|
2022-06-21 01:27:20 -07:00
|
|
|
imageName="ubuntu-2004-focal-v20220419 --image-project ubuntu-os-cloud"
|
2019-03-27 15:19:55 -07:00
|
|
|
fi
|
2018-09-16 14:46:08 -07:00
|
|
|
|
2018-11-10 17:00:06 -08:00
|
|
|
declare -a nodes
|
2018-09-16 14:46:08 -07:00
|
|
|
if [[ $numNodes = 1 ]]; then
|
|
|
|
nodes=("$namePrefix")
|
|
|
|
else
|
2018-11-10 17:00:06 -08:00
|
|
|
for node in $(seq -f "${namePrefix}%0${#numNodes}g" 1 "$numNodes"); do
|
|
|
|
nodes+=("$node")
|
|
|
|
done
|
2018-09-16 14:46:08 -07:00
|
|
|
fi
|
|
|
|
|
|
|
|
declare -a args
|
|
|
|
args=(
|
2018-09-17 08:25:10 -07:00
|
|
|
--zone "$zone"
|
|
|
|
--tags testnet
|
|
|
|
--metadata "testnet=$networkName"
|
2019-09-18 10:38:38 -07:00
|
|
|
--maintenance-policy TERMINATE
|
|
|
|
--restart-on-failure
|
2019-11-04 10:30:26 -08:00
|
|
|
--scopes compute-rw
|
2018-09-16 14:46:08 -07:00
|
|
|
)
|
2018-09-17 08:25:10 -07:00
|
|
|
|
2018-11-04 19:06:14 -08:00
|
|
|
# shellcheck disable=SC2206 # Do not want to quote $imageName as it may contain extra args
|
|
|
|
args+=(--image $imageName)
|
|
|
|
|
2019-10-14 23:11:29 -07:00
|
|
|
if [[ $optionalPreemptible = true ]]; then
|
|
|
|
args+=(--preemptible)
|
|
|
|
fi
|
|
|
|
|
2018-09-17 08:25:10 -07:00
|
|
|
# shellcheck disable=SC2206 # Do not want to quote $machineType as it may contain extra args
|
2019-05-17 20:06:07 -07:00
|
|
|
for word in $machineType; do
|
|
|
|
# Special handling for the "--min-cpu-platform" argument which may contain a
|
|
|
|
# space (escaped as '%20')...
|
|
|
|
args+=("${word//%20/ }")
|
|
|
|
done
|
2018-09-16 14:46:08 -07:00
|
|
|
if [[ -n $optionalBootDiskSize ]]; then
|
|
|
|
args+=(
|
2018-09-17 08:25:10 -07:00
|
|
|
--boot-disk-size "${optionalBootDiskSize}GB"
|
2018-09-16 14:46:08 -07:00
|
|
|
)
|
|
|
|
fi
|
|
|
|
if [[ -n $optionalStartupScript ]]; then
|
|
|
|
args+=(
|
|
|
|
--metadata-from-file "startup-script=$optionalStartupScript"
|
|
|
|
)
|
|
|
|
fi
|
2018-09-22 16:43:47 -07:00
|
|
|
if [[ -n $optionalBootDiskType ]]; then
|
|
|
|
args+=(
|
|
|
|
--boot-disk-type "${optionalBootDiskType}"
|
|
|
|
)
|
|
|
|
fi
|
2018-09-16 14:46:08 -07:00
|
|
|
|
|
|
|
if [[ -n $optionalAddress ]]; then
|
|
|
|
[[ $numNodes = 1 ]] || {
|
|
|
|
echo "Error: address may not be supplied when provisioning multiple nodes: $optionalAddress"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
args+=(
|
2018-09-17 08:25:10 -07:00
|
|
|
--address "$optionalAddress"
|
2018-09-16 14:46:08 -07:00
|
|
|
)
|
|
|
|
fi
|
|
|
|
|
|
|
|
(
|
|
|
|
set -x
|
|
|
|
gcloud beta compute instances create "${nodes[@]}" "${args[@]}"
|
|
|
|
)
|
2019-07-11 15:23:32 -07:00
|
|
|
|
|
|
|
if [[ -n $optionalAdditionalDiskSize ]]; then
|
|
|
|
if [[ $numNodes = 1 ]]; then
|
|
|
|
(
|
|
|
|
set -x
|
|
|
|
cloud_CreateAndAttachPersistentDisk "${namePrefix}" "$optionalAdditionalDiskSize" "pd-ssd" "$zone"
|
|
|
|
)
|
|
|
|
else
|
|
|
|
for node in $(seq -f "${namePrefix}%0${#numNodes}g" 1 "$numNodes"); do
|
|
|
|
(
|
|
|
|
set -x
|
|
|
|
cloud_CreateAndAttachPersistentDisk "${node}" "$optionalAdditionalDiskSize" "pd-ssd" "$zone"
|
|
|
|
)
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
fi
|
2018-09-16 14:46:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_DeleteInstances
|
|
|
|
#
|
|
|
|
# Deletes all the instances listed in the `instances` array
|
|
|
|
#
|
|
|
|
cloud_DeleteInstances() {
|
|
|
|
if [[ ${#instances[0]} -eq 0 ]]; then
|
|
|
|
echo No instances to delete
|
|
|
|
return
|
|
|
|
fi
|
2019-03-27 15:19:55 -07:00
|
|
|
|
2018-09-16 14:46:08 -07:00
|
|
|
declare names=("${instances[@]/:*/}")
|
2019-03-27 15:19:55 -07:00
|
|
|
declare zones=("${instances[@]/*:/}")
|
2019-04-24 17:50:42 -07:00
|
|
|
declare unique_zones=()
|
|
|
|
read -r -a unique_zones <<< "$(echo "${zones[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')"
|
2018-09-16 14:46:08 -07:00
|
|
|
|
2019-04-24 17:50:42 -07:00
|
|
|
for zone in "${unique_zones[@]}"; do
|
2018-09-16 14:46:08 -07:00
|
|
|
set -x
|
2019-04-18 13:16:14 -07:00
|
|
|
# Try deleting instances in all zones
|
|
|
|
gcloud beta compute instances delete --zone "$zone" --quiet "${names[@]}" || true
|
|
|
|
done
|
2018-09-16 14:46:08 -07:00
|
|
|
}
|
|
|
|
|
2019-04-23 15:41:45 -07:00
|
|
|
#
|
|
|
|
# cloud_WaitForInstanceReady [instanceName] [instanceIp] [instanceZone] [timeout]
|
|
|
|
#
|
|
|
|
# Return once the newly created VM instance is responding. This function is cloud-provider specific.
|
|
|
|
#
|
|
|
|
cloud_WaitForInstanceReady() {
|
|
|
|
declare instanceName="$1"
|
|
|
|
declare instanceIp="$2"
|
|
|
|
# declare instanceZone="$3"
|
|
|
|
declare timeout="$4"
|
|
|
|
|
2019-08-12 08:28:58 -07:00
|
|
|
if [[ $instanceIp = "TERMINATED" ]]; then
|
|
|
|
return 1
|
|
|
|
fi
|
2019-04-23 15:41:45 -07:00
|
|
|
timeout "${timeout}"s bash -c "set -o pipefail; until ping -c 3 $instanceIp | tr - _; do echo .; done"
|
|
|
|
}
|
2018-09-16 14:46:08 -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() {
|
|
|
|
declare instanceName="$1"
|
|
|
|
# shellcheck disable=SC2034 # publicIp is unused
|
|
|
|
declare publicIp="$2"
|
|
|
|
declare remoteFile="$3"
|
|
|
|
declare localFile="$4"
|
2019-03-27 15:19:55 -07:00
|
|
|
declare zone="$5"
|
2018-09-16 14:46:08 -07:00
|
|
|
|
2019-08-12 08:28:58 -07:00
|
|
|
if [[ $publicIp = "TERMINATED" ]]; then
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
2018-09-16 14:46:08 -07:00
|
|
|
(
|
|
|
|
set -x
|
|
|
|
gcloud compute scp --zone "$zone" "$instanceName:$remoteFile" "$localFile"
|
|
|
|
)
|
|
|
|
}
|
2019-07-11 15:23:32 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_CreateAndAttachPersistentDisk [instanceName] [diskSize] [diskType]
|
|
|
|
#
|
|
|
|
# Create a persistent disk and attach it to a pre-existing VM instance.
|
|
|
|
# Set disk to auto-delete upon instance deletion
|
|
|
|
#
|
|
|
|
cloud_CreateAndAttachPersistentDisk() {
|
|
|
|
declare instanceName="$1"
|
|
|
|
declare diskSize="$2"
|
|
|
|
declare diskType="$3"
|
|
|
|
declare zone="$4"
|
|
|
|
diskName="${instanceName}-pd"
|
|
|
|
|
|
|
|
gcloud beta compute disks create "$diskName" \
|
|
|
|
--size "$diskSize" \
|
|
|
|
--type "$diskType" \
|
|
|
|
--zone "$zone"
|
|
|
|
|
|
|
|
gcloud compute instances attach-disk "$instanceName" \
|
|
|
|
--disk "$diskName" \
|
|
|
|
--zone "$zone"
|
|
|
|
|
|
|
|
gcloud compute instances set-disk-auto-delete "$instanceName" \
|
|
|
|
--disk "$diskName" \
|
|
|
|
--zone "$zone" \
|
|
|
|
--auto-delete
|
|
|
|
}
|
2019-09-19 14:08:23 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# cloud_StatusAll
|
|
|
|
#
|
|
|
|
# Not yet implemented for this cloud provider
|
|
|
|
cloud_StatusAll() {
|
|
|
|
echo "ERROR: cloud_StatusAll is not yet implemented for GCE"
|
|
|
|
}
|