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