| #!/bin/bash |
| # Copyright 2015, Google Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # * Neither the name of Google Inc. nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| # |
| # Contains funcs that help maintain GRPC's Docker images. |
| # |
| # Most funcs rely on the special-purpose GCE instance to build the docker |
| # instances and store them in a GCS-backed docker repository. |
| # |
| # The GCE instance |
| # - should be based on the container-optimized GCE instance |
| # [https://cloud.google.com/compute/docs/containers]. |
| # - should be running google/docker-registry image |
| # [https://registry.hub.docker.com/u/google/docker-registry/], so that images |
| # can be saved to GCS |
| # - should have the GCE support scripts from this directory install on it. |
| # |
| # The expected workflow is |
| # - start a grpc docker GCE instance |
| # * on startup, some of the docker images will be regenerated automatically |
| # - used grpc_update_image to update images via that instance |
| |
| |
| # Creates the ssh key file expect by 'gcloud compute ssh' if it does not exist. |
| # |
| # Allows gcloud ssh commands to run on freshly started docker instances. |
| _grpc_ensure_gcloud_ssh() { |
| local default_key_file="$HOME/.ssh/google_compute_engine" |
| if [ "$HOME" == "/" ] |
| then |
| default_key_file="/root/.ssh/google_compute_engine" |
| fi |
| [ -f $default_key_file ] || { |
| ssh-keygen -f $default_key_file -N '' > /dev/null || { |
| echo "could not precreate $default_key_file" 1>&2 |
| return 1 |
| } |
| } |
| } |
| |
| # Pushes a dockerfile dir to cloud storage. |
| # |
| # dockerfile is expected to the parent directory to a nunber of directoies each |
| # of which specifies a Dockerfiles. |
| # |
| # grpc_push_dockerfiles path/to/docker_parent_dir gs://bucket/path/to/gcs/parent |
| grpc_push_dockerfiles() { |
| local docker_dir=$1 |
| [[ -n $docker_dir ]] || { |
| echo "$FUNCNAME: missing arg: docker_dir" 1>&2 |
| return 1 |
| } |
| |
| local gs_root_uri=$2 |
| [[ -n $gs_root_uri ]] || { |
| echo "$FUNCNAME: missing arg: gs_root_uri" 1>&2 |
| return 1 |
| } |
| |
| find $docker_dir -name '*~' -o -name '#*#' -exec rm -fv {} \; || { |
| echo "$FUNCNAME: failed: cleanup of tmp files in $docker_dir" 1>&2 |
| return 1 |
| } |
| gsutil cp -R $docker_dir $gs_root_uri || { |
| echo "$FUNCNAME: failed: cp $docker_dir -> $gs_root_uri" 1>&2 |
| return 1 |
| } |
| } |
| |
| # Adds the user to docker group on a GCE instance, and restarts the docker |
| # daemon |
| grpc_add_docker_user() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| local host=$1 |
| [[ -n $host ]] || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| |
| local project=$2 |
| local project_opt='' |
| [[ -n $project ]] && project_opt=" --project $project" |
| |
| local zone=$3 |
| local zone_opt='' |
| [[ -n $zone ]] && zone_opt=" --zone $zone" |
| |
| |
| local func_lib="/var/local/startup_scripts/shared_startup_funcs.sh" |
| local ssh_cmd="source $func_lib && grpc_docker_add_docker_group" |
| gcloud compute $project_opt ssh $zone_opt $host --command "$ssh_cmd" |
| } |
| |
| _grpc_update_image_args() { |
| echo "image_args $@" |
| # default the host, root storage uri and docker file root |
| grpc_gs_root='gs://tmp-grpc-dev/admin/' |
| grpc_dockerfile_root='tools/dockerfile' |
| grpc_gce_script_root='tools/gce_setup' |
| host='grpc-docker-builder' |
| |
| # see if -p or -z is used to override the the project or zone |
| local OPTIND |
| local OPTARG |
| while getopts :r:d:h: name |
| do |
| case $name in |
| d) grpc_dockerfile_root=$OPTARG ;; |
| r) grpc_gs_root=$OPTARG ;; |
| s) grpc_gce_script_root=$OPTARG ;; |
| h) host=$OPTARG ;; |
| :) continue ;; # ignore -r or -d without args, just use the defaults |
| \?) echo "-$OPTARG: unknown flag; it's ignored" 1>&2; continue ;; |
| esac |
| done |
| shift $((OPTIND-1)) |
| |
| [[ -d $grpc_dockerfile_root ]] || { |
| echo "Could not locate dockerfile root dir: $grpc_dockerfile_root" 1>&2 |
| return 1 |
| } |
| |
| [[ -d $grpc_gce_script_root ]] || { |
| echo "Could not locate gce script dir: $grpc_gce_script_root" 1>&2 |
| return 1 |
| } |
| |
| # the suffix is required and can't be defaulted |
| # the suffix has two roles: |
| # - images are labelled grpc/<label_suffix> |
| # - the dockerfile is for an image is dockerfile_root/grpc_<label_suffix> |
| [[ -n $1 ]] && { |
| label_suffix=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: label_suffix (e.g cxx,base,ruby,java_base)" 1>&2 |
| return 1 |
| } |
| } |
| |
| # Updates a docker image specified in a local dockerfile via the docker |
| # container GCE instance. |
| # |
| # the docker container GCE instance |
| # - should have been setup using ./new_grpc_docker_instance |
| # |
| # There are options for |
| # |
| # call-seq: |
| # grpc_update_image php_base |
| # grpc_update_image cxx # rebuilds the cxx image |
| # |
| grpc_update_image() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| |
| # set up by _grpc_update_args |
| local host grpc_gs_root grpc_gce_script_root grpc_dockerfile_root label_suffix |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| _grpc_set_project_and_zone -f _grpc_update_image_args "$@" || return 1 |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local image_label="grpc/$label_suffix" |
| local docker_dir_basename="grpc_$label_suffix" |
| local gce_docker_dir="/var/local/dockerfile/${docker_dir_basename}" |
| |
| # Set up and run the SSH command that builds the image |
| local func_lib="shared_startup_funcs.sh" |
| local gce_func_lib="/var/local/startup_scripts/$func_lib" |
| local ssh_cmd="source $gce_func_lib" |
| local ssh_cmd+=" && grpc_dockerfile_refresh $image_label $gce_docker_dir" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run |
| |
| # Update the remote copy of the GCE func library. |
| local src_func_lib="$grpc_gce_script_root/$func_lib" |
| local rmt_func_lib="$host:$gce_func_lib" |
| gcloud compute copy-files $src_func_lib $rmt_func_lib $project_opt $zone_opt || return 1 |
| |
| # Update the remote version of the docker func. |
| local src_docker_dir="$grpc_dockerfile_root/$docker_dir_basename" |
| local rmt_docker_root="$host:/var/local/dockerfile" |
| gcloud compute copy-files $src_docker_dir $rmt_docker_root $project_opt $zone_opt || return 1 |
| |
| gcloud compute $project_opt ssh $zone_opt $host --command "$ssh_cmd" |
| } |
| |
| # gce_has_instance checks if a project contains a named instance |
| # |
| # call-seq: |
| # gce_has_instance <project> <instance_name> |
| gce_has_instance() { |
| local project=$1 |
| [[ -n $project ]] || { echo "$FUNCNAME: missing arg: project" 1>&2; return 1; } |
| local checked_instance=$2 |
| [[ -n $checked_instance ]] || { |
| echo "$FUNCNAME: missing arg: checked_instance" 1>&2 |
| return 1 |
| } |
| |
| instances=$(gcloud --project $project compute instances list \ |
| | sed -e 's/ \+/ /g' | cut -d' ' -f 1) |
| for i in $instances |
| do |
| if [[ $i == $checked_instance ]] |
| then |
| return 0 |
| fi |
| done |
| |
| echo "instance '$checked_instance' not found in compute project $project" 1>&2 |
| return 1 |
| } |
| |
| # gce_find_internal_ip finds the ip address of a instance if it is present in |
| # the project. |
| # |
| # gce_find_internal_ip <project> <instance_name> |
| gce_find_internal_ip() { |
| local project=$1 |
| [[ -n $project ]] || { echo "$FUNCNAME: missing arg: project" 1>&2; return 1; } |
| local checked_instance=$2 |
| [[ -n $checked_instance ]] || { |
| echo "$FUNCNAME: missing arg: checked_instance" 1>&2 |
| return 1 |
| } |
| |
| gce_has_instance $project $checked_instance || return 1 |
| gcloud --project $project compute instances list \ |
| | grep -e "$checked_instance\s" \ |
| | sed -e 's/ \+/ /g' | cut -d' ' -f 4 |
| } |
| |
| # sets the vars grpc_zone and grpc_project |
| # |
| # to be used in funcs that want to set the zone and project and potential |
| # override them with |
| # |
| # grpc_zone |
| # - is set to the value gcloud config value for compute/zone if that's present |
| # - it defaults to asia-east1-a |
| # - it can be overridden by passing -z <other value> |
| # |
| # grpc_project |
| # - is set to the value gcloud config value for project if that's present |
| # - it defaults to stoked-keyword-656 (the grpc cloud testing project) |
| # - it can be overridden by passing -p <other value> |
| _grpc_set_project_and_zone() { |
| # can be set to 1 by passing -n in the args |
| dry_run=0 |
| |
| # by default; grpc_zone == gcloud config value || asia-east1-a |
| # - can be assigned via -p<project> in the args |
| grpc_zone=$(gcloud config list compute/zone --format text \ |
| | sed -e 's/ \+/ /g' | cut -d' ' -f 2) |
| # pick a known zone as a default |
| [[ $grpc_zone == 'None' ]] && grpc_zone='asia-east1-a' |
| |
| # grpc_project == gcloud config value || stoked-keyword-656 |
| # - can be assigned via -z<zone> in the args |
| grpc_project=$(gcloud config list project --format text \ |
| | sed -e 's/ \+/ /g' | cut -d' ' -f 2) |
| # pick an known zone as a default |
| [[ $grpc_project == 'None' ]] && grpc_project='stoked-keyword-656' |
| |
| # see if -p or -z is used to override the the project or zone |
| local OPTIND |
| local OPTARG |
| local arg_func |
| while getopts :np:z:f: name |
| do |
| case $name in |
| f) declare -F $OPTARG >> /dev/null && { |
| arg_func=$OPTARG; |
| } || { |
| echo "-f: arg_func value: $OPTARG is not defined" |
| return 2 |
| } |
| ;; |
| n) dry_run=1 ;; |
| p) grpc_project=$OPTARG ;; |
| z) grpc_zone=$OPTARG ;; |
| :) [[ $OPT_ARG == 'f' ]] && { |
| echo "-f: arg_func provided" 1>&2 |
| return 2 |
| } || { |
| # ignore -p or -z without args, just use the defaults |
| continue |
| } |
| ;; |
| \?) echo "-$OPTARG: unknown flag; it's ignored" 1>&2; continue ;; |
| esac |
| done |
| shift $((OPTIND-1)) |
| [[ -n $arg_func ]] && $arg_func "$@" |
| } |
| |
| # construct the flags to be passed to the binary running the test client |
| # |
| # call-seq: |
| # flags=$(grpc_interop_test_flags <server_ip> <server_port> <test_case>) |
| # [[ -n flags ]] || return 1 |
| grpc_interop_test_flags() { |
| [[ -n $1 ]] && { # server_ip |
| local server_ip=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: server_ip" 1>&2 |
| return 1 |
| } |
| [[ -n $1 ]] && { # port |
| local port=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: port" 1>&2 |
| return 1 |
| } |
| [[ -n $1 ]] && { # test_case |
| local test_case=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: test_case" 1>&2 |
| return 1 |
| } |
| echo "--server_host=$server_ip --server_port=$port --test_case=$test_case" |
| } |
| |
| # checks the positional args and assigns them to variables visible in the caller |
| # |
| # these are the positional args passed to grpc_interop_test after option flags |
| # are removed |
| # |
| # five args are expected, in order |
| # - test_case |
| # - host <the gce docker instance on which to run the test> |
| # - client to run |
| # - server_host <the gce docker instance on which the test server is running> |
| # - server type |
| grpc_interop_test_args() { |
| [[ -n $1 ]] && { # test_case |
| test_case=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: test_case" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # host |
| host=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # client_type |
| case $1 in |
| cxx|go|java|node|php|python|ruby) |
| grpc_gen_test_cmd="grpc_interop_gen_$1_cmd" |
| declare -F $grpc_gen_test_cmd >> /dev/null || { |
| echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2 |
| return 2 |
| } |
| shift |
| ;; |
| *) |
| echo "bad client_type: $1" 1>&2 |
| return 1 |
| ;; |
| esac |
| } || { |
| echo "$FUNCNAME: missing arg: client_type" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # grpc_server |
| grpc_server=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: grpc_server" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # server_type |
| case $1 in |
| cxx) grpc_port=8010 ;; |
| go) grpc_port=8020 ;; |
| java) grpc_port=8030 ;; |
| node) grpc_port=8040 ;; |
| python) grpc_port=8050 ;; |
| ruby) grpc_port=8060 ;; |
| *) echo "bad server_type: $1" 1>&2; return 1 ;; |
| esac |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: server_type" 1>&2 |
| return 1 |
| } |
| } |
| |
| # checks the positional args and assigns them to variables visible in the caller |
| # |
| # these are the positional args passed to grpc_cloud_prod_test after option flags |
| # are removed |
| # |
| # three args are expected, in order |
| # - test_case |
| # - host <the gce docker instance on which to run the test> |
| # - client to run |
| grpc_cloud_prod_test_args() { |
| [[ -n $1 ]] && { # test_case |
| test_case=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: test_case" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # host |
| host=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # client_type |
| case $1 in |
| cxx|go|java|node|php|python|ruby) |
| grpc_gen_test_cmd="grpc_cloud_prod_gen_$1_cmd" |
| declare -F $grpc_gen_test_cmd >> /dev/null || { |
| echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2 |
| return 2 |
| } |
| shift |
| ;; |
| *) |
| echo "bad client_type: $1" 1>&2 |
| return 1 |
| ;; |
| esac |
| } || { |
| echo "$FUNCNAME: missing arg: client_type" 1>&2 |
| return 1 |
| } |
| } |
| |
| # checks the positional args and assigns them to variables visible in the caller |
| # |
| # these are the positional args passed to grpc_cloud_prod_auth_test after option flags |
| # are removed |
| # |
| # three args are expected, in order |
| # - test_case |
| # - host <the gce docker instance on which to run the test> |
| # - client to run |
| grpc_cloud_prod_auth_test_args() { |
| grpc_gen_test_cmd="grpc_cloud_prod_auth_" |
| [[ -n $1 ]] && { # test_case |
| test_case=$1 |
| grpc_gen_test_cmd+="$1" |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: test_case" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # host |
| host=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| |
| [[ -n $1 ]] && { # client_type |
| case $1 in |
| cxx|go|java|nodejs|php|python|ruby) |
| grpc_gen_test_cmd+="_gen_$1_cmd" |
| declare -F $grpc_gen_test_cmd >> /dev/null || { |
| echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2 |
| return 2 |
| } |
| shift |
| ;; |
| *) |
| echo "bad client_type: $1" 1>&2 |
| return 1 |
| ;; |
| esac |
| } || { |
| echo "$FUNCNAME: missing arg: client_type" 1>&2 |
| return 1 |
| } |
| } |
| |
| _grpc_sync_scripts_args() { |
| grpc_gce_script_root='tools/gce_setup' |
| |
| local OPTIND |
| local OPTARG |
| while getopts :s: name |
| do |
| case $name in |
| s) grpc_gce_script_root=$OPTARG ;; |
| :) continue ;; # ignore -s without args, just use the defaults |
| \?) echo "-$OPTARG: unknown flag; it's ignored" 1>&2; continue ;; |
| esac |
| done |
| shift $((OPTIND-1)) |
| |
| [[ -d $grpc_gce_script_root ]] || { |
| echo "Could not locate gce script dir: $grpc_gce_script_root" 1>&2 |
| return 1 |
| } |
| |
| [[ $# -lt 1 ]] && { |
| echo "$FUNCNAME: missing arg: host1 [host2 ... hostN]" 1>&2 |
| return 1 |
| } |
| grpc_hosts="$@" |
| } |
| |
| # Updates the latest version of the support scripts on some hosts. |
| # |
| # call-seq; |
| # grpc_sync_scripts <server_name1>, <server_name2> .. <server_name3> |
| # |
| # Updates the GCE docker instance <server_name> |
| grpc_sync_scripts() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| local grpc_hosts grpc_gce_script_root |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f _grpc_sync_scripts_args "$@" || return 1 |
| |
| local func_lib="shared_startup_funcs.sh" |
| local gce_func_lib="/var/local/startup_scripts/$func_lib" |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local host |
| for host in $grpc_hosts |
| do |
| gce_has_instance $grpc_project $host || return 1; |
| # Update the remote copy of the GCE func library. |
| local src_func_lib="$grpc_gce_script_root/$func_lib" |
| local rmt_func_lib="$host:$gce_func_lib" |
| gcloud compute copy-files $src_func_lib $rmt_func_lib $project_opt $zone_opt || return 1 |
| done |
| } |
| |
| grpc_sync_images_args() { |
| [[ $# -lt 1 ]] && { |
| echo "$FUNCNAME: missing arg: host1 [host2 ... hostN]" 1>&2 |
| return 1 |
| } |
| grpc_hosts="$@" |
| } |
| |
| # Updates all the known docker images on a host.. |
| # |
| # call-seq; |
| # grpc_sync_images <server_name1>, <server_name2> .. <server_name3> |
| # |
| # Updates the GCE docker instance <server_name> |
| grpc_sync_images() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| local grpc_hosts |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f grpc_sync_images_args "$@" || return 1 |
| |
| local func_lib="/var/local/startup_scripts/shared_startup_funcs.sh" |
| local cmd="source $func_lib && grpc_docker_pull_known" |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local host |
| for host in $grpc_hosts |
| do |
| gce_has_instance $grpc_project $host || return 1; |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && continue # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" |
| done |
| } |
| |
| _grpc_show_servers_args() { |
| [[ -n $1 ]] && { # host |
| host=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| } |
| |
| |
| # Shows servers on a docker instance. |
| # |
| # call-seq; |
| # grpc_show_servers <server_name> |
| # E.g |
| # grpc_show_server grpc-docker-server |
| # |
| # Shows the grpc servers on the GCE instance <server_name> |
| grpc_show_servers() { |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| # set by _grpc_show_servers |
| local host |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f _grpc_show_servers_args "$@" || return 1 |
| gce_has_instance $grpc_project $host || return 1; |
| |
| local cmd="sudo docker ps | grep grpc_" |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && continue # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" |
| } |
| |
| _grpc_launch_servers_args() { |
| [[ -n $1 ]] && { # host |
| host=$1 |
| shift |
| } || { |
| echo "$FUNCNAME: missing arg: host" 1>&2 |
| return 1 |
| } |
| [[ -n $1 ]] && { |
| servers="$@" |
| } || { |
| servers="cxx java go node ruby" |
| echo "$FUNCNAME: no servers specified, will launch defaults '$servers'" |
| } |
| } |
| |
| # Launches servers on a docker instance. |
| # |
| # call-seq; |
| # grpc_launch_servers <server_name> [server1 server2 ...] |
| # E.g |
| # grpc_launch_server grpc-docker-server ruby node |
| # |
| # Restarts all the specified servers on the GCE instance <server_name> |
| # If no servers are specified, it launches all known servers |
| grpc_launch_servers() { |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| # set by _grpc_launch_servers_args |
| local host servers |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f _grpc_launch_servers_args "$@" || return 1 |
| gce_has_instance $grpc_project $host || return 1; |
| |
| # launch each of the servers in turn |
| for server in $servers |
| do |
| local grpc_port |
| case $server in |
| cxx) grpc_port=8010 ;; |
| go) grpc_port=8020 ;; |
| java) grpc_port=8030 ;; |
| node) grpc_port=8040 ;; |
| python) grpc_port=8050 ;; |
| ruby) grpc_port=8060 ;; |
| *) echo "bad server_type: $1" 1>&2; return 1 ;; |
| esac |
| local docker_label="grpc/$server" |
| local docker_name="grpc_interop_$server" |
| |
| cmd="sudo docker kill $docker_name > /dev/null 2>&1; " |
| cmd+="sudo docker rm $docker_name > /dev/null 2>&1; " |
| cmd+="sudo docker run -d --name $docker_name" |
| cmd+=" -p $grpc_port:$grpc_port $docker_label" |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" |
| done |
| } |
| |
| # Runs a test command on a docker instance. |
| # |
| # call-seq: |
| # grpc_interop_test <test_name> <host> <client_type> \ |
| # <server_host> <server_type> |
| # |
| # N.B: server_name defaults to 'grpc-docker-server' |
| # |
| # requirements: |
| # host is a GCE instance running docker with access to the gRPC docker images |
| # server_name is a GCE docker instance running the gRPC server in docker |
| # test_name is one of the named gRPC tests [http://go/grpc_interop_tests] |
| # client_type is one of [cxx,go,java,php,python,ruby] |
| # server_type is one of [cxx,go,java,python,ruby] |
| # |
| # it assumes: |
| # that each grpc-imp has a docker image named grpc/<imp>, e.g, grpc/java |
| # a test is run using $ docker run 'path/to/interop_test_bin --flags' |
| # the required images are available on <host> |
| # |
| # server_name [default:grpc-docker-server] is an instance that runs the |
| # <server_type> server on the standard test port for the <server_type> |
| # |
| # each server_type runs it tests on a standard test port as follows: |
| # cxx: 8010 |
| # go: 8020 |
| # java: 8030 |
| # node: 8040 |
| # python: 8050 |
| # ruby: 8060 |
| # |
| # each client_type should have an associated bash func: |
| # grpc_interop_gen_<client_type>_cmd |
| # the func provides the dockerized commmand for running client_type's test. |
| # If no such func is available, tests for that client type cannot be run. |
| # |
| # the flags for running a test are the same: |
| # |
| # --server_host=<svr_addr> --server_port=<svr_port> --test_case=<...> |
| grpc_interop_test() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| # grpc_interop_test_args |
| local test_case host grpc_gen_test_cmd grpc_server grpc_port |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f grpc_interop_test_args "$@" || return 1 |
| gce_has_instance $grpc_project $host || return 1; |
| |
| local addr=$(gce_find_internal_ip $grpc_project $grpc_server) |
| [[ -n $addr ]] || return 1 |
| local flags=$(grpc_interop_test_flags $addr $grpc_port $test_case) |
| [[ -n $flags ]] || return 1 |
| cmd=$($grpc_gen_test_cmd $flags) |
| [[ -n $cmd ]] || return 1 |
| |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" & |
| PID=$! |
| sleep 10 |
| echo "pid is $PID" |
| if ps -p $PID |
| then |
| kill $PID |
| return 1 |
| fi |
| |
| } |
| |
| # Runs a test command on a docker instance. |
| # |
| # call-seq: |
| # grpc_cloud_prod_test <test_name> <host> <client_type> |
| # |
| # requirements: |
| # host is a GCE instance running docker with access to the gRPC docker images |
| # test_name is one of the named gRPC tests [http://go/grpc_interop_tests] |
| # client_type is one of [cxx,go,java,php,python,ruby] |
| # |
| # it assumes: |
| # that each grpc-imp has a docker image named grpc/<imp>, e.g, grpc/java |
| # a test is run using $ docker run 'path/to/interop_test_bin --flags' |
| # the required images are available on <host> |
| # |
| # each client_type should have an associated bash func: |
| # grpc_cloud_prod_gen_<client_type>_cmd |
| # the func provides the dockerized commmand for running client_type's test. |
| # If no such func is available, tests for that client type cannot be run. |
| grpc_cloud_prod_test() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| # grpc_cloud_prod_test_args |
| local test_case host grpc_gen_test_cmd |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f grpc_cloud_prod_test_args "$@" || return 1 |
| gce_has_instance $grpc_project $host || return 1; |
| |
| local test_case_flag=" --test_case=$test_case" |
| cmd=$($grpc_gen_test_cmd $test_case_flag) |
| [[ -n $cmd ]] || return 1 |
| |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" & |
| PID=$! |
| sleep 10 |
| echo "pid is $PID" |
| if ps -p $PID |
| then |
| kill $PID |
| return 1 |
| fi |
| |
| } |
| |
| # Runs a test command on a docker instance. |
| # |
| # call-seq: |
| # grpc_cloud_prod_auth_test <test_name> <host> <client_type> |
| # |
| # requirements: |
| # host is a GCE instance running docker with access to the gRPC docker images |
| # test_name is one of the named gRPC tests [http://go/grpc_interop_tests] |
| # client_type is one of [cxx,go,java,php,python,ruby] |
| # |
| # it assumes: |
| # that each grpc-imp has a docker image named grpc/<imp>, e.g, grpc/java |
| # a test is run using $ docker run 'path/to/interop_test_bin --flags' |
| # the required images are available on <host> |
| # |
| # each client_type should have an associated bash func: |
| # grpc_cloud_prod_auth_<test_case>_gen_<client_type>_cmd |
| # the func provides the dockerized commmand for running client_type's test. |
| # If no such func is available, tests for that client type cannot be run. |
| grpc_cloud_prod_auth_test() { |
| _grpc_ensure_gcloud_ssh || return 1; |
| # declare vars local so that they don't pollute the shell environment |
| # where they this func is used. |
| |
| local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone |
| # grpc_cloud_prod_test_args |
| local test_case host grpc_gen_test_cmd |
| |
| # set the project zone and check that all necessary args are provided |
| _grpc_set_project_and_zone -f grpc_cloud_prod_auth_test_args "$@" || return 1 |
| gce_has_instance $grpc_project $host || return 1; |
| |
| local test_case_flag=" --test_case=$test_case" |
| cmd=$($grpc_gen_test_cmd $test_case_flag) |
| [[ -n $cmd ]] || return 1 |
| |
| local project_opt="--project $grpc_project" |
| local zone_opt="--zone $grpc_zone" |
| local ssh_cmd="bash -l -c \"$cmd\"" |
| echo "will run:" |
| echo " $ssh_cmd" |
| echo "on $host" |
| [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run |
| gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" |
| } |
| |
| # constructs the full dockerized ruby interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_ruby_cmd() { |
| local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c" |
| local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" |
| local the_cmd="$cmd_prefix 'ruby $test_script --use_test_ca --use_tls $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized java interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_gen_ruby_cmd() { |
| local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c" |
| local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" |
| local test_script+=" --use_tls" |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" |
| local the_cmd="$cmd_prefix '$env_prefix ruby $test_script $gfe_flags $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized ruby service_account auth interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_auth_service_account_creds_gen_ruby_cmd() { |
| local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c"; |
| local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" |
| local test_script+=" --use_tls" |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local added_gfe_flags=$(_grpc_svc_acc_test_flags) |
| local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" |
| local the_cmd="$cmd_prefix '$env_prefix ruby $test_script $gfe_flags $added_gfe_flag $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized ruby gce auth interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_auth_compute_engine_creds_gen_ruby_cmd() { |
| local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c"; |
| local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" |
| local test_script+=" --use_tls" |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local added_gfe_flags=$(_grpc_gce_test_flags) |
| local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" |
| local the_cmd="$cmd_prefix '$env_prefix ruby $test_script $gfe_flags $added_gfe_flag $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized Go interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_go_cmd() { |
| local cmd_prefix="sudo docker run grpc/go /bin/bash -c" |
| local test_script="cd src/google.golang.org/grpc/interop/client" |
| local test_script+=" && go run client.go --use_tls=true" |
| local the_cmd="$cmd_prefix '$test_script $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized Go interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_gen_go_cmd() { |
| local cmd_prefix="sudo docker run grpc/go /bin/bash -c" |
| local test_script="cd src/google.golang.org/grpc/interop/client" |
| local test_script+=" && go run client.go --use_tls=true" |
| local gfe_flags=" --tls_ca_file=\"\" --tls_server_name=\"\" --server_port=443 --server_host=grpc-test.sandbox.google.com" |
| local the_cmd="$cmd_prefix '$test_script $gfe_flags $@'" |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized java interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_java_cmd() { |
| local cmd_prefix="sudo docker run grpc/java"; |
| local test_script="/var/local/git/grpc-java/run-test-client.sh"; |
| local test_script+=" --use_test_ca=true --use_tls=true" |
| local the_cmd="$cmd_prefix $test_script $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized java interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_gen_java_cmd() { |
| local cmd_prefix="sudo docker run grpc/java"; |
| local test_script="/var/local/git/grpc-java/run-test-client.sh"; |
| local test_script+=" --use_tls=true" |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized php interop test cmd. |
| # |
| # TODO(mlumish): update this to use the script once that's on git |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_php_cmd() { |
| local cmd_prefix="sudo docker run grpc/php bin/bash -l -c"; |
| local test_script="cd /var/local/git/grpc/src/php/tests/interop"; |
| local test_script+=" && php -d extension_dir=../../ext/grpc/modules/"; |
| local test_script+=" -d extension=grpc.so interop_client.php"; |
| local the_cmd="$cmd_prefix '$test_script $@ 1>&2'"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized node interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_node_cmd() { |
| local cmd_prefix="sudo docker run grpc/node"; |
| local test_script="/usr/bin/nodejs /var/local/git/grpc/src/node/interop/interop_client.js --use_tls=true --use_test_ca=true"; |
| local the_cmd="$cmd_prefix $test_script $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized node gce=>prod interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_gen_node_cmd() { |
| local cmd_prefix="sudo docker run grpc/node"; |
| local test_script="/usr/bin/nodejs /var/local/git/grpc/src/node/interop/interop_client.js --use_tls=true"; |
| local gfe_flags=$(_grpc_prod_gfe_flags); |
| local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized node service_account auth interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_auth_service_account_creds_gen_node_cmd() { |
| local cmd_prefix="sudo docker run grpc/node"; |
| local test_script="/usr/bin/nodejs /var/local/git/grpc/src/node/interop/interop_client.js --use_tls=true"; |
| local gfe_flags=$(_grpc_prod_gfe_flags); |
| local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" |
| env_prefix+=" GOOGLE_APPLICATION_CREDENTIALS=/service_account/stubbyCloudTestingTest-7dd63462c60c.json" |
| local the_cmd="$env_prefix $cmd_prefix $test_script $gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized cpp interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_interop_gen_cxx_cmd() { |
| local cmd_prefix="sudo docker run grpc/cxx"; |
| local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl"; |
| local the_cmd="$cmd_prefix $test_script $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized cpp gce=>prod interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_gen_cxx_cmd() { |
| local cmd_prefix="sudo docker run grpc/cxx"; |
| local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots"; |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized cpp service_account auth interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_auth_service_account_creds_gen_cxx_cmd() { |
| local cmd_prefix="sudo docker run grpc/cxx"; |
| local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots"; |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local added_gfe_flags=$(_grpc_svc_acc_test_flags) |
| local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # constructs the full dockerized cpp gce auth interop test cmd. |
| # |
| # call-seq: |
| # flags= .... # generic flags to include the command |
| # cmd=$($grpc_gen_test_cmd $flags) |
| grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() { |
| local cmd_prefix="sudo docker run grpc/cxx"; |
| local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots"; |
| local gfe_flags=$(_grpc_prod_gfe_flags) |
| local added_gfe_flags=$(_grpc_gce_test_flags) |
| local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; |
| echo $the_cmd |
| } |
| |
| # outputs the flags passed to gfe tests |
| _grpc_prod_gfe_flags() { |
| echo " --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" |
| } |
| |
| # outputs the flags passed to the service account auth tests |
| _grpc_svc_acc_test_flags() { |
| echo " --service_account_key_file=/service_account/stubbyCloudTestingTest-7dd63462c60c.json --oauth_scope=https://www.googleapis.com/auth/xapi.zoo" |
| } |
| |
| # outputs the flags passed to the gcloud auth tests |
| _grpc_gce_test_flags() { |
| echo " --default_service_account=155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com --oauth_scope=https://www.googleapis.com/auth/xapi.zoo" |
| } |
| |
| # TODO(grpc-team): add grpc_interop_gen_xxx_cmd for python |