github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/tools/integration/gce.sh (about) 1 #!/bin/bash 2 # This script has a bunch of GCE-related functions: 3 # ./gce.sh setup - starts two VMs on GCE and configures them to run our integration tests 4 # . ./gce.sh; ./run_all.sh - set a bunch of environment variables for the tests 5 # ./gce.sh destroy - tear down the VMs 6 # ./gce.sh make_template - make a fresh VM template; update TEMPLATE_NAME first! 7 8 set -e 9 10 : "${KEY_FILE:=/tmp/gce_private_key.json}" 11 : "${SSH_KEY_FILE:=$HOME/.ssh/gce_ssh_key}" 12 : "${IMAGE_FAMILY:=ubuntu-1404-lts}" 13 : "${IMAGE_PROJECT:=ubuntu-os-cloud}" 14 : "${USER_ACCOUNT:=ubuntu}" 15 : "${ZONE:=us-central1-a}" 16 : "${PROJECT:=}" 17 : "${TEMPLATE_NAME:=}" 18 : "${NUM_HOSTS:=}" 19 20 if [ -z "${PROJECT}" ] || [ -z "${NUM_HOSTS}" ] || [ -z "${TEMPLATE_NAME}" ]; then 21 echo "Must specify PROJECT, NUM_HOSTS and TEMPLATE_NAME" 22 exit 1 23 fi 24 25 SUFFIX="" 26 if [ -n "$CIRCLECI" ]; then 27 SUFFIX="-${CIRCLE_PROJECT_USERNAME}-${CIRCLE_PROJECT_REPONAME}-${CIRCLE_BUILD_NUM}-$CIRCLE_NODE_INDEX" 28 else 29 SUFFIX="-${USER}" 30 fi 31 32 # Setup authentication 33 gcloud auth activate-service-account --key-file "$KEY_FILE" 1>/dev/null 34 gcloud config set project "$PROJECT" 35 36 function vm_names() { 37 local names= 38 for i in $(seq 1 "$NUM_HOSTS"); do 39 names=("host$i$SUFFIX" "${names[@]}") 40 done 41 echo "${names[@]}" 42 } 43 44 # Delete all vms in this account 45 function destroy() { 46 local names 47 # shellcheck disable=SC2046 48 if [ $(gcloud compute firewall-rules list "test-allow-docker$SUFFIX" 2>/dev/null | wc -l) -gt 0 ]; then 49 gcloud compute firewall-rules delete "test-allow-docker$SUFFIX" 50 fi 51 names="$(vm_names)" 52 # shellcheck disable=SC2086 53 if [ "$(gcloud compute instances list --zones "$ZONE" -q $names | wc -l)" -le 1 ]; then 54 return 0 55 fi 56 for i in {0..10}; do 57 # gcloud instances delete can sometimes hang. 58 case $( 59 set +e 60 timeout 60s /bin/bash -c "gcloud compute instances delete --zone $ZONE -q $names >/dev/null 2>&1" 61 echo $? 62 ) in 63 0) 64 return 0 65 ;; 66 124) 67 # 124 means it timed out 68 break 69 ;; 70 *) 71 return 1 72 ;; 73 esac 74 done 75 } 76 77 function internal_ip() { 78 jq -r ".[] | select(.name == \"$2\") | .networkInterfaces[0].networkIP" "$1" 79 } 80 81 function external_ip() { 82 jq -r ".[] | select(.name == \"$2\") | .networkInterfaces[0].accessConfigs[0].natIP" "$1" 83 } 84 85 function try_connect() { 86 for i in {0..10}; do 87 ssh -t "$1" true && return 88 sleep 2 89 done 90 } 91 92 function install_docker_on() { 93 name=$1 94 echo "Installing Docker on $name for user ${USER_ACCOUNT}" 95 # shellcheck disable=SC2087 96 ssh -t "$name" sudo bash -x -s <<EOF 97 set -x 98 set -e 99 curl -sSL https://get.docker.com/gpg | sudo apt-key add - 100 curl -sSL https://get.docker.com/ | sh 101 apt-get update -qq; 102 apt-get install -q -y --force-yes --no-install-recommends ethtool; 103 usermod -a -G docker "${USER_ACCOUNT}"; 104 echo 'DOCKER_OPTS="-H unix:///var/run/docker.sock -H unix:///var/run/alt-docker.sock -H tcp://0.0.0.0:2375 -s overlay"' >> /etc/default/docker; 105 service docker restart 106 EOF 107 # It seems we need a short delay for docker to start up, so I put this in 108 # a separate ssh connection. This installs nsenter. 109 ssh -t "$name" sudo docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter 110 } 111 112 function copy_hosts() { 113 hostname=$1 114 hosts=$2 115 ssh -t "$hostname" "sudo -- sh -c \"cat >>/etc/hosts\"" <"$hosts" 116 } 117 118 # Create new set of VMs 119 function setup() { 120 destroy 121 122 names=($(vm_names)) 123 gcloud compute instances create "${names[@]}" --image "$TEMPLATE_NAME" --zone "$ZONE" --tags "test$SUFFIX" --network=test 124 my_ip="$(curl -s http://ipinfo.io/ip)" 125 gcloud compute firewall-rules create "test-allow-docker$SUFFIX" --network=test --allow tcp:2375,tcp:12375,tcp:4040,tcp:80 --target-tags "test$SUFFIX" --source-ranges "$my_ip" 126 127 gcloud compute config-ssh --ssh-key-file "$SSH_KEY_FILE" 128 sed -i '/UserKnownHostsFile=\/dev\/null/d' ~/.ssh/config 129 130 # build an /etc/hosts file for these vms 131 hosts=$(mktemp hosts.XXXXXXXXXX) 132 json=$(mktemp json.XXXXXXXXXX) 133 gcloud compute instances list --format=json >"$json" 134 for name in "${names[@]}"; do 135 echo "$(internal_ip "$json" "$name") $name.$ZONE.$PROJECT" >>"$hosts" 136 done 137 138 for name in "${names[@]}"; do 139 hostname="$name.$ZONE.$PROJECT" 140 141 # Add the remote ip to the local /etc/hosts 142 sudo sed -i "/$hostname/d" /etc/hosts 143 sudo sh -c "echo \"$(external_ip "$json" "$name") $hostname\" >>/etc/hosts" 144 try_connect "$hostname" 145 146 copy_hosts "$hostname" "$hosts" & 147 done 148 149 wait 150 151 rm "$hosts" "$json" 152 } 153 154 function make_template() { 155 gcloud compute instances create "$TEMPLATE_NAME" --image-family "$IMAGE_FAMILY" --image-project "$IMAGE_PROJECT" --zone "$ZONE" 156 gcloud compute config-ssh --ssh-key-file "$SSH_KEY_FILE" 157 name="$TEMPLATE_NAME.$ZONE.$PROJECT" 158 try_connect "$name" 159 install_docker_on "$name" 160 gcloud -q compute instances delete "$TEMPLATE_NAME" --keep-disks boot --zone "$ZONE" 161 gcloud compute images create "$TEMPLATE_NAME" --source-disk "$TEMPLATE_NAME" --source-disk-zone "$ZONE" 162 } 163 164 function hosts() { 165 hosts= 166 args= 167 json=$(mktemp json.XXXXXXXXXX) 168 gcloud compute instances list --format=json >"$json" 169 for name in $(vm_names); do 170 hostname="$name.$ZONE.$PROJECT" 171 hosts=($hostname "${hosts[@]}") 172 args=("--add-host=$hostname:$(internal_ip "$json" "$name")" "${args[@]}") 173 done 174 echo export SSH=\"ssh -l "${USER_ACCOUNT}"\" 175 echo "export HOSTS=\"${hosts[*]}\"" 176 echo "export ADD_HOST_ARGS=\"${args[*]}\"" 177 rm "$json" 178 } 179 180 case "$1" in 181 setup) 182 setup 183 ;; 184 185 hosts) 186 hosts 187 ;; 188 189 destroy) 190 destroy 191 ;; 192 193 make_template) 194 # see if template exists 195 if ! gcloud compute images list | grep "$PROJECT" | grep "$TEMPLATE_NAME"; then 196 make_template 197 else 198 echo "Reusing existing template:" 199 gcloud compute images describe "$TEMPLATE_NAME" | grep "^creationTimestamp" 200 fi 201 ;; 202 esac