diff --git a/.github/change_repo_manager.sh b/.github/change_repo_manager.sh
new file mode 100644
index 00000000..5f73a6c2
--- /dev/null
+++ b/.github/change_repo_manager.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright 2020 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+if [ $# -lt 1 ];then
+ echo "Usage: $0 github-id"
+ exit 1
+fi
+
+echo "Change repo manager to $1"
+
+BASE_PATH=$(dirname $0)
+
+for file in bug_report.md cleanup_request.md feature_request.md question.md
+do
+ sed -i".bak" -E "s/assignees: ([a-zA-Z0-9-]+)/assignees: $1/" "$BASE_PATH/ISSUE_TEMPLATE/$file"
+ rm "$BASE_PATH/ISSUE_TEMPLATE/$file.bak"
+done
+
+sed -i".bak" -E "s/^@([a-zA-Z0-9-]+)/@$1/" "$BASE_PATH/pull_request_template.md"
+rm "$BASE_PATH/pull_request_template.md.bak"
+
+echo "Done"
diff --git a/bazel/update_mirror.sh b/bazel/update_mirror.sh
new file mode 100644
index 00000000..a4805db6
--- /dev/null
+++ b/bazel/update_mirror.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Script to upload github archives for bazel dependencies to GCS, creating a reliable mirror link.
+# Archives are copied to "grpc-bazel-mirror" GCS bucket (https://console.cloud.google.com/storage/browser/grpc-bazel-mirror?project=grpc-testing)
+# and will by downloadable with the https://storage.googleapis.com/grpc-bazel-mirror/ prefix.
+#
+# This script should be run each time bazel dependencies are updated.
+
+set -e
+
+cd $(dirname $0)/..
+
+# Create a temp directory to hold the versioned tarball,
+# and clean it up when the script exits.
+tmpdir="$(mktemp -d)"
+function cleanup {
+ rm -rf "$tmpdir"
+}
+trap cleanup EXIT
+
+function upload {
+ local file="$1"
+
+ if gsutil stat "gs://grpc-bazel-mirror/${file}" > /dev/null
+ then
+ echo "Skipping ${file}"
+ else
+ echo "Downloading https://${file}"
+ curl -L --fail --output "${tmpdir}/archive" "https://${file}"
+
+ echo "Uploading https://${file} to https://storage.googleapis.com/grpc-bazel-mirror/${file}"
+ gsutil cp "${tmpdir}/archive" "gs://grpc-bazel-mirror/${file}"
+
+ rm -rf "${tmpdir}/archive"
+ fi
+}
+
+# How to check that all mirror URLs work:
+# 1. clean $HOME/.cache/bazel
+# 2. bazel clean --expunge
+# 3. bazel sync (failed downloads will print warnings)
+
+# A specific link can be upload manually by running e.g.
+# upload "github.com/google/boringssl/archive/1c2769383f027befac5b75b6cedd25daf3bf4dcf.tar.gz"
+
+# bazel binaries used by the tools/bazel wrapper script
+upload github.com/bazelbuild/bazel/releases/download/1.0.0/bazel-1.0.0-linux-x86_64
+upload github.com/bazelbuild/bazel/releases/download/1.0.0/bazel-1.0.0-darwin-x86_64
+upload github.com/bazelbuild/bazel/releases/download/1.0.0/bazel-1.0.0-windows-x86_64.exe
+
+upload github.com/bazelbuild/bazel/releases/download/2.2.0/bazel-2.2.0-linux-x86_64
+upload github.com/bazelbuild/bazel/releases/download/2.2.0/bazel-2.2.0-darwin-x86_64
+upload github.com/bazelbuild/bazel/releases/download/2.2.0/bazel-2.2.0-windows-x86_64.exe
+
+upload github.com/bazelbuild/bazel/releases/download/3.7.1/bazel-3.7.1-linux-x86_64
+upload github.com/bazelbuild/bazel/releases/download/3.7.1/bazel-3.7.1-darwin-x86_64
+upload github.com/bazelbuild/bazel/releases/download/3.7.1/bazel-3.7.1-windows-x86_64.exe
+
+upload github.com/bazelbuild/bazel/releases/download/4.2.1/bazel-4.2.1-linux-x86_64
+upload github.com/bazelbuild/bazel/releases/download/4.2.1/bazel-4.2.1-darwin-x86_64
+upload github.com/bazelbuild/bazel/releases/download/4.2.1/bazel-4.2.1-windows-x86_64.exe
+
+# Collect the github archives to mirror from grpc_deps.bzl
+grep -o '"https://github.com/[^"]*"' bazel/grpc_deps.bzl | sed 's/^"https:\/\///' | sed 's/"$//' | while read -r line ; do
+ echo "Updating mirror for ${line}"
+ upload "${line}"
+done
diff --git a/examples/php/greeter_proto_gen.sh b/examples/php/greeter_proto_gen.sh
new file mode 100644
index 00000000..07c7e61b
--- /dev/null
+++ b/examples/php/greeter_proto_gen.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+cd $(dirname $0)/../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_php_plugin
+
+$PROTOC --proto_path=examples/protos \
+ --php_out=examples/php \
+ --grpc_out=generate_server:examples/php \
+ --plugin=$PLUGIN examples/protos/helloworld.proto
diff --git a/examples/php/route_guide/route_guide_proto_gen.sh b/examples/php/route_guide/route_guide_proto_gen.sh
new file mode 100644
index 00000000..8b7e61c4
--- /dev/null
+++ b/examples/php/route_guide/route_guide_proto_gen.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+cd $(dirname $0)/../../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_php_plugin
+
+$PROTOC --proto_path=examples/protos \
+ --php_out=examples/php/route_guide \
+ --grpc_out=generate_server:examples/php/route_guide \
+ --plugin=$PLUGIN examples/protos/route_guide.proto
diff --git a/examples/php/route_guide/run_route_guide_client.sh b/examples/php/route_guide/run_route_guide_client.sh
new file mode 100644
index 00000000..4f1013f5
--- /dev/null
+++ b/examples/php/route_guide/run_route_guide_client.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+php -d extension=grpc.so -d max_execution_time=300 \
+ route_guide_client.php \
+ ../../node/static_codegen/route_guide/route_guide_db.json
diff --git a/examples/php/run_greeter_client.sh b/examples/php/run_greeter_client.sh
new file mode 100644
index 00000000..457b692b
--- /dev/null
+++ b/examples/php/run_greeter_client.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+php -d extension=grpc.so -d max_execution_time=300 \
+ greeter_client.php $1
diff --git a/src/csharp/build_nuget.sh b/src/csharp/build_nuget.sh
new file mode 100644
index 00000000..9ebb6d85
--- /dev/null
+++ b/src/csharp/build_nuget.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+mkdir -p ../../artifacts
+
+# Collect the artifacts built by the previous build step
+mkdir -p nativelibs
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/csharp_ext_* nativelibs || true
+
+# Collect protoc artifacts built by the previous build step
+mkdir -p protoc_plugins
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/protoc_* protoc_plugins || true
+
+# Add current timestamp to dev nugets
+./expand_dev_version.sh
+
+dotnet restore Grpc.sln
+
+# To be able to build the Grpc.Core project, we also need to put grpc_csharp_ext to where Grpc.Core.csproj
+# expects it.
+mkdir -p ../../cmake/build
+cp nativelibs/csharp_ext_linux_x64/libgrpc_csharp_ext.so ../../cmake/build
+
+dotnet pack --configuration Release Grpc.Core.Api --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
+dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Tools --output ../../../artifacts
+# rem build auxiliary packages
+dotnet pack --configuration Release Grpc --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Core.NativeDebug --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Core.Xamarin --output ../../../artifacts
+
+# Create a zipfile with all the nugets we just created
+cd ../../artifacts
+zip csharp_nugets_windows_dotnetcli.zip *.nupkg
diff --git a/src/csharp/build_unitypackage.sh b/src/csharp/build_unitypackage.sh
new file mode 100644
index 00000000..4363ee19
--- /dev/null
+++ b/src/csharp/build_unitypackage.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+mkdir -p ../../artifacts
+
+# Collect the artifacts built by the previous build step
+mkdir -p nativelibs
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/csharp_ext_* nativelibs || true
+
+# Add current timestamp to dev nugets
+./expand_dev_version.sh
+
+# Extract current Grpc.Core version from build/dependencies.props
+UNITYPACKAGE_VERSION="$(grep -o '.*' build/dependencies.props | sed 's///' | sed 's/<\/GrpcCsharpVersion>//')"
+
+dotnet restore Grpc.sln
+
+# To be able to build the Grpc.Core project, we also need to put grpc_csharp_ext to where Grpc.Core.csproj
+# expects it.
+mkdir -p ../../cmake/build
+cp nativelibs/csharp_ext_linux_x64/libgrpc_csharp_ext.so ../../cmake/build
+
+dotnet build --configuration Release Grpc.Core
+# build HealthCheck to get hold of Google.Protobuf.dll assembly
+dotnet build --configuration Release Grpc.HealthCheck
+
+# copy Grpc assemblies to the unity package skeleton
+# TODO(jtattermusch): Add Grpc.Auth assembly and its dependencies
+cp Grpc.Core.Api/bin/Release/net45/Grpc.Core.Api.dll unitypackage/unitypackage_skeleton/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.dll
+cp Grpc.Core.Api/bin/Release/net45/Grpc.Core.Api.pdb unitypackage/unitypackage_skeleton/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.pdb
+cp Grpc.Core.Api/bin/Release/net45/Grpc.Core.Api.xml unitypackage/unitypackage_skeleton/Plugins/Grpc.Core.Api/lib/net45/Grpc.Core.Api.xml
+cp Grpc.Core/bin/Release/net45/Grpc.Core.dll unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/lib/net45/Grpc.Core.dll
+cp Grpc.Core/bin/Release/net45/Grpc.Core.pdb unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/lib/net45/Grpc.Core.pdb
+cp Grpc.Core/bin/Release/net45/Grpc.Core.xml unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/lib/net45/Grpc.Core.xml
+
+# copy desktop native libraries to the unity package skeleton
+cp nativelibs/csharp_ext_linux_x64/libgrpc_csharp_ext.so unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/linux/x64/libgrpc_csharp_ext.so
+cp nativelibs/csharp_ext_macos_x64/libgrpc_csharp_ext.dylib unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/osx/x64/grpc_csharp_ext.bundle
+cp nativelibs/csharp_ext_windows_x86/grpc_csharp_ext.dll unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/win/x86/grpc_csharp_ext.dll
+cp nativelibs/csharp_ext_windows_x64/grpc_csharp_ext.dll unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/win/x64/grpc_csharp_ext.dll
+
+# add Android and iOS native libraries
+cp nativelibs/csharp_ext_linux_android_armeabi-v7a/libgrpc_csharp_ext.so unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/android/armeabi-v7a/libgrpc_csharp_ext.so
+cp nativelibs/csharp_ext_linux_android_arm64-v8a/libgrpc_csharp_ext.so unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/android/arm64-v8a/libgrpc_csharp_ext.so
+cp nativelibs/csharp_ext_linux_android_x86/libgrpc_csharp_ext.so unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/android/x86/libgrpc_csharp_ext.so
+cp nativelibs/csharp_ext_macos_ios/libgrpc_csharp_ext.a unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/ios/libgrpc_csharp_ext.a
+cp nativelibs/csharp_ext_macos_ios/libgrpc.a unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/ios/libgrpc.a
+
+# add gRPC dependencies
+# TODO(jtattermusch): also include XMLdoc
+cp Grpc.Core/bin/Release/net45/System.Runtime.CompilerServices.Unsafe.dll unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.dll
+cp Grpc.Core/bin/Release/net45/System.Buffers.dll unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.dll
+cp Grpc.Core/bin/Release/net45/System.Memory.dll unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.dll
+
+# add Google.Protobuf
+# TODO(jtattermusch): also include XMLdoc
+cp Grpc.HealthCheck/bin/Release/net45/Google.Protobuf.dll unitypackage/unitypackage_skeleton/Plugins/Google.Protobuf/lib/net45/Google.Protobuf.dll
+
+# create a zipfile that will act as a Unity package
+pushd unitypackage/unitypackage_skeleton
+zip -r ../../grpc_unity_package.zip Plugins
+popd
+
+cp grpc_unity_package.zip ../../artifacts/grpc_unity_package.${UNITYPACKAGE_VERSION}.zip
diff --git a/src/csharp/docfx/generate_reference_docs.sh b/src/csharp/docfx/generate_reference_docs.sh
new file mode 100644
index 00000000..8e7fc068
--- /dev/null
+++ b/src/csharp/docfx/generate_reference_docs.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generates C# API docs using docfx inside docker.
+set -ex
+cd $(dirname $0)
+
+# cleanup temporary files
+rm -rf html obj grpc-gh-pages
+
+# generate into src/csharp/docfx/html directory
+cd ..
+docker run --rm -v "$(pwd)":/work -w /work/docfx --user "$(id -u):$(id -g)" -it tsgkadot/docker-docfx:latest docfx
+cd docfx
+
+# prepare a clone of "gh-pages" branch where the generated docs are stored
+GITHUB_USER="${USER}"
+git clone -b gh-pages -o upstream git@github.com:grpc/grpc.git grpc-gh-pages
+cd grpc-gh-pages
+git remote add origin "git@github.com:${GITHUB_USER}/grpc.git"
+
+# replace old generated docs by the ones we just generated
+rm -r csharp
+cp -r ../html csharp
+
+echo "Done. Go to src/csharp/docfx/grpc-gh-pages git repository and create a pull request to update the generated docs."
diff --git a/src/csharp/expand_dev_version.sh b/src/csharp/expand_dev_version.sh
new file mode 100644
index 00000000..714762af
--- /dev/null
+++ b/src/csharp/expand_dev_version.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Updates the GrpcSharpVersion property so that we can build
+# dev nuget packages differentiated by timestamp.
+
+set -e
+
+cd "$(dirname "$0")"
+
+DEV_DATETIME_SUFFIX=$(date -u "+%Y%m%d%H%M")
+# expand the -dev suffix to contain current timestamp
+sed -ibak "s/-dev<\/GrpcCsharpVersion>/-dev${DEV_DATETIME_SUFFIX}<\/GrpcCsharpVersion>/" build/dependencies.props
diff --git a/src/csharp/experimental/build_native_ext_for_android.sh b/src/csharp/experimental/build_native_ext_for_android.sh
new file mode 100644
index 00000000..2749d4e0
--- /dev/null
+++ b/src/csharp/experimental/build_native_ext_for_android.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script to crosscompile grpc_csharp_ext native extension for Android.
+
+set -ex
+
+cd "$(dirname "$0")/../../../cmake"
+
+mkdir -p build
+cd build
+
+# set to the location where Android SDK is installed
+# e.g. ANDROID_SDK_PATH="$HOME/Android/Sdk"
+
+# set to location where Android NDK is installed, usually a subfolder of Android SDK
+# to install the Android NKD, use the "sdkmanager" tool
+# e.g. ANDROID_NDK_PATH=${ANDROID_SDK_PATH}/ndk-bundle
+
+# set to location of the cmake executable from the Android SDK
+# to install cmake, use the "sdkmanager" tool
+# e.g. ANDROID_SDK_CMAKE=${ANDROID_SDK_PATH}/cmake/3.6.4111459/bin/cmake
+
+# ANDROID_ABI in ('arm64-v8a', 'armeabi-v7a')
+# e.g. ANDROID_ABI=armeabi-v7a
+
+# android-19 corresponds to Kitkat 4.4
+${ANDROID_SDK_CMAKE} ../.. \
+ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake" \
+ -DCMAKE_ANDROID_NDK="${ANDROID_NDK_PATH}" \
+ -DCMAKE_ANDROID_STL_TYPE=c++_static \
+ -DRUN_HAVE_POSIX_REGEX=0 \
+ -DRUN_HAVE_STD_REGEX=0 \
+ -DRUN_HAVE_STEADY_CLOCK=0 \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_PLATFORM=android-19 \
+ -DANDROID_ABI="${ANDROID_ABI}" \
+ -DANDROID_NDK="${ANDROID_NDK_PATH}" \
+ -DgRPC_XDS_USER_AGENT_IS_CSHARP=ON
+
+make -j4 grpc_csharp_ext
diff --git a/src/csharp/experimental/build_native_ext_for_ios.sh b/src/csharp/experimental/build_native_ext_for_ios.sh
new file mode 100644
index 00000000..5afa071f
--- /dev/null
+++ b/src/csharp/experimental/build_native_ext_for_ios.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script to crosscompile grpc_csharp_ext native extension for iOS.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Usage: build
+function build {
+ SDK="$1"
+ ARCH="$2"
+
+ PATH_AR="$(xcrun --sdk $SDK --find ar)"
+ PATH_CC="$(xcrun --sdk $SDK --find clang)"
+ PATH_CXX="$(xcrun --sdk $SDK --find clang++)"
+
+ CPPFLAGS="-O2 -Wframe-larger-than=16384 -arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path) -mios-version-min=9.0 -DPB_NO_PACKED_STRUCTS=1 -DBORINGSSL_PREFIX=GRPC -Isrc/boringssl"
+ LDFLAGS="-arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path) -Wl,ios_version_min=9.0"
+
+ # TODO(jtattermusch): Ideally we'd be setting build defines that correspond to using cmake's
+ # gRPC_XDS_USER_AGENT_IS_CSHARP option here, but since using XDS with C# on iOS is unlikely
+ # and gRPC C#'s support of iOS is only experimental, it's fair to skip that for now
+ # (which will result in XDS user agent language being "not specified" and that's ok
+ # since there are other circumstances in which it isn't set).
+ # TODO(jtattermusch): revisit the build arguments
+ make -j4 static_csharp \
+ VALID_CONFIG_ios_$ARCH="1" \
+ CC_ios_$ARCH="$PATH_CC" \
+ CXX_ios_$ARCH="$PATH_CXX" \
+ LD_ios_$ARCH="$PATH_CC" \
+ LDXX_ios_$ARCH="$PATH_CXX" \
+ CPPFLAGS_ios_$ARCH="$CPPFLAGS" \
+ LDFLAGS_ios_$ARCH="$LDFLAGS" \
+ DEFINES_ios_$ARCH="NDEBUG" \
+ CONFIG="ios_$ARCH"
+}
+
+# Usage: fatten
+function fatten {
+ LIB_NAME="$1"
+
+ mkdir -p libs/ios
+ lipo -create -output libs/ios/lib$LIB_NAME.a \
+ libs/ios_armv7/lib$LIB_NAME.a \
+ libs/ios_arm64/lib$LIB_NAME.a \
+ libs/ios_x86_64/lib$LIB_NAME.a
+}
+
+build iphoneos armv7
+build iphoneos arm64
+build iphonesimulator x86_64
+
+fatten grpc
+fatten grpc_csharp_ext
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
new file mode 100644
index 00000000..c7c45a77
--- /dev/null
+++ b/src/csharp/generate_proto_csharp.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Regenerates gRPC service stubs from proto files.
+set -e
+cd $(dirname $0)/../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_csharp_plugin
+
+EXAMPLES_DIR=src/csharp/Grpc.Examples
+HEALTHCHECK_DIR=src/csharp/Grpc.HealthCheck
+REFLECTION_DIR=src/csharp/Grpc.Reflection
+TESTING_DIR=src/csharp/Grpc.IntegrationTesting
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
+ -I src/proto src/proto/math/math.proto
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
+ -I src/proto src/proto/grpc/health/v1/health.proto
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$REFLECTION_DIR --grpc_out=$REFLECTION_DIR \
+ -I src/proto src/proto/grpc/reflection/v1alpha/reflection.proto
+
+# Put grpc/core/stats.proto in a subdirectory to avoid collision with grpc/testing/stats.proto
+mkdir -p $TESTING_DIR/CoreStats
+$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR/CoreStats --grpc_out=$TESTING_DIR/CoreStats \
+ -I src/proto src/proto/grpc/core/stats.proto
+
+# TODO(jtattermusch): following .proto files are a bit broken and import paths
+# don't match the package names. Setting -I to the correct value src/proto
+# breaks the code generation.
+$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
+ -I . src/proto/grpc/testing/{control,echo_messages,empty,empty_service,messages,metrics,payloads,benchmark_service,report_qps_scenario_service,worker_service,stats,test}.proto
diff --git a/src/objective-c/format-all-comments.sh b/src/objective-c/format-all-comments.sh
new file mode 100644
index 00000000..a665b7a8
--- /dev/null
+++ b/src/objective-c/format-all-comments.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+find . -type f -name "*.h" ! -path "*/Pods/*" ! -path "./generated_libraries/*" ! -path "./examples/*" ! -path "./tests/*" | xargs ./change-comments.py
diff --git a/src/objective-c/tests/build_one_example.sh b/src/objective-c/tests/build_one_example.sh
new file mode 100644
index 00000000..762af5e0
--- /dev/null
+++ b/src/objective-c/tests/build_one_example.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+# Params:
+# EXAMPLE_PATH - directory of the example
+# SCHEME - scheme of the example, used by xcodebuild
+
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
+TEST_PATH=$(cd "$(dirname $0)" > /dev/null ; pwd)
+
+cd `dirname $0`/../../..
+
+cd $EXAMPLE_PATH
+
+# clean the directory
+rm -rf Pods
+rm -rf *.xcworkspace
+rm -f Podfile.lock
+
+pod install | $TEST_PATH/verbose_time.sh
+
+set -o pipefail
+XCODEBUILD_FILTER='(^CompileC |^Ld |^.*clang |^ *cd |^ *export |^Libtool |^.*libtool |^CpHeader |^ *builtin-copy )'
+if [ "$SCHEME" == "tvOS-sample" ]; then
+ xcodebuild \
+ build \
+ -workspace *.xcworkspace \
+ -scheme $SCHEME \
+ -destination generic/platform=tvOS \
+ -derivedDataPath Build/Build \
+ CODE_SIGN_IDENTITY="" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO \
+ | $TEST_PATH/verbose_time.sh \
+ | egrep -v "$XCODEBUILD_FILTER" \
+ | egrep -v "^$" -
+else
+ xcodebuild \
+ build \
+ -workspace *.xcworkspace \
+ -scheme $SCHEME \
+ -destination generic/platform=iOS \
+ -derivedDataPath Build/Build \
+ CODE_SIGN_IDENTITY="" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO \
+ | $TEST_PATH/verbose_time.sh \
+ | egrep -v "$XCODEBUILD_FILTER" \
+ | egrep -v "^$" -
+fi
+
diff --git a/src/objective-c/tests/build_one_example_bazel.sh b/src/objective-c/tests/build_one_example_bazel.sh
new file mode 100644
index 00000000..b547ac15
--- /dev/null
+++ b/src/objective-c/tests/build_one_example_bazel.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+# Params:
+# EXAMPLE_PATH - directory of the example
+# SCHEME - scheme of the example, used by xcodebuild
+
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
+cd `dirname $0`/../../..
+
+cd $EXAMPLE_PATH/..
+
+if [ "$SCHEME" == "watchOS-sample-WatchKit-App" ]; then
+ SCHEME="watchOS-sample watchOS-sample-watchApp"
+fi
+../../../tools/bazel build $SCHEME
diff --git a/src/objective-c/tests/build_tests.sh b/src/objective-c/tests/build_tests.sh
new file mode 100644
index 00000000..95d17cd7
--- /dev/null
+++ b/src/objective-c/tests/build_tests.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
+cd $(dirname $0)
+
+hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; }
+hash xcodebuild 2>/dev/null || {
+ echo >&2 "XCode command-line tools need to be installed."
+ exit 1
+}
+
+# clean pod cache and prior pods
+rm -Rf Pods Podfile.lock Tests.xcworkspace
+rm -f RemoteTestClient/*.{h,m}
+pod cache clean --all
+
+echo "TIME: $(date)"
+pod install --verbose | ./verbose_time.sh
+
+# verify pod header installation
+if [ -d "./Pods/Headers/Public/gRPC-Core/grpc/impl/codegen" ]
+then
+ echo "grpc/impl/codegen/ has been imported."
+ number_of_files=$(find Pods/Headers/Public/gRPC-Core/grpc/impl/codegen -name "*.h" | wc -l)
+ echo "The number of files in Pods/Headers/Public/gRPC-Core/grpc/impl/codegen/ is $number_of_files"
+else
+ echo "Error: grpc/impl/codegen/ hasn't been imported."
+fi
diff --git a/src/objective-c/tests/examples_build_test.sh b/src/objective-c/tests/examples_build_test.sh
new file mode 100644
index 00000000..92ebaacc
--- /dev/null
+++ b/src/objective-c/tests/examples_build_test.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script is used after a release to verify the released pods are working appropriately
+
+set -ex
+
+SCHEME=HelloWorld EXAMPLE_PATH=examples/objective-c/helloworld ./build_one_example.sh
+SCHEME=RouteGuideClient EXAMPLE_PATH=examples/objective-c/route_guide ./build_one_example.sh
+SCHEME=AuthSample EXAMPLE_PATH=examples/objective-c/auth_sample ./build_one_example.sh
diff --git a/src/objective-c/tests/run_one_test.sh b/src/objective-c/tests/run_one_test.sh
new file mode 100644
index 00000000..53a813da
--- /dev/null
+++ b/src/objective-c/tests/run_one_test.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+cd $(dirname $0)
+
+BAZEL=../../../tools/bazel
+
+INTEROP=../../../bazel-out/darwin-fastbuild/bin/test/cpp/interop/interop_server
+
+[ -d Tests.xcworkspace ] || {
+ ./build_tests.sh
+}
+
+[ -f $INTEROP ] || {
+ $BAZEL build //test/cpp/interop:interop_server
+}
+
+[ -z "$(ps aux |egrep 'port_server\.py.*-p\s32766')" ] && {
+ echo >&2 "Can't find the port server. Start port server with tools/run_tests/start_port_server.py."
+ exit 1
+}
+
+PLAIN_PORT=$(curl localhost:32766/get)
+TLS_PORT=$(curl localhost:32766/get)
+
+$INTEROP --port=$PLAIN_PORT --max_send_message_size=8388608 &
+$INTEROP --port=$TLS_PORT --max_send_message_size=8388608 --use_tls &
+
+# Create loopback aliases for iOS performance tests
+if [ $SCHEME == PerfTests ] || [ $SCHEME == PerfTestsPosix ]; then
+for ((i=2;i<11;i++))
+do
+ sudo ifconfig lo0 alias 127.0.0.$i up
+done
+fi
+
+function finish {
+ if [ $SCHEME == PerfTests ] || [ $SCHEME == PerfTestsPosix ]; then
+ for ((i=2;i<11;i++))
+ do
+ sudo ifconfig lo0 -alias 127.0.0.$i
+ done
+ fi
+ kill -9 `jobs -p`
+ echo "EXIT TIME: $(date)"
+}
+trap finish EXIT
+
+set -o pipefail
+
+XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )'
+
+if [ -z $PLATFORM ]; then
+DESTINATION='name=iPhone 8'
+elif [ $PLATFORM == ios ]; then
+DESTINATION='name=iPhone 8'
+elif [ $PLATFORM == macos ]; then
+DESTINATION='platform=macOS'
+elif [ $PLATFORM == tvos ]; then
+DESTINATION='platform=tvOS Simulator,name=Apple TV'
+fi
+
+
+xcodebuild \
+ -workspace Tests.xcworkspace \
+ -scheme $SCHEME \
+ -destination "$DESTINATION" \
+ HOST_PORT_LOCALSSL=localhost:$TLS_PORT \
+ HOST_PORT_LOCAL=localhost:$PLAIN_PORT \
+ HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
+ GCC_OPTIMIZATION_LEVEL=s \
+ test \
+ | ./verbose_time.sh \
+ | egrep -v "$XCODEBUILD_FILTER" \
+ | egrep -v '^$' \
+ | egrep -v "(GPBDictionary|GPBArray)" -
+
diff --git a/src/objective-c/tests/run_one_test_bazel.sh b/src/objective-c/tests/run_one_test_bazel.sh
new file mode 100644
index 00000000..09da7bfb
--- /dev/null
+++ b/src/objective-c/tests/run_one_test_bazel.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+# TODO(tonyzhehaolu):
+# For future use when Xcode is upgraded and tvos_unit_test is fully functional
+
+set -ev
+
+cd $(dirname $0)
+
+BAZEL=../../../tools/bazel
+
+INTEROP=../../../bazel-out/darwin-fastbuild/bin/test/cpp/interop/interop_server
+
+[ -d Tests.xcworkspace ] || {
+ ./build_tests.sh
+}
+
+[ -f $INTEROP ] || {
+ BAZEL build //test/cpp/interop:interop_server
+}
+
+[ -z "$(ps aux |egrep 'port_server\.py.*-p\s32766')" ] && {
+ echo >&2 "Can't find the port server. Start port server with tools/run_tests/start_port_server.py."
+ exit 1
+}
+
+PLAIN_PORT=$(curl localhost:32766/get)
+TLS_PORT=$(curl localhost:32766/get)
+
+$INTEROP --port=$PLAIN_PORT --max_send_message_size=8388608 &
+$INTEROP --port=$TLS_PORT --max_send_message_size=8388608 --use_tls &
+
+trap 'kill -9 `jobs -p` ; echo "EXIT TIME: $(date)"' EXIT
+
+../../../tools/bazel run $SCHEME
diff --git a/src/objective-c/tests/run_plugin_option_tests.sh b/src/objective-c/tests/run_plugin_option_tests.sh
new file mode 100644
index 00000000..8f7a6a10
--- /dev/null
+++ b/src/objective-c/tests/run_plugin_option_tests.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+cd $(dirname $0)
+
+# Run the tests server.
+
+ROOT_DIR=../../..
+BAZEL=$ROOT_DIR/tools/bazel
+PROTOC=$ROOT_DIR/bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=$ROOT_DIR/bazel-bin/src/compiler/grpc_objective_c_plugin
+RUNTIME_IMPORT_PREFIX=prefix/dir/
+
+[ -f $PROTOC ] && [ -f $PLUGIN ] || {
+ BAZEL build @com_google_protobuf//:protoc //src/compiler:grpc_objective_c_plugin
+}
+
+rm -rf RemoteTestClient/*pb*
+
+$PROTOC \
+ --plugin=protoc-gen-grpc=$PLUGIN \
+ --objc_out=RemoteTestClient \
+ --grpc_out=grpc_local_import_prefix=$RUNTIME_IMPORT_PREFIX,runtime_import_prefix=$RUNTIME_IMPORT_PREFIX:RemoteTestClient \
+ -I $ROOT_DIR \
+ -I ../../../third_party/protobuf/src \
+ $ROOT_DIR/src/objective-c/examples/RemoteTestClient/*.proto
+
+# Verify the "runtime_import_prefix" option
+# Verify the output proto filename
+[ -e ./RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m ] || {
+ echo >&2 "protoc outputs wrong filename."
+ exit 1
+}
+
+# Verify paths of protobuf WKTs in generated code contain runtime import prefix.
+[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m |
+ egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"'GPBEmpty\.pbobjc\.h'`" ] || {
+ echo >&2 "protoc generated import with wrong filename."
+ exit 1
+}
+
+# Verify paths of non WKTs protos in generated code don't contain runtime import prefix.
+[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m |
+ egrep '.*\Messages.pbobjc.h"$' |
+ egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"`" ] && {
+ echo >&2 "protoc generated import with wrong filename."
+ exit 1
+}
+
+# Verify the "grpc_local_import_directory" option
+# Verify system files are imported in a "local" way in header files.
+[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.h |
+ egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"'/ProtoRPC/.*\.h'`"] || {
+ echo >&2 "grpc system files should be imported with full paths."
+}
+
+# Verify system files are imported in a "local" way in source files.
+[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m |
+ egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"'/ProtoRPC/.*\.h'`"] || {
+ echo >&2 "grpc system files should be imported with full paths."
+}
+
+# Run one extra command to clear $? before exiting the script to prevent
+# failing even when tests pass.
+echo "Plugin option tests passed."
diff --git a/src/objective-c/tests/run_plugin_tests.sh b/src/objective-c/tests/run_plugin_tests.sh
new file mode 100644
index 00000000..606aea84
--- /dev/null
+++ b/src/objective-c/tests/run_plugin_tests.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+cd $(dirname $0)
+
+# Run the tests server.
+
+ROOT_DIR=../../..
+BAZEL=$ROOT_DIR/tools/bazel
+PROTOC=$ROOT_DIR/bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=$ROOT_DIR/bazel-bin/src/compiler/grpc_objective_c_plugin
+
+[ -f $PROTOC ] && [ -f $PLUGIN ] || {
+ BAZEL build @com_google_protobuf//:protoc //src/compiler:grpc_objective_c_plugin
+}
+
+rm -rf PluginTest/*pb*
+
+$PROTOC \
+ --plugin=protoc-gen-grpc=$PLUGIN \
+ --objc_out=PluginTest \
+ --grpc_out=PluginTest \
+ -I PluginTest \
+ -I ../../../third_party/protobuf/src \
+ PluginTest/*.proto
+
+# Verify the output proto filename
+[ -e ./PluginTest/TestDashFilename.pbrpc.h ] || {
+ echo >&2 "protoc outputs wrong filename."
+ exit 1
+}
+
+# TODO(jtattermusch): rewrite the tests to make them more readable.
+# Also, the way they are written, they need one extra command to run in order to
+# clear $? after they run (see end of this script)
+# Verify names of the imported protos in generated code don't contain dashes.
+[ "`cat PluginTest/TestDashFilename.pbrpc.h |
+ egrep '#import ".*\.pb(objc|rpc)\.h"$' |
+ egrep '-'`" ] && {
+ echo >&2 "protoc generated import with wrong filename."
+ exit 1
+}
+[ "`cat PluginTest/TestDashFilename.pbrpc.m |
+ egrep '#import ".*\.pb(objc|rpc)\.h"$' |
+ egrep '-'`" ] && {
+ echo >&2 "protoc generated import with wrong filename."
+ exit 1
+}
+
+# Run one extra command to clear $? before exiting the script to prevent
+# failing even when tests pass.
+echo "Plugin tests passed."
diff --git a/src/objective-c/tests/verbose_time.sh b/src/objective-c/tests/verbose_time.sh
new file mode 100644
index 00000000..05926cae
--- /dev/null
+++ b/src/objective-c/tests/verbose_time.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!/bin/bash
+
+while IFS= read -r line; do
+ echo "$(date) - $line"
+done
diff --git a/src/php/bin/build_all_docker_images.sh b/src/php/bin/build_all_docker_images.sh
new file mode 100644
index 00000000..77e2df7a
--- /dev/null
+++ b/src/php/bin/build_all_docker_images.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)/../../..
+
+ALL_IMAGES=( grpc-ext grpc-src alpine centos7 php-src php-future php-zts
+ fork-support i386 php8 )
+
+if [[ "$1" == "--cmds" ]]; then
+ for arg in "${ALL_IMAGES[@]}"
+ do
+ echo "docker build -t grpc-php/$arg -f ./src/php/docker/$arg/Dockerfile ."
+ done
+ exit 0
+fi
+
+if [[ $# -eq 0 ]]; then
+ lst=("${ALL_IMAGES[@]}")
+else
+ lst=("$@")
+fi
+
+set -x
+for arg in "${lst[@]}"
+do
+ docker build -t grpc-php/"$arg" -f ./src/php/docker/"$arg"/Dockerfile .
+done
diff --git a/src/php/bin/determine_extension_dir.sh b/src/php/bin/determine_extension_dir.sh
new file mode 100644
index 00000000..66989816
--- /dev/null
+++ b/src/php/bin/determine_extension_dir.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+default_extension_dir=$(php-config --extension-dir)
+if [ ! -e $default_extension_dir/grpc.so ]; then
+ # the grpc extension is not found in the default PHP extension dir
+ # try the source modules directory
+ module_dir=$(pwd)/../ext/grpc/modules
+ if [ ! -e $module_dir/grpc.so ]; then
+ echo "Please run 'phpize && ./configure && make' from ext/grpc first"
+ exit 1
+ fi
+ # sym-link in system supplied extensions
+ for f in $default_extension_dir/*.so; do
+ ln -s $f $module_dir/$(basename $f) &> /dev/null || true
+ done
+ extension_dir="-d extension_dir=${module_dir} -d extension=grpc.so"
+else
+ extension_dir="-d extension=grpc.so"
+fi
diff --git a/src/php/bin/generate_proto_php.sh b/src/php/bin/generate_proto_php.sh
new file mode 100644
index 00000000..e5013537
--- /dev/null
+++ b/src/php/bin/generate_proto_php.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)/../../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_php_plugin
+
+$PROTOC --proto_path=src/proto/math \
+ --php_out=src/php/tests/generated_code \
+ --grpc_out=generate_server:src/php/tests/generated_code \
+ --plugin=$PLUGIN \
+ src/proto/math/math.proto
+
+# replace the Empty message with EmptyMessage
+# because Empty is a PHP reserved word
+output_file=$(mktemp)
+sed 's/message Empty/message EmptyMessage/g' \
+ src/proto/grpc/testing/empty.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/empty.proto
+sed 's/grpc\.testing\.Empty/grpc\.testing\.EmptyMessage/g' \
+ src/proto/grpc/testing/test.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/test.proto
+
+# interop test protos
+$PROTOC --proto_path=. \
+ --php_out=src/php/tests/interop \
+ --grpc_out=generate_server:src/php/tests/interop \
+ --plugin=$PLUGIN \
+ src/proto/grpc/testing/messages.proto \
+ src/proto/grpc/testing/empty.proto \
+ src/proto/grpc/testing/test.proto
+
+# change it back
+sed 's/message EmptyMessage/message Empty/g' \
+ src/proto/grpc/testing/empty.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/empty.proto
+sed 's/grpc\.testing\.EmptyMessage/grpc\.testing\.Empty/g' \
+ src/proto/grpc/testing/test.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/test.proto
diff --git a/src/php/bin/interop_client.sh b/src/php/bin/interop_client.sh
new file mode 100644
index 00000000..0aa6a66f
--- /dev/null
+++ b/src/php/bin/interop_client.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+source ./determine_extension_dir.sh
+cd ../tests/interop
+php $extension_dir -d max_execution_time=300 \
+ interop_client.php $@ 1>&2
diff --git a/src/php/bin/interop_server.sh b/src/php/bin/interop_server.sh
new file mode 100644
index 00000000..64f031f8
--- /dev/null
+++ b/src/php/bin/interop_server.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+source ./determine_extension_dir.sh
+cd ../tests/interop
+php $extension_dir -d max_execution_time=300 \
+ interop_server.php $@ 1>&2
diff --git a/src/php/bin/php_extension_to_php_doc.sh b/src/php/bin/php_extension_to_php_doc.sh
new file mode 100644
index 00000000..59f80a4a
--- /dev/null
+++ b/src/php/bin/php_extension_to_php_doc.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+if ! command -v awk > /dev/null; then
+ >&2 echo "ERROR: 'awk' not installed"
+ exit 1
+fi
+
+cd $(dirname $0)
+
+COMMAND="${1:-}"
+
+# parse class and methods
+for FILENAME in call_credentials.c call.c channel.c channel_credentials.c \
+ server_credentials.c server.c timeval.c ; do
+ CLASS_NAME=$(awk -F _ '{for(i=1; i<=NF; i++) printf "%s", toupper(substr($i,1,1)) substr($i, 2);}' \
+ <<< "${FILENAME%.*}")
+ if [[ "$COMMAND" == "generate" ]]; then
+ echo Generating lib/Grpc/$CLASS_NAME.php ...
+ awk -f php_extension_doxygen_filter.awk ../ext/grpc/$FILENAME \
+ > ../lib/Grpc/$CLASS_NAME.php
+ elif [[ "$COMMAND" == "cleanup" ]]; then
+ rm ../lib/Grpc/$CLASS_NAME.php
+ else
+ >&2 echo "Missing or wrong command. Usage: '$(basename $0) '"
+ exit 1
+ fi
+done
+
+# parse constants
+if [[ "$COMMAND" == "generate" ]]; then
+ echo Generating lib/Grpc/Constants.php ...
+ awk -f php_extension_doxygen_filter.awk ../ext/grpc/php_grpc.c \
+ > ../lib/Grpc/Constants.php
+elif [[ "$COMMAND" == "cleanup" ]]; then
+ rm ../lib/Grpc/Constants.php
+fi
diff --git a/src/php/bin/run_all_docker_images.sh b/src/php/bin/run_all_docker_images.sh
new file mode 100644
index 00000000..a1034581
--- /dev/null
+++ b/src/php/bin/run_all_docker_images.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)/../../..
+
+ALL_IMAGES=( grpc-ext grpc-src alpine centos7 php-src php-future php-zts
+ fork-support i386 php8 )
+
+if [[ "$1" == "--cmds" ]]; then
+ for arg in "${ALL_IMAGES[@]}"
+ do
+ echo "docker run -it --rm grpc-php/$arg"
+ done
+ exit 0
+fi
+
+if [[ $# -eq 0 ]]; then
+ lst=("${ALL_IMAGES[@]}")
+else
+ lst=("$@")
+fi
+
+set -x
+for arg in "${lst[@]}"
+do
+ docker run -it --rm grpc-php/"$arg"
+done
diff --git a/src/php/bin/run_gen_code_test.sh b/src/php/bin/run_gen_code_test.sh
new file mode 100644
index 00000000..93308a86
--- /dev/null
+++ b/src/php/bin/run_gen_code_test.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+source ./determine_extension_dir.sh
+export GRPC_TEST_HOST=localhost:50051
+export GRPC_TEST_INSECURE_HOST=localhost:50052
+
+php $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \
+ ../tests/generated_code/GeneratedCodeTest.php
+php $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \
+ ../tests/generated_code/GeneratedCodeWithCallbackTest.php
diff --git a/src/php/bin/run_php_cs_fixer.sh b/src/php/bin/run_php_cs_fixer.sh
new file mode 100644
index 00000000..afdb57bb
--- /dev/null
+++ b/src/php/bin/run_php_cs_fixer.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+command -v php-cs-fixer > /dev/null || {
+ echo "Cannot find php-cs-fixer. Exiting..."
+ exit 1
+}
+cd $(dirname $0)/..
+php-cs-fixer fix lib/Grpc || true
+php-cs-fixer fix tests/generated_code || true
+php-cs-fixer fix tests/interop || true
+php-cs-fixer fix tests/unit_tests || true
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
new file mode 100644
index 00000000..0408a91a
--- /dev/null
+++ b/src/php/bin/run_tests.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Loads the local shared library, and runs all of the test cases in tests/
+# against it
+set -ex
+cd $(dirname $0)/../../..
+root=$(pwd)
+cd src/php/bin
+source ./determine_extension_dir.sh
+# in some jenkins macos machine, somehow the PHP build script can't find libgrpc.dylib
+export DYLD_LIBRARY_PATH=$root/libs/$CONFIG
+$(which php) $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \
+ --exclude-group persistent_list_bound_tests ../tests/unit_tests
+
+for arg in "$@"
+do
+ if [[ "$arg" == "--skip-persistent-channel-tests" ]]; then
+ SKIP_PERSISTENT_CHANNEL_TESTS=true
+ elif [[ "$arg" == "--ignore-valgrind-undef-errors" ]]; then
+ VALGRIND_UNDEF_VALUE_ERRORS="--undef-value-errors=no"
+ fi
+done
+
+if [[ "$SKIP_PERSISTENT_CHANNEL_TESTS" != "true" ]]; then
+ $(which php) $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \
+ ../tests/unit_tests/PersistentChannelTests
+fi
+
+export ZEND_DONT_UNLOAD_MODULES=1
+export USE_ZEND_ALLOC=0
+# Detect whether valgrind is executable
+if [ -x "$(command -v valgrind)" ]; then
+ $(which valgrind) --error-exitcode=10 --leak-check=yes \
+ $VALGRIND_UNDEF_VALUE_ERRORS \
+ $(which php) $extension_dir -d max_execution_time=300 \
+ ../tests/MemoryLeakTest/MemoryLeakTest.php
+fi
diff --git a/src/php/bin/run_xds_client.sh b/src/php/bin/run_xds_client.sh
new file mode 100644
index 00000000..82809a34
--- /dev/null
+++ b/src/php/bin/run_xds_client.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# This script is being launched from the run_xds_tests.py runner and is
+# responsible for managing child PHP processes.
+
+cleanup () {
+ echo "Trapped SIGTERM. Cleaning up..."
+ set -x
+ kill -9 $PID1
+ kill -9 $PID2
+ running=false
+ set +x
+}
+
+trap cleanup SIGTERM
+
+set -e
+cd $(dirname $0)/../../..
+root=$(pwd)
+
+# tmp_file1 contains the list of RPCs (and their spec) the parent PHP
+# process want executed
+tmp_file1=$(mktemp)
+# tmp_file2 contains the RPC result of each key initiated
+tmp_file2=$(mktemp)
+
+set -x
+# This is the PHP parent process, who is primarily responding to the
+# run_xds_tests.py runner's stats requests
+php -d extension=grpc.so -d extension=pthreads.so \
+ src/php/tests/interop/xds_client.php $1 $2 $3 $4 $5 $6 \
+ --tmp_file1=$tmp_file1 --tmp_file2=$tmp_file2 &
+PID1=$!
+
+# This script watches RPCs written to tmp_file1, spawn off more PHP
+# child processes to execute them, and writes the result to tmp_file2
+python3 -u src/php/bin/xds_manager.py \
+ --tmp_file1=$tmp_file1 --tmp_file2=$tmp_file2 \
+ --bootstrap_path=$GRPC_XDS_BOOTSTRAP &
+PID2=$!
+set +x
+
+# This will be killed by a SIGTERM signal from the run_xds_tests.py
+# runner
+running=true
+while $running
+do
+ sleep 1
+done
diff --git a/src/php/bin/stress_client.sh b/src/php/bin/stress_client.sh
new file mode 100644
index 00000000..4022ad86
--- /dev/null
+++ b/src/php/bin/stress_client.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+cd $(dirname $0)
+source ./determine_extension_dir.sh
+php $extension_dir -d max_execution_time=300 \
+ ../tests/interop/stress_client.php $@ 1>&2
diff --git a/src/ruby/end2end/gen_protos.sh b/src/ruby/end2end/gen_protos.sh
new file mode 100644
index 00000000..be6b4981
--- /dev/null
+++ b/src/ruby/end2end/gen_protos.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+grpc_tools_ruby_protoc -I protos --ruby_out=lib --grpc_out=lib protos/echo.proto protos/client_control.proto
diff --git a/src/ruby/pb/generate_proto_ruby.sh b/src/ruby/pb/generate_proto_ruby.sh
new file mode 100644
index 00000000..8cbb4292
--- /dev/null
+++ b/src/ruby/pb/generate_proto_ruby.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Regenerates gRPC service stubs from proto files.
+set -e
+cd $(dirname $0)/../../..
+
+# protoc and grpc_*_plugin binaries can be obtained by running
+# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
+PROTOC=bazel-bin/external/com_google_protobuf/protoc
+PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_ruby_plugin
+
+$PROTOC -I src/proto src/proto/grpc/health/v1/health.proto \
+ --grpc_out=src/ruby/pb \
+ --ruby_out=src/ruby/pb \
+ --plugin=$PLUGIN
+
+$PROTOC -I . \
+ src/proto/grpc/testing/{messages,test,empty}.proto \
+ --grpc_out=src/ruby/pb \
+ --ruby_out=src/ruby/pb \
+ --plugin=$PLUGIN
+
+$PROTOC -I . \
+ src/proto/grpc/core/stats.proto \
+ --grpc_out=src/ruby/qps \
+ --ruby_out=src/ruby/qps \
+ --plugin=$PLUGIN
+
+$PROTOC -I . \
+ src/proto/grpc/testing/{messages,payloads,stats,benchmark_service,report_qps_scenario_service,worker_service,control}.proto \
+ --grpc_out=src/ruby/qps \
+ --ruby_out=src/ruby/qps \
+ --plugin=$PLUGIN
+
+$PROTOC -I src/proto/math src/proto/math/math.proto \
+ --grpc_out=src/ruby/bin \
+ --ruby_out=src/ruby/bin \
+ --plugin=$PLUGIN
diff --git a/test/core/end2end/end2end_test.sh b/test/core/end2end/end2end_test.sh
new file mode 100644
index 00000000..6b23d848
--- /dev/null
+++ b/test/core/end2end/end2end_test.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Test runner for end2end tests from bazel
+
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+if [ -n "$3" ]
+ then
+ export GRPC_POLL_STRATEGY=$3
+fi
+"$1" "$2"
diff --git a/test/core/http/python_wrapper.sh b/test/core/http/python_wrapper.sh
new file mode 100644
index 00000000..9ed6e329
--- /dev/null
+++ b/test/core/http/python_wrapper.sh
@@ -0,0 +1 @@
+../../../tools/distrib/python_wrapper.sh
\ No newline at end of file
diff --git a/test/core/iomgr/ios/CFStreamTests/build_and_run_tests.sh b/test/core/iomgr/ios/CFStreamTests/build_and_run_tests.sh
new file mode 100644
index 00000000..3c2b1a32
--- /dev/null
+++ b/test/core/iomgr/ios/CFStreamTests/build_and_run_tests.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+set -o pipefail
+
+cd "$(dirname "$0")"
+
+echo "TIME: $(date)"
+
+./build_tests.sh
+
+echo "TIME: $(date)"
+
+XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )'
+
+xcodebuild \
+ -workspace CFStreamTests.xcworkspace \
+ -scheme CFStreamTests \
+ -destination name="iPhone 8" \
+ test \
+ | grep -E -v "$XCODEBUILD_FILTER" \
+ | grep -E -v '^$' \
+ | grep -E -v "(GPBDictionary|GPBArray)" -
+
+echo "TIME: $(date)"
+
+xcodebuild \
+ -workspace CFStreamTests.xcworkspace \
+ -scheme CFStreamTests_Asan \
+ -destination name="iPhone 8" \
+ test \
+ | grep -E -v "$XCODEBUILD_FILTER" \
+ | grep -E -v '^$' \
+ | grep -E -v "(GPBDictionary|GPBArray)" -
+
+echo "TIME: $(date)"
+
+xcodebuild \
+ -workspace CFStreamTests.xcworkspace \
+ -scheme CFStreamTests_Tsan \
+ -destination name="iPhone 8" \
+ test \
+ | grep -E -v "$XCODEBUILD_FILTER" \
+ | grep -E -v '^$' \
+ | grep -E -v "(GPBDictionary|GPBArray)" -
+
+echo "TIME: $(date)"
+
+xcodebuild \
+ -workspace CFStreamTests.xcworkspace \
+ -scheme CFStreamTests_Msan \
+ -destination name="iPhone 8" \
+ test \
+ | grep -E -v "$XCODEBUILD_FILTER" \
+ | grep -E -v '^$' \
+ | grep -E -v "(GPBDictionary|GPBArray)" -
diff --git a/test/core/iomgr/ios/CFStreamTests/build_tests.sh b/test/core/iomgr/ios/CFStreamTests/build_tests.sh
new file mode 100644
index 00000000..f4262456
--- /dev/null
+++ b/test/core/iomgr/ios/CFStreamTests/build_tests.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -ev
+
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
+cd "$(dirname "$0")"
+
+hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; }
+hash xcodebuild 2>/dev/null || {
+ echo >&2 "XCode command-line tools need to be installed."
+ exit 1
+}
+
+# clean up pod cache and existing pods
+rm -Rf Pods Podfile.lock CFStreamTests.xcworkspace
+pod cache clean --all
+
+echo "TIME: $(date)"
+pod install --verbose
+
+# ios-test-cfstream-tests flakes sometimes because of missing files in gRPC-Core,
+# add some log to help find out the root cause.
+# TODO(yulinliang): Delete it after solving the issue.
+if [ -d "./Pods/Headers/Public/gRPC-Core/grpc/impl/codegen" ]
+then
+ echo "grpc/impl/codegen/ has been imported."
+ number_of_files=$(find Pods/Headers/Public/gRPC-Core/grpc/impl/codegen -name "*.h" | wc -l)
+ echo "The number of files in Pods/Headers/Public/gRPC-Core/grpc/impl/codegen/ is $number_of_files"
+else
+ echo "Error: grpc/impl/codegen/ hasn't been imported."
+fi
+
diff --git a/test/core/util/fuzzer_one_entry_runner.sh b/test/core/util/fuzzer_one_entry_runner.sh
new file mode 100644
index 00000000..7c471afc
--- /dev/null
+++ b/test/core/util/fuzzer_one_entry_runner.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Test runner for fuzzer tests from bazel
+
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"$1" "$2"
diff --git a/test/core/util/run_with_poller.sh b/test/core/util/run_with_poller.sh
new file mode 100644
index 00000000..382a63e8
--- /dev/null
+++ b/test/core/util/run_with_poller.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+export GRPC_POLL_STRATEGY=$1
+shift
+"$@"
diff --git a/test/cpp/codegen/run_golden_file_test.sh b/test/cpp/codegen/run_golden_file_test.sh
new file mode 100644
index 00000000..8fe801c8
--- /dev/null
+++ b/test/cpp/codegen/run_golden_file_test.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eux
+
+GENERATED_PB_H_DIR="${TEST_SRCDIR}/com_github_grpc_grpc/test/cpp/codegen/"
+test/cpp/codegen/golden_file_test --generated_file_path="$GENERATED_PB_H_DIR"
diff --git a/test/cpp/ios/build_and_run_tests.sh b/test/cpp/ios/build_and_run_tests.sh
new file mode 100644
index 00000000..7d674fcb
--- /dev/null
+++ b/test/cpp/ios/build_and_run_tests.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l c++
+
+set -ev
+
+cd "$(dirname "$0")"
+
+echo "TIME: $(date)"
+
+./build_tests.sh | ./verbose_time.sh
+
+echo "TIME: $(date)"
+
+set -o pipefail
+
+XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )'
+
+xcodebuild \
+ -workspace Tests.xcworkspace \
+ -scheme CronetTests \
+ -destination name="iPhone 8" \
+ test \
+ | ./verbose_time.sh \
+ | grep -E -v "$XCODEBUILD_FILTER" \
+ | grep -E -v '^$' -
diff --git a/test/cpp/ios/build_tests.sh b/test/cpp/ios/build_tests.sh
new file mode 100644
index 00000000..176cc083
--- /dev/null
+++ b/test/cpp/ios/build_tests.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't run this script standalone. Instead, run from the repository root:
+# ./tools/run_tests/run_tests.py -l objc
+
+set -e
+
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
+cd "$(dirname "$0")"
+
+hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; }
+hash xcodebuild 2>/dev/null || {
+ echo >&2 "XCode command-line tools need to be installed."
+ exit 1
+}
+
+# clean the directory
+rm -rf Pods
+rm -rf Tests.xcworkspace
+rm -f Podfile.lock
+rm -rf RemoteTestClientCpp/src
+
+echo "TIME: $(date)"
+pod install
+
+# ios-cpp-test-cronet flakes sometimes because of missing files in Protobuf-C++,
+# add some log to help find out the root cause.
+# TODO(yulinliang): Delete it after solving the issue.
+if [ -d "./Pods/Headers/Public/Protobuf-C++/google/protobuf" ]
+then
+ echo "Protobuf-C++/google/protobuf/ has been imported."
+ number_of_files=$(find Pods/Headers/Public/Protobuf-C++/google/protobuf -name "*.h" | wc -l)
+ echo "The number of header files in Pods/Headers/Public/Protobuf-C++/google/protobuf/ is $number_of_files"
+else
+ echo "Error: Protobuf-C++/google/protobuf/ hasn't been imported."
+fi
diff --git a/test/cpp/ios/verbose_time.sh b/test/cpp/ios/verbose_time.sh
new file mode 100644
index 00000000..05926cae
--- /dev/null
+++ b/test/cpp/ios/verbose_time.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!/bin/bash
+
+while IFS= read -r line; do
+ echo "$(date) - $line"
+done
diff --git a/test/distrib/bazel/run_bazel_distrib_test.sh b/test/distrib/bazel/run_bazel_distrib_test.sh
new file mode 100644
index 00000000..89babec1
--- /dev/null
+++ b/test/distrib/bazel/run_bazel_distrib_test.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+# TODO(jtattermusch): make build work with bazel 2.2.0 and bazel 1.2.1 if that's reasonably simple.
+SUPPORTED_VERSIONS=(
+ "3.7.2"
+ "4.0.0"
+)
+
+FAILED_VERSIONS=""
+for VERSION in "${SUPPORTED_VERSIONS[@]}"; do
+ echo "Running bazel distribtest with bazel version ${VERSION}"
+ ./test_single_bazel_version.sh "${VERSION}" || FAILED_VERSIONS="${FAILED_VERSIONS}${VERSION} "
+done
+
+if [ "$FAILED_VERSIONS" != "" ]
+then
+ echo "Bazel distribtest failed: Failed to build with bazel versions ${FAILED_VERSIONS}"
+ exit 1
+fi
diff --git a/test/distrib/bazel/test_latest_bazel_version.sh b/test/distrib/bazel/test_latest_bazel_version.sh
new file mode 100644
index 00000000..fb02a86c
--- /dev/null
+++ b/test/distrib/bazel/test_latest_bazel_version.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+GITHUB_URL="https://github.com"
+REPO="bazelbuild/bazel"
+
+VERSION=$(curl -Ls "${GITHUB_URL}/${REPO}/releases/latest" | \
+ grep "href=.*\.tar.gz" | \
+ grep -o "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*")
+
+./test_single_bazel_version.sh "$VERSION"
diff --git a/test/distrib/bazel/test_single_bazel_version.sh b/test/distrib/bazel/test_single_bazel_version.sh
new file mode 100644
index 00000000..ef338c93
--- /dev/null
+++ b/test/distrib/bazel/test_single_bazel_version.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$#" != "1" ] ; then
+ echo "Must supply bazel version to be tested." >/dev/stderr
+ exit 1
+fi
+
+VERSION="$1"
+
+cd "$(dirname "$0")"/../../..
+
+EXCLUDED_TARGETS=(
+ # iOS platform fails the analysis phase since there is no toolchain available
+ # for it.
+ "-//src/objective-c/..."
+ "-//third_party/objective_c/..."
+
+ # This could be a legitmate failure due to bitrot.
+ "-//src/proto/grpc/testing:test_gen_proto"
+
+ # This appears to be a legitimately broken BUILD file. There's a reference to
+ # a non-existent "link_dynamic_library.sh".
+ "-//third_party/toolchains/bazel_0.26.0_rbe_windows:all"
+
+ # TODO(jtattermusch): add back once fixed
+ "-//examples/android/binder/..."
+)
+
+export OVERRIDE_BAZEL_VERSION="$VERSION"
+# when running under bazel docker image, the workspace is read only.
+export OVERRIDE_BAZEL_WRAPPER_DOWNLOAD_DIR=/tmp
+bazel build -- //... "${EXCLUDED_TARGETS[@]}"
diff --git a/test/distrib/cpp/run_distrib_test_cmake.sh b/test/distrib/cpp/run_distrib_test_cmake.sh
new file mode 100644
index 00000000..247914d9
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install absl
+mkdir -p "third_party/abseil-cpp/cmake/build"
+pushd "third_party/abseil-cpp/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
+# Install c-ares
+# If the distribution provides a new-enough version of c-ares,
+# this section can be replaced with:
+# apt-get install -y libc-ares-dev
+mkdir -p "third_party/cares/cares/cmake/build"
+pushd "third_party/cares/cares/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release ../..
+make -j4 install
+popd
+
+# Install protobuf
+mkdir -p "third_party/protobuf/cmake/build"
+pushd "third_party/protobuf/cmake/build"
+cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release ..
+make -j4 install
+popd
+
+# Install re2
+mkdir -p "third_party/re2/cmake/build"
+pushd "third_party/re2/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
+# Install zlib
+mkdir -p "third_party/zlib/cmake/build"
+pushd "third_party/zlib/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release ../..
+make -j4 install
+popd
+
+# Just before installing gRPC, wipe out contents of all the submodules to simulate
+# a standalone build from an archive
+# shellcheck disable=SC2016
+git submodule foreach 'cd $toplevel; rm -rf $name'
+
+# Install gRPC
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DgRPC_INSTALL=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_CARES_PROVIDER=package \
+ -DgRPC_ABSL_PROVIDER=package \
+ -DgRPC_PROTOBUF_PROVIDER=package \
+ -DgRPC_RE2_PROVIDER=package \
+ -DgRPC_SSL_PROVIDER=package \
+ -DgRPC_ZLIB_PROVIDER=package \
+ ../..
+make -j4 install
+popd
+
+# Build helloworld example using cmake
+mkdir -p "examples/cpp/helloworld/cmake/build"
+pushd "examples/cpp/helloworld/cmake/build"
+cmake ../..
+make
+popd
diff --git a/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh b/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh
new file mode 100644
index 00000000..24083956
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install CMake 3.16
+apt-get update && apt-get install -y wget
+wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
+sh cmake-linux.sh -- --skip-license --prefix=/usr
+rm cmake-linux.sh
+
+# Build and install gRPC for the host architecture.
+# We do this because we need to be able to run protoc and grpc_cpp_plugin
+# while cross-compiling.
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DgRPC_INSTALL=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_SSL_PROVIDER=package \
+ ../..
+make -j4 install
+popd
+
+# Write a toolchain file to use for cross-compiling.
+cat > /tmp/toolchain.cmake <<'EOT'
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(CMAKE_STAGING_PREFIX /tmp/stage)
+set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-6)
+set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-6)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+EOT
+
+# Build and install gRPC for ARM.
+# This build will use the host architecture copies of protoc and
+# grpc_cpp_plugin that we built earlier because we installed them
+# to a location in our PATH (/usr/local/bin).
+mkdir -p "cmake/build_arm"
+pushd "cmake/build_arm"
+cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=/tmp/install \
+ ../..
+make -j4 install
+popd
+
+# Build helloworld example for ARM.
+# As above, it will find and use protoc and grpc_cpp_plugin
+# for the host architecture.
+mkdir -p "examples/cpp/helloworld/cmake/build_arm"
+pushd "examples/cpp/helloworld/cmake/build_arm"
+cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -Dabsl_DIR=/tmp/stage/lib/cmake/absl \
+ -DProtobuf_DIR=/tmp/stage/lib/cmake/protobuf \
+ -DgRPC_DIR=/tmp/stage/lib/cmake/grpc \
+ ../..
+make
+popd
diff --git a/test/distrib/cpp/run_distrib_test_cmake_as_externalproject.sh b/test/distrib/cpp/run_distrib_test_cmake_as_externalproject.sh
new file mode 100644
index 00000000..1729f2d8
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_as_externalproject.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# To increase the confidence that gRPC installation works without depending on
+# too many submodules unnecessarily, just wipe out contents of most submodules
+# before starting the test.
+rm -r third_party/benchmark/* || true
+rm -r third_party/bloaty/* || true
+rm -r third_party/boringssl-with-bazel/* || true
+rm -r third_party/googletest/* || true
+
+# Build helloworld example using cmake superbuild
+cd examples/cpp/helloworld/cmake_externalproject
+mkdir -p cmake/build
+cd cmake/build
+cmake ../..
+make
diff --git a/test/distrib/cpp/run_distrib_test_cmake_as_submodule.sh b/test/distrib/cpp/run_distrib_test_cmake_as_submodule.sh
new file mode 100644
index 00000000..defc63e0
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_as_submodule.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Build helloworld example using cmake, including grpc with "add_subdirectory"
+cd examples/cpp/helloworld
+mkdir -p cmake/build
+cd cmake/build
+cmake -DGRPC_AS_SUBMODULE=ON ../..
+make
diff --git a/test/distrib/cpp/run_distrib_test_cmake_fetchcontent.sh b/test/distrib/cpp/run_distrib_test_cmake_fetchcontent.sh
new file mode 100644
index 00000000..c81cb07c
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_fetchcontent.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+grpc_dir=$(pwd)
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install CMake 3.16
+apt-get update && apt-get install -y wget
+wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
+sh cmake-linux.sh -- --skip-license --prefix=/usr
+rm cmake-linux.sh
+
+# Build helloworld example.
+# This uses CMake's FetchContent module to download gRPC and its dependencies
+# and add it to the helloworld project as a subdirectory.
+mkdir -p "examples/cpp/helloworld/cmake/build"
+pushd "examples/cpp/helloworld/cmake/build"
+# We set FETCHCONTENT_SOURCE_DIR_GRPC to use the existing gRPC checkout
+# rather than cloning a release.
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_SSL_PROVIDER=package \
+ -DGRPC_FETCHCONTENT=ON \
+ -DFETCHCONTENT_SOURCE_DIR_GRPC="$grpc_dir" \
+ ../..
+make -j4
+popd
diff --git a/test/distrib/cpp/run_distrib_test_cmake_module_install.sh b/test/distrib/cpp/run_distrib_test_cmake_module_install.sh
new file mode 100644
index 00000000..96e63b18
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_module_install.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install CMake 3.16
+apt-get update && apt-get install -y wget
+wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
+sh cmake-linux.sh -- --skip-license --prefix=/usr
+rm cmake-linux.sh
+
+# Install gRPC and its dependencies
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DgRPC_INSTALL=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_SSL_PROVIDER=package \
+ ../..
+make -j4 install
+popd
+
+# Build helloworld example using cmake
+mkdir -p "examples/cpp/helloworld/cmake/build"
+pushd "examples/cpp/helloworld/cmake/build"
+cmake ../..
+make
+popd
diff --git a/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh b/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh
new file mode 100644
index 00000000..ab61f169
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install CMake 3.16
+apt-get update && apt-get install -y wget
+wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
+sh cmake-linux.sh -- --skip-license --prefix=/usr
+rm cmake-linux.sh
+
+# Install gRPC and its dependencies
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DgRPC_INSTALL=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_SSL_PROVIDER=package \
+ ../..
+make -j4 install
+popd
+
+# Build helloworld example using make & pkg-config
+cd examples/cpp/helloworld
+export PKG_CONFIG_PATH=/usr/local/grpc/lib/pkgconfig
+export PATH=$PATH:/usr/local/grpc/bin
+make
diff --git a/test/distrib/cpp/run_distrib_test_cmake_pkgconfig.sh b/test/distrib/cpp/run_distrib_test_cmake_pkgconfig.sh
new file mode 100644
index 00000000..e0c04ea8
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake_pkgconfig.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install absl
+mkdir -p "third_party/abseil-cpp/cmake/build"
+pushd "third_party/abseil-cpp/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
+# Install c-ares
+mkdir -p "third_party/cares/cares/cmake/build"
+pushd "third_party/cares/cares/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release ../..
+make -j4 install
+popd
+
+# Install protobuf
+mkdir -p "third_party/protobuf/cmake/build"
+pushd "third_party/protobuf/cmake/build"
+cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release ..
+make -j4 install
+popd
+
+# Install re2
+mkdir -p "third_party/re2/cmake/build"
+pushd "third_party/re2/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
+# Install zlib
+mkdir -p "third_party/zlib/cmake/build"
+pushd "third_party/zlib/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release ../..
+make -j4 install
+popd
+
+# Just before installing gRPC, wipe out contents of all the submodules to simulate
+# a standalone build from an archive
+# shellcheck disable=SC2016
+git submodule foreach 'cd $toplevel; rm -rf $name'
+
+# Install gRPC
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=/usr/local/grpc \
+ -DgRPC_INSTALL=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ -DgRPC_ABSL_PROVIDER=package \
+ -DgRPC_CARES_PROVIDER=package \
+ -DgRPC_PROTOBUF_PROVIDER=package \
+ -DgRPC_RE2_PROVIDER=package \
+ -DgRPC_SSL_PROVIDER=package \
+ -DgRPC_ZLIB_PROVIDER=package \
+ ../..
+make -j4 install
+popd
+
+# Build helloworld example using Makefile and pkg-config
+pushd examples/cpp/helloworld
+export PKG_CONFIG_PATH=/usr/local/grpc/lib/pkgconfig
+export PATH=$PATH:/usr/local/grpc/bin
+make
+popd
+
+# Build route_guide example using Makefile and pkg-config
+pushd examples/cpp/route_guide
+export PKG_CONFIG_PATH=/usr/local/grpc/lib/pkgconfig
+export PATH=$PATH:/usr/local/grpc/bin
+make
+popd
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
new file mode 100644
index 00000000..824e33e2
--- /dev/null
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
+
+./update_version.sh auto
+
+# Retry "nuget restore" to work around https://github.com/grpc/grpc/issues/16312
+nuget restore || nuget restore || nuget restore
+
+msbuild DistribTest.sln
+
+mono DistribTest/bin/Debug/DistribTest.exe
diff --git a/test/distrib/csharp/run_distrib_test_dotnetcli.sh b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
new file mode 100644
index 00000000..69257edd
--- /dev/null
+++ b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
+
+./update_version.sh auto
+
+cd DistribTest
+
+# TODO(jtattermusch): make sure we don't pollute the global nuget cache with
+# the nugets being tested.
+dotnet restore DistribTestDotNet.csproj
+
+dotnet build DistribTestDotNet.csproj
+
+ls -R bin
+
+if [ "${SKIP_NET45_DISTRIBTEST}" != "1" ]
+then
+ dotnet publish -f net45 DistribTestDotNet.csproj
+
+ # .NET 4.5 target after dotnet build
+ mono bin/Debug/net45/publish/DistribTestDotNet.exe
+
+ # .NET 4.5 target after dotnet publish
+ mono bin/Debug/net45/publish/DistribTestDotNet.exe
+fi
+
+if [ "${SKIP_NETCOREAPP21_DISTRIBTEST}" != "1" ]
+then
+ dotnet publish -f netcoreapp2.1 DistribTestDotNet.csproj
+
+ # .NET Core target after dotnet build
+ dotnet exec bin/Debug/netcoreapp2.1/DistribTestDotNet.dll
+
+ # .NET Core target after dotnet publish
+ dotnet exec bin/Debug/netcoreapp2.1/publish/DistribTestDotNet.dll
+fi
+
+if [ "${SKIP_NETCOREAPP31_DISTRIBTEST}" != "1" ]
+then
+ dotnet publish -f netcoreapp3.1 DistribTestDotNet.csproj
+
+ # .NET Core target after dotnet build
+ dotnet exec bin/Debug/netcoreapp3.1/DistribTestDotNet.dll
+
+ # .NET Core target after dotnet publish
+ dotnet exec bin/Debug/netcoreapp3.1/publish/DistribTestDotNet.dll
+fi
+
+if [ "${SKIP_NET50_DISTRIBTEST}" != "1" ]
+then
+ dotnet publish -f net5.0 DistribTestDotNet.csproj
+
+ dotnet publish -r linux-x64 -f net5.0 DistribTestDotNet.csproj -p:PublishSingleFile=true --self-contained true --output net5_singlefile_publish
+
+ # .NET Core target after dotnet build
+ dotnet exec bin/Debug/net5.0/DistribTestDotNet.dll
+
+ # .NET Core target after dotnet publish
+ dotnet exec bin/Debug/net5.0/publish/DistribTestDotNet.dll
+
+ # binary generated by the single file publish
+ ./net5_singlefile_publish/DistribTestDotNet
+fi
diff --git a/test/distrib/csharp/update_version.sh b/test/distrib/csharp/update_version.sh
new file mode 100644
index 00000000..9759cc56
--- /dev/null
+++ b/test/distrib/csharp/update_version.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+cd "$(dirname "$0")"
+
+CSHARP_VERSION="$1"
+if [ "$CSHARP_VERSION" == "auto" ]
+then
+ # autodetect C# version from the name of Grpc.Core.0.0.0-x.nupkg file
+ # TODO: find a better shellcheck-compliant way to write the following line
+ # shellcheck disable=SC2010
+ CSHARP_VERSION=$(ls TestNugetFeed | grep -m 1 '^Grpc\.Core\.[0-9].*\.nupkg$' | sed s/^Grpc\.Core\.// | sed s/\.nupkg$// | sed s/\.symbols$//)
+ echo "Autodetected nuget ${CSHARP_VERSION}"
+fi
+
+# Replaces version placeholder with value provided as first argument.
+sed -ibak "s/__GRPC_NUGET_VERSION__/${CSHARP_VERSION}/g" DistribTest/packages.config DistribTest/DistribTest.csproj DistribTest/DistribTestDotNet.csproj
diff --git a/test/distrib/php/run_distrib_test.sh b/test/distrib/php/run_distrib_test.sh
new file mode 100644
index 00000000..0ca30f40
--- /dev/null
+++ b/test/distrib/php/run_distrib_test.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
+
+find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
+ MAKEFLAGS=-j xargs pecl install
+
+php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/test/distrib/php/run_distrib_test_macos.sh b/test/distrib/php/run_distrib_test_macos.sh
new file mode 100644
index 00000000..1ec38c65
--- /dev/null
+++ b/test/distrib/php/run_distrib_test_macos.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
+
+find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
+ xargs sudo MAKEFLAGS=-j pecl install
+
+php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/test/distrib/python/run_binary_distrib_test.sh b/test/distrib/python/run_binary_distrib_test.sh
new file mode 100644
index 00000000..061d0416
--- /dev/null
+++ b/test/distrib/python/run_binary_distrib_test.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+"$(dirname "$0")/test_packages.sh" binary
diff --git a/test/distrib/python/run_source_distrib_test.sh b/test/distrib/python/run_source_distrib_test.sh
new file mode 100644
index 00000000..f6676746
--- /dev/null
+++ b/test/distrib/python/run_source_distrib_test.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+"$(dirname "$0")/test_packages.sh" source
diff --git a/test/distrib/python/test_packages.sh b/test/distrib/python/test_packages.sh
new file mode 100644
index 00000000..a68eba40
--- /dev/null
+++ b/test/distrib/python/test_packages.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+shopt -s nullglob
+
+if [[ "$1" == "binary" ]]
+then
+ echo "Testing Python binary distribution"
+ ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-[0-9]*.whl)
+ TOOLS_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio_tools-[0-9]*.whl)
+else
+ echo "Testing Python source distribution"
+ ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-[0-9]*.tar.gz)
+ TOOLS_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-tools-[0-9]*.tar.gz)
+fi
+
+HEALTH_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-health-checking-[0-9]*.tar.gz)
+REFLECTION_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-reflection-[0-9]*.tar.gz)
+TESTING_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-testing-[0-9]*.tar.gz)
+
+VIRTUAL_ENV=$(mktemp -d)
+python3 -m virtualenv "$VIRTUAL_ENV"
+PYTHON=$VIRTUAL_ENV/bin/python
+"$PYTHON" -m pip install --upgrade six pip wheel
+
+function validate_wheel_hashes() {
+ for file in "$@"; do
+ "$PYTHON" -m wheel unpack "$file" -d /tmp || return 1
+ done
+ return 0
+}
+
+function at_least_one_installs() {
+ for file in "$@"; do
+ if "$PYTHON" -m pip install "$file"; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+
+#
+# Validate the files in wheel matches their hashes and size in RECORD
+#
+
+if [[ "$1" == "binary" ]]; then
+ validate_wheel_hashes "${ARCHIVES[@]}"
+ validate_wheel_hashes "${TOOLS_ARCHIVES[@]}"
+fi
+
+
+#
+# Install our distributions in order of dependencies
+#
+
+at_least_one_installs "${ARCHIVES[@]}"
+at_least_one_installs "${TOOLS_ARCHIVES[@]}"
+at_least_one_installs "${HEALTH_ARCHIVES[@]}"
+at_least_one_installs "${REFLECTION_ARCHIVES[@]}"
+at_least_one_installs "${TESTING_ARCHIVES[@]}"
+
+
+#
+# Test our distributions
+#
+
+# TODO(jtattermusch): add a .proto file to the distribtest, generate python
+# code from it and then use the generated code from distribtest.py
+"$PYTHON" -m grpc.tools.protoc --help
+
+"$PYTHON" distribtest.py
diff --git a/test/distrib/ruby/run_distrib_test.sh b/test/distrib/ruby/run_distrib_test.sh
new file mode 100644
index 00000000..a611fd1b
--- /dev/null
+++ b/test/distrib/ruby/run_distrib_test.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+function die {
+ echo "$1"
+ exit 1
+}
+
+ARCH="$1"
+PLATFORM="$2"
+PACKAGE_TYPE="$3"
+echo "$EXTERNAL_GIT_ROOT"
+GRPC_VERSION="$(ruby -e 'require ENV["EXTERNAL_GIT_ROOT"] + "/src/ruby/lib/grpc/version.rb"; puts GRPC::VERSION')"
+if [[ "$PACKAGE_TYPE" == "source" ]]; then
+ GEM_NAME="grpc-${GRPC_VERSION}.gem"
+else
+ [[ "$PACKAGE_TYPE" == "binary" ]] || die "unexpeced package type: $PACKAGE_TYPE"
+ GEM_NAME="grpc-${GRPC_VERSION}-${ARCH}-${PLATFORM}.gem"
+fi
+# Create an indexed local gem source with gRPC gems to test
+GEM_SOURCE=../../../gem_source
+mkdir -p "${GEM_SOURCE}/gems"
+cp "${EXTERNAL_GIT_ROOT}/input_artifacts/${GEM_NAME}" "${GEM_SOURCE}/gems"
+# TODO: rewrite the following line to be shellcheck-compliant
+# shellcheck disable=SC2010
+if [[ "$(ls "${GEM_SOURCE}/gems" | grep -c grpc)" != 1 ]]; then
+ echo "Sanity check failed. Copied over more than one grpc gem into the gem source directory."
+ exit 1
+fi;
+gem install builder
+gem generate_index --directory "${GEM_SOURCE}"
+
+bundle install
+
+bundle exec ./distribtest.rb
+
+[[ "$PACKAGE_TYPE" == "source" ]] && exit 0
+# Attempt to repro https://github.com/protocolbuffers/protobuf/issues/4210.
+# This sanity check only works for linux-based distrib tests and for
+# binary gRPC packages.
+INSTALLATION_DIR="$(gem env | grep '\- INSTALLATION DIRECTORY' | awk '{ print $4 }')"
+if [[ "$(find "$INSTALLATION_DIR" -name 'grpc_c.so' | wc -l)" == 0 ]]; then
+ echo "Sanity check failed. The gRPC package is not installed in $INSTALLATION_DIR."
+ exit 1
+fi
+LIBRUBY_DEPENDENCY_EXISTS="$(find "$INSTALLATION_DIR" -name 'grpc_c.so' -exec ldd {} \; | grep -c 'libruby')" || true
+if [[ "$LIBRUBY_DEPENDENCY_EXISTS" != 0 ]]; then
+ echo "A grpc_c.so file in this binary gRPC package is dynamically linked to libruby."
+fi
+DEPENDENCY_NOT_FOUND="$(find "$INSTALLATION_DIR" -name 'grpc_c.so' -exec ldd {} \; | grep -c 'not found')" || true
+if [[ "$DEPENDENCY_NOT_FOUND" != 0 ]]; then
+ echo "A grpc_c.so file in this binary gRPC package has an non-portable dependency."
+fi
+if [ "$LIBRUBY_DEPENDENCY_EXISTS" != 0 ] || [ "$DEPENDENCY_NOT_FOUND" != 0 ]; then
+ exit 1
+fi
diff --git a/third_party/upb/kokoro/ubuntu/build.sh b/third_party/upb/kokoro/ubuntu/build.sh
new file mode 100644
index 00000000..64536f64
--- /dev/null
+++ b/third_party/upb/kokoro/ubuntu/build.sh
@@ -0,0 +1,75 @@
+#!/bin/bash -eu
+#
+# Copyright (c) 2009-2021, Google LLC
+# 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 LLC 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 Google LLC 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.
+
+set -ex
+
+# Install the latest version of Bazel.
+if [ -x "$(command -v use_bazel.sh)" ]; then
+ use_bazel.sh 4.1.0
+fi
+
+# Verify/query CMake
+echo PATH=$PATH
+ls -l `which cmake`
+cmake --version
+
+# Log the bazel path and version.
+which bazel
+bazel version
+
+cd $(dirname $0)/../..
+
+if which gcc; then
+ gcc --version
+ CC=gcc bazel test -c opt --test_output=errors ... -- -benchmarks:benchmark
+ if [[ $(uname) = "Linux" ]]; then
+ CC=gcc bazel test --test_output=errors ...
+ CC=gcc bazel test --test_output=errors ... --//:fasttable_enabled=true -- -cmake:test_generated_files -benchmarks:benchmark
+ fi
+ # TODO: work through these errors and enable this.
+ # if gcc -fanalyzer -x c /dev/null -c -o /dev/null; then
+ # CC=gcc bazel test --copt=-fanalyzer --test_output=errors ...
+ # fi
+fi
+
+if which clang; then
+ if [[ $(uname) = "Linux" ]]; then
+ CC=clang bazel test --test_output=errors ...
+ CC=clang bazel test --test_output=errors -c opt ... -- -benchmarks:benchmark
+ CC=clang bazel test --test_output=errors ... --//:fasttable_enabled=true -- -cmake:test_generated_files
+
+ CC=clang bazel test --test_output=errors --config=m32 ... -- -benchmarks:benchmark
+ CC=clang bazel test --test_output=errors --config=asan ... -- -benchmarks:benchmark
+
+ # TODO: update to a newer Lua that hopefully does not trigger UBSAN.
+ CC=clang bazel test --test_output=errors --config=ubsan ... -- -tests/bindings/lua:test_lua
+ fi
+fi
+
+if which valgrind; then
+ bazel test --config=valgrind ... -- -tests:test_conformance_upb -cmake:cmake_build
+fi
diff --git a/tools/api_reference/add_google_analytics.sh b/tools/api_reference/add_google_analytics.sh
new file mode 100644
index 00000000..14549b79
--- /dev/null
+++ b/tools/api_reference/add_google_analytics.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script finds all html files in the current directory, and adds the
+# GA tracking snippet to them.
+
+read -r -d '' SNIPPET << EOF
+
+EOF
+
+S=$(echo -n "$SNIPPET" | tr '\n' ' ')
+
+while IFS= read -r -d '' M
+do
+ if grep -q "i,s,o,g,r,a,m" "$M"; then
+ :
+ else
+ sed -i "s__${S}_" "$M"
+ fi
+done < <(find . -name \*.html -print0)
diff --git a/tools/buildgen/generate_build_additions.sh b/tools/buildgen/generate_build_additions.sh
new file mode 100644
index 00000000..46ff7e9e
--- /dev/null
+++ b/tools/buildgen/generate_build_additions.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+gen_build_yaml_dirs=" \
+ src/abseil-cpp \
+ src/boringssl \
+ src/benchmark \
+ src/proto \
+ src/re2 \
+ src/upb \
+ src/zlib \
+ src/c-ares \
+ test/core/end2end \
+ test/cpp/naming"
+
+
+gen_build_files=""
+for gen_build_yaml in $gen_build_yaml_dirs
+do
+ output_file=$(mktemp /tmp/gen_$(echo $gen_build_yaml | tr '/' '_').yaml.XXXXX)
+ python3 $gen_build_yaml/gen_build_yaml.py > $output_file
+ gen_build_files="$gen_build_files $output_file"
+done
diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh
new file mode 100644
index 00000000..b98be3ba
--- /dev/null
+++ b/tools/buildgen/generate_projects.sh
@@ -0,0 +1,47 @@
+#! /bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+set -e
+
+export TEST=${TEST:-false}
+
+YAML_OK=$(python3 -c "import yaml; print(yaml.__version__.split('.') >= ['5', '4', '1'])")
+
+if [[ "${YAML_OK}" != "True" ]]; then
+ # PyYAML dropped 3.5 support at 5.4.1, which makes 5.3.1 the latest version we
+ # can use.
+ python3 -m pip install --upgrade --ignore-installed PyYAML==5.3.1 --user
+fi
+
+echo "Generating build_autogenerated.yaml from bazel BUILD file"
+rm -f build_autogenerated.yaml
+python3 tools/buildgen/extract_metadata_from_bazel_xml.py
+
+cd `dirname $0`/../..
+
+tools/buildgen/build_cleaner.py build_handwritten.yaml
+
+# check build_autogenerated.yaml is already in its "clean" form
+TEST=true tools/buildgen/build_cleaner.py build_autogenerated.yaml
+
+. tools/buildgen/generate_build_additions.sh
+
+# Instead of generating from a single build.yaml, we've split it into
+# - build_handwritten.yaml: manually written metadata
+# - build_autogenerated.yaml: generated from bazel BUILD file
+python3 tools/buildgen/generate_projects.py build_handwritten.yaml build_autogenerated.yaml $gen_build_files "$@"
+
+rm $gen_build_files
diff --git a/tools/codegen/core/gen_upb_api.sh b/tools/codegen/core/gen_upb_api.sh
new file mode 100644
index 00000000..75d093ae
--- /dev/null
+++ b/tools/codegen/core/gen_upb_api.sh
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd $(dirname $0)/../../..
+bazel=`pwd`/tools/bazel
+
+if [ $# -eq 0 ]; then
+ UPB_OUTPUT_DIR=$PWD/src/core/ext/upb-generated
+ UPBDEFS_OUTPUT_DIR=$PWD/src/core/ext/upbdefs-generated
+ rm -rf $UPB_OUTPUT_DIR
+ rm -rf $UPBDEFS_OUTPUT_DIR
+ mkdir -p $UPB_OUTPUT_DIR
+ mkdir -p $UPBDEFS_OUTPUT_DIR
+else
+ UPB_OUTPUT_DIR=$1/upb-generated
+ UPBDEFS_OUTPUT_DIR=$1/upbdefs-generated
+ mkdir $UPB_OUTPUT_DIR
+ mkdir $UPBDEFS_OUTPUT_DIR
+fi
+
+$bazel build @com_google_protobuf//:protoc
+PROTOC=$PWD/bazel-bin/external/com_google_protobuf/protoc
+
+$bazel build @upb//upbc:protoc-gen-upb
+UPB_PLUGIN=$PWD/bazel-bin/external/upb/upbc/protoc-gen-upb
+
+$bazel build @upb//upbc:protoc-gen-upbdefs
+UPBDEFS_PLUGIN=$PWD/bazel-bin/external/upb/upbc/protoc-gen-upbdefs
+
+# Please keep the proto list sorted alphabetically.
+proto_files=( \
+ "envoy/admin/v3/config_dump.proto" \
+ "envoy/annotations/deprecation.proto" \
+ "envoy/annotations/resource.proto" \
+ "envoy/config/accesslog/v3/accesslog.proto" \
+ "envoy/config/bootstrap/v3/bootstrap.proto" \
+ "envoy/config/cluster/v3/circuit_breaker.proto" \
+ "envoy/config/cluster/v3/cluster.proto" \
+ "envoy/config/cluster/v3/filter.proto" \
+ "envoy/config/cluster/v3/outlier_detection.proto" \
+ "envoy/config/core/v3/address.proto" \
+ "envoy/config/core/v3/backoff.proto" \
+ "envoy/config/core/v3/base.proto" \
+ "envoy/config/core/v3/config_source.proto" \
+ "envoy/config/core/v3/event_service_config.proto" \
+ "envoy/config/core/v3/extension.proto" \
+ "envoy/config/core/v3/grpc_service.proto" \
+ "envoy/config/core/v3/health_check.proto" \
+ "envoy/config/core/v3/http_uri.proto" \
+ "envoy/config/core/v3/protocol.proto" \
+ "envoy/config/core/v3/proxy_protocol.proto" \
+ "envoy/config/core/v3/resolver.proto" \
+ "envoy/config/core/v3/socket_option.proto" \
+ "envoy/config/core/v3/substitution_format_string.proto" \
+ "envoy/config/core/v3/udp_socket_config.proto" \
+ "envoy/config/endpoint/v3/endpoint_components.proto" \
+ "envoy/config/endpoint/v3/endpoint.proto" \
+ "envoy/config/endpoint/v3/load_report.proto" \
+ "envoy/config/listener/v3/api_listener.proto" \
+ "envoy/config/listener/v3/listener_components.proto" \
+ "envoy/config/listener/v3/listener.proto" \
+ "envoy/config/listener/v3/quic_config.proto" \
+ "envoy/config/listener/v3/udp_listener_config.proto" \
+ "envoy/config/metrics/v3/stats.proto" \
+ "envoy/config/overload/v3/overload.proto" \
+ "envoy/config/rbac/v3/rbac.proto" \
+ "envoy/config/route/v3/route_components.proto" \
+ "envoy/config/route/v3/route.proto" \
+ "envoy/config/route/v3/scoped_route.proto" \
+ "envoy/config/trace/v3/http_tracer.proto" \
+ "envoy/extensions/clusters/aggregate/v3/cluster.proto" \
+ "envoy/extensions/filters/common/fault/v3/fault.proto" \
+ "envoy/extensions/filters/http/fault/v3/fault.proto" \
+ "envoy/extensions/filters/http/router/v3/router.proto" \
+ "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto" \
+ "envoy/extensions/transport_sockets/tls/v3/cert.proto" \
+ "envoy/extensions/transport_sockets/tls/v3/common.proto" \
+ "envoy/extensions/transport_sockets/tls/v3/secret.proto" \
+ "envoy/extensions/transport_sockets/tls/v3/tls.proto" \
+ "envoy/service/cluster/v3/cds.proto" \
+ "envoy/service/discovery/v3/ads.proto" \
+ "envoy/service/discovery/v3/discovery.proto" \
+ "envoy/service/endpoint/v3/eds.proto" \
+ "envoy/service/listener/v3/lds.proto" \
+ "envoy/service/load_stats/v3/lrs.proto" \
+ "envoy/service/route/v3/rds.proto" \
+ "envoy/service/route/v3/srds.proto" \
+ "envoy/service/status/v3/csds.proto" \
+ "envoy/type/http/v3/path_transformation.proto" \
+ "envoy/type/matcher/v3/metadata.proto" \
+ "envoy/type/matcher/v3/node.proto" \
+ "envoy/type/matcher/v3/number.proto" \
+ "envoy/type/matcher/v3/path.proto" \
+ "envoy/type/matcher/v3/regex.proto" \
+ "envoy/type/matcher/v3/string.proto" \
+ "envoy/type/matcher/v3/struct.proto" \
+ "envoy/type/matcher/v3/value.proto" \
+ "envoy/type/metadata/v3/metadata.proto" \
+ "envoy/type/tracing/v3/custom_tag.proto" \
+ "envoy/type/v3/http.proto" \
+ "envoy/type/v3/percent.proto" \
+ "envoy/type/v3/range.proto" \
+ "envoy/type/v3/semantic_version.proto" \
+ "google/api/annotations.proto" \
+ "google/api/expr/v1alpha1/checked.proto" \
+ "google/api/expr/v1alpha1/syntax.proto" \
+ "google/api/http.proto" \
+ "google/protobuf/any.proto" \
+ "google/protobuf/descriptor.proto" \
+ "google/protobuf/duration.proto" \
+ "google/protobuf/empty.proto" \
+ "google/protobuf/struct.proto" \
+ "google/protobuf/timestamp.proto" \
+ "google/protobuf/wrappers.proto" \
+ "google/rpc/status.proto" \
+ "src/proto/grpc/gcp/altscontext.proto" \
+ "src/proto/grpc/gcp/handshaker.proto" \
+ "src/proto/grpc/gcp/transport_security_common.proto" \
+ "src/proto/grpc/health/v1/health.proto" \
+ "src/proto/grpc/lb/v1/load_balancer.proto" \
+ "src/proto/grpc/lookup/v1/rls.proto" \
+ "third_party/istio/security/proto/providers/google/meshca.proto" \
+ "udpa/annotations/migrate.proto" \
+ "udpa/annotations/security.proto" \
+ "udpa/annotations/sensitive.proto" \
+ "udpa/annotations/status.proto" \
+ "udpa/annotations/versioning.proto" \
+ "validate/validate.proto" \
+ "xds/annotations/v3/status.proto" \
+ "xds/core/v3/authority.proto" \
+ "xds/core/v3/collection_entry.proto" \
+ "xds/core/v3/context_params.proto" \
+ "xds/core/v3/resource_locator.proto" \
+ "xds/core/v3/resource_name.proto" \
+ "xds/core/v3/resource.proto" \
+ "xds/data/orca/v3/orca_load_report.proto" \
+ "xds/type/v3/typed_struct.proto")
+
+INCLUDE_OPTIONS="-I=$PWD/third_party/xds \
+ -I=$PWD/third_party/envoy-api \
+ -I=$PWD/third_party/googleapis \
+ -I=$PWD/third_party/protobuf/src \
+ -I=$PWD/third_party/protoc-gen-validate \
+ -I=$PWD"
+
+for i in "${proto_files[@]}"
+do
+ echo "Compiling: ${i}"
+ $PROTOC \
+ $INCLUDE_OPTIONS \
+ $i \
+ --upb_out=$UPB_OUTPUT_DIR \
+ --plugin=protoc-gen-upb=$UPB_PLUGIN
+ # In PHP build Makefile, the files with .upb.c suffix collide .upbdefs.c suffix due to a PHP buildsystem bug.
+ # Work around this by placing the generated files with ".upbdefs.h" and ".upbdefs.c" suffix under a different directory.
+ # See https://github.com/grpc/grpc/issues/23307
+ $PROTOC \
+ $INCLUDE_OPTIONS \
+ $i \
+ --upb_out=$UPBDEFS_OUTPUT_DIR \
+ --plugin=protoc-gen-upb=$UPBDEFS_PLUGIN
+done
diff --git a/tools/distrib/build_ruby_environment_macos.sh b/tools/distrib/build_ruby_environment_macos.sh
new file mode 100644
index 00000000..5495799b
--- /dev/null
+++ b/tools/distrib/build_ruby_environment_macos.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+rm -rf ~/.rake-compiler
+
+CROSS_RUBY="$(pwd)/$(mktemp tmpfile.XXXXXXXX)"
+
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.1.1/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
+
+# See https://github.com/grpc/grpc/issues/12161 for verconf.h patch details
+patch "$CROSS_RUBY" << EOF
+--- cross-ruby.rake 2021-03-05 12:04:09.898286632 -0800
++++ patched 2021-03-05 12:05:35.594318962 -0800
+@@ -111,10 +111,11 @@
+ "--host=#{MINGW_HOST}",
+ "--target=#{MINGW_TARGET}",
+ "--build=#{RUBY_BUILD}",
+- '--enable-shared',
++ '--enable-static',
++ '--disable-shared',
+ '--disable-install-doc',
++ '--without-gmp',
+ '--with-ext=',
+- 'LDFLAGS=-pipe -s',
+ ]
+
+ # Force Winsock2 for Ruby 1.8, 1.9 defaults to it
+@@ -130,6 +131,7 @@
+ # make
+ file "#{build_dir}/ruby.exe" => ["#{build_dir}/Makefile"] do |t|
+ chdir File.dirname(t.prerequisites.first) do
++ sh "test -s verconf.h || rm -f verconf.h" # if verconf.h has size 0, make sure it gets re-built by make
+ sh MAKE
+ end
+ end
+EOF
+
+MAKE="make -j8"
+
+# Install ruby 3.0.0 for rake-compiler
+# Download ruby 3.0.0 sources outside of the cross-ruby.rake file, since the
+# latest rake-compiler/v1.1.1 cross-ruby.rake file requires tar.bz2 source
+# files.
+# TODO(apolcyn): remove this hack when tar.bz2 sources are available for ruby
+# 3.0.0 in https://ftp.ruby-lang.org/pub/ruby/3.0/. Also see
+# https://stackoverflow.com/questions/65477613/rvm-where-is-ruby-3-0-0.
+set +x # rvm commands are very verbose
+source ~/.rvm/scripts/rvm
+echo "rvm use 3.0.0"
+rvm use 3.0.0
+set -x
+RUBY_3_0_0_TAR="${HOME}/.rake-compiler/sources/ruby-3.0.0.tar.gz"
+mkdir -p "$(dirname $RUBY_3_0_0_TAR)"
+curl -L "https://ftp.ruby-lang.org/pub/ruby/3.0/$(basename $RUBY_3_0_0_TAR)" -o "$RUBY_3_0_0_TAR"
+ccache -c
+ruby --version | grep 'ruby 3.0.0'
+rake -f "$CROSS_RUBY" cross-ruby VERSION=3.0.0 HOST=x86_64-darwin11 MAKE="$MAKE" SOURCE="$RUBY_3_0_0_TAR"
+echo "installed ruby 3.0.0 build targets"
+# Install ruby 2.7.0 for rake-compiler
+set +x
+echo "rvm use 2.7.0"
+rvm use 2.7.0
+set -x
+ruby --version | grep 'ruby 2.7.0'
+ccache -c
+rake -f "$CROSS_RUBY" cross-ruby VERSION=2.7.0 HOST=x86_64-darwin11 MAKE="$MAKE"
+echo "installed ruby 2.7.0 build targets"
+# Install ruby 2.4-2.6 for rake-compiler
+set +x
+echo "rvm use 2.5.0"
+rvm use 2.5.0
+set -x
+ruby --version | grep 'ruby 2.5.0'
+for v in 2.6.0 2.5.0 2.4.0 ; do
+ ccache -c
+ rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
+ echo "installed ruby $v build targets"
+done
+
+sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > "$CROSS_RUBY"
+mv "$CROSS_RUBY" ~/.rake-compiler/config.yml
diff --git a/tools/distrib/buildifier_format_code.sh b/tools/distrib/buildifier_format_code.sh
new file mode 100644
index 00000000..8245cd4a
--- /dev/null
+++ b/tools/distrib/buildifier_format_code.sh
@@ -0,0 +1,70 @@
+#! /bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+BUILDIFIER_VERSION="0.29.0"
+TEMP_BUILDIFIER_PATH="/tmp/buildifier"
+EXTRA_BUILDIFIER_FLAGS=$*
+
+function error_handling() {
+ error=$1
+ if [[ -x "$error" ]]; then
+ echo "${error}"
+ exit 1
+ fi
+}
+
+function download_buildifier() {
+ platform="$(uname -s)"
+ case "${platform}" in
+ Linux*) download_link="https://github.com/bazelbuild/buildtools/releases/download/${BUILDIFIER_VERSION}/buildifier";;
+ Darwin*) download_link="https://github.com/bazelbuild/buildtools/releases/download/${BUILDIFIER_VERSION}/buildifier.mac";;
+ *) error_handling "Unsupported platform: ${platform}";;
+ esac
+
+ if [ -x "$(command -v curl)" ]; then
+ curl -L -o ${TEMP_BUILDIFIER_PATH} ${download_link}
+ elif [ -x "$(command -v wget)" ]; then
+ wget -O ${TEMP_BUILDIFIER_PATH} ${download_link}
+ else
+ error_handling "Download failed: curl and wget not available"
+ fi
+
+ chmod +x ${TEMP_BUILDIFIER_PATH}
+}
+
+
+# Get the correct version of buildifier
+if [ -x "$(command -v buildifier)" ]; then
+ existing_buildifier_version="$(buildifier -version 2>&1 | head -n1 | cut -d" " -f3)"
+ if [[ "${existing_buildifier_version}" != "${BUILDIFIER_VERSION}" ]]; then
+ download_buildifier
+ buildifier_bin="${TEMP_BUILDIFIER_PATH}"
+ else
+ buildifier_bin="buildifier"
+ fi
+else
+ download_buildifier
+ buildifier_bin="${TEMP_BUILDIFIER_PATH}"
+fi
+
+# cd to repo root
+dir=$(dirname "${0}")
+cd "${dir}/../.."
+
+bazel_files=$(find . \( -iname 'BUILD' -o -iname '*.bzl' -o -iname '*.bazel' -o -iname 'WORKSPACE' \) -type f -not -path "./third_party/*")
+# shellcheck disable=SC2086,SC2068
+${buildifier_bin} ${EXTRA_BUILDIFIER_FLAGS[@]} -v ${bazel_files}
diff --git a/tools/distrib/buildifier_format_code_strict.sh b/tools/distrib/buildifier_format_code_strict.sh
new file mode 100644
index 00000000..e8a98418
--- /dev/null
+++ b/tools/distrib/buildifier_format_code_strict.sh
@@ -0,0 +1,20 @@
+#! /bin/bash -ex
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+dir=$(dirname "${0}")
+buildifier_format_script="${dir}/buildifier_format_code.sh"
+
+${buildifier_format_script} -lint warn
diff --git a/tools/distrib/check_boringssl_prefix_symbol.sh b/tools/distrib/check_boringssl_prefix_symbol.sh
new file mode 100644
index 00000000..9b6a4788
--- /dev/null
+++ b/tools/distrib/check_boringssl_prefix_symbol.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check if the current BoringSSL prefix symbols is up to date
+set -e
+
+cd "$(dirname $0)"
+cd ../../third_party/boringssl-with-bazel
+
+BORINGSSL_COMMIT=$(git rev-parse HEAD)
+PREFIX_SYMBOLS_COMMIT=$(cat ../../src/boringssl/boringssl_prefix_symbols.h | head -n1 | awk '{print $NF}')
+
+[ $BORINGSSL_COMMIT == $PREFIX_SYMBOLS_COMMIT ] || { echo "The BoringSSL commit does not match the commit of the prefix symbols (src/boringssl/boringssl_prefix_symbols.h). Run tools/distrib/generate_boringssl_prefix_header.sh to update the prefix symbols." ; exit 1 ; }
+
+exit 0
diff --git a/tools/distrib/check_protobuf_pod_version.sh b/tools/distrib/check_protobuf_pod_version.sh
new file mode 100644
index 00000000..174931a0
--- /dev/null
+++ b/tools/distrib/check_protobuf_pod_version.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd `dirname $0`/../..
+
+# get the version of protobuf in /third_party/protobuf
+pushd third_party/protobuf
+
+version1=$(git describe --tags | cut -f 1 -d'-')
+v1=${version1:1}
+
+popd
+
+# get the version of protobuf in /src/objective-c/!ProtoCompiler.podspec
+v2=$(cat src/objective-c/\!ProtoCompiler.podspec | egrep "v = " | cut -f 2 -d"'")
+
+# get the version of protobuf in /src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
+v3=$(cat src/objective-c/\!ProtoCompiler-gRPCPlugin.podspec | egrep 'dependency.*!ProtoCompiler' | cut -f 4 -d"'")
+
+# compare and emit error
+ret=0
+if [ $v1 != $v2 ]; then
+ echo 'Protobuf version in src/objective-c/!ProtoCompiler.podspec does not match protobuf version in third_party/protobuf.'
+ ret=1
+fi
+
+if [ $v1 != $v3 ]; then
+ echo 'Protobuf version in src/objective-c/!ProtoCompiler-gRPCPlugin.podspec does not match protobuf version in third_party/protobuf.'
+ ret=1
+fi
+
+exit $ret
diff --git a/tools/distrib/check_pytype.sh b/tools/distrib/check_pytype.sh
new file mode 100644
index 00000000..c8a9a9df
--- /dev/null
+++ b/tools/distrib/check_pytype.sh
@@ -0,0 +1,19 @@
+#! /bin/bash -ex
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+JOBS=$(nproc) || JOBS=4
+python3 -m pip install pytype==2019.11.27
+
+python3 -m pytype --keep-going -j "$JOBS" --strict-import --config "setup.cfg"
diff --git a/tools/distrib/check_trailing_newlines.sh b/tools/distrib/check_trailing_newlines.sh
new file mode 100644
index 00000000..21e19409
--- /dev/null
+++ b/tools/distrib/check_trailing_newlines.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# change to root directory
+cd $(dirname $0)/../..
+
+function find_without_newline() {
+ find . -type f -not -path './third_party/*' -and \( \
+ -name '*.c' \
+ -or -name '*.cc' \
+ -or -name '*.proto' \
+ -or -name '*.rb' \
+ -or -name '*.py' \
+ -or -name '*.cs' \
+ -or -name '*.sh' \) -print0 \
+ | while IFS= read -r -d '' f; do
+ if [[ ! -z $f ]]; then
+ if [[ $(tail -c 1 "$f") != $NEWLINE ]]; then
+ echo "Error: file '$f' is missing a trailing newline character."
+ if $1; then # fix
+ sed -i -e '$a\' $f
+ echo 'Fixed!'
+ fi
+ fi
+ fi
+ done
+}
+
+if [[ $# == 1 && $1 == '--fix' ]]; then
+ FIX=true
+else
+ FIX=false
+fi
+
+ERRORS=$(find_without_newline $FIX)
+if [[ "$ERRORS" != '' ]]; then
+ echo "$ERRORS"
+ if ! $FIX; then
+ exit 1
+ fi
+fi
diff --git a/tools/distrib/check_upb_output.sh b/tools/distrib/check_upb_output.sh
new file mode 100644
index 00000000..f3697c09
--- /dev/null
+++ b/tools/distrib/check_upb_output.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+readonly UPB_GENERATED_SRC=src/core/ext/upb-generated
+readonly UPBDEFS_GENERATED_SRC=src/core/ext/upbdefs-generated
+readonly UPB_TMP_OUTPUT="$(mktemp -d)"
+
+tools/codegen/core/gen_upb_api.sh "$UPB_TMP_OUTPUT"
+
+diff -rq "$UPB_GENERATED_SRC" "$UPB_TMP_OUTPUT/upb-generated"
+diff -rq "$UPBDEFS_GENERATED_SRC" "$UPB_TMP_OUTPUT/upbdefs-generated"
diff --git a/tools/distrib/check_windows_dlls.sh b/tools/distrib/check_windows_dlls.sh
new file mode 100644
index 00000000..c25091ed
--- /dev/null
+++ b/tools/distrib/check_windows_dlls.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to root directory
+cd "$(dirname "$0")/../.."
+
+bundle
+rake dlls
diff --git a/tools/distrib/clang_format_code.sh b/tools/distrib/clang_format_code.sh
new file mode 100644
index 00000000..cd7553e9
--- /dev/null
+++ b/tools/distrib/clang_format_code.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to root directory
+cd $(dirname $0)/../..
+REPO_ROOT=$(pwd)
+
+if [ "$CLANG_FORMAT_SKIP_DOCKER" == "" ]
+then
+ # build clang-format docker image
+ docker build -t grpc_clang_format tools/dockerfile/grpc_clang_format
+
+ # run clang-format against the checked out codebase
+ # when modifying the checked-out files, the current user will be impersonated
+ # so that the updated files don't end up being owned by "root".
+ docker run -e TEST="$TEST" -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_FORMAT_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code --user "$(id -u):$(id -g)" -t grpc_clang_format /clang_format_all_the_things.sh
+else
+ CLANG_FORMAT_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+fi
diff --git a/tools/distrib/clang_tidy_code.sh b/tools/distrib/clang_tidy_code.sh
new file mode 100644
index 00000000..dade5929
--- /dev/null
+++ b/tools/distrib/clang_tidy_code.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+echo "NOTE: to automagically apply fixes, invoke with --fix"
+
+set -ex
+
+# change to root directory
+cd $(dirname $0)/../..
+REPO_ROOT=$(pwd)
+
+# grep targets with manual tag, which is not included in a result of bazel build using ...
+# let's get a list of them using query command and pass it to gen_compilation_database.py
+export MANUAL_TARGETS=$(bazel query 'attr("tags", "manual", tests(//test/cpp/...))' | grep -v _on_ios)
+
+# generate a clang compilation database for all C/C++ sources in the repo.
+tools/distrib/gen_compilation_database.py \
+ --include_headers \
+ --ignore_system_headers \
+ --dedup_targets \
+ "//:*" \
+ "//src/core/..." \
+ "//src/compiler/..." \
+ "//test/core/..." \
+ "//test/cpp/..." \
+ $MANUAL_TARGETS
+
+if [ "$CLANG_TIDY_SKIP_DOCKER" == "" ]
+then
+ # build clang-tidy docker image
+ docker build -t grpc_clang_tidy tools/dockerfile/grpc_clang_tidy
+
+ # run clang-tidy against the checked out codebase
+ # when modifying the checked-out files, the current user will be impersonated
+ # so that the updated files don't end up being owned by "root".
+ docker run \
+ -e TEST="$TEST" \
+ -e CHANGED_FILES="$CHANGED_FILES" \
+ -e CLANG_TIDY_ROOT="/local-code" \
+ --rm=true \
+ -v "${REPO_ROOT}":/local-code \
+ -v "${HOME/.cache/bazel}":"${HOME/.cache/bazel}" \
+ --user "$(id -u):$(id -g)" \
+ -t grpc_clang_tidy /clang_tidy_all_the_things.sh "$@"
+else
+ CLANG_TIDY_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_clang_tidy/clang_tidy_all_the_things.sh "$@"
+fi
diff --git a/tools/distrib/docgen/_generate_python_doc.sh b/tools/distrib/docgen/_generate_python_doc.sh
new file mode 100644
index 00000000..febc3188
--- /dev/null
+++ b/tools/distrib/docgen/_generate_python_doc.sh
@@ -0,0 +1,31 @@
+#! /bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is meant to be ran in Docker instance of python:3.8.
+
+set -ex
+
+# Some Python package installation requires permission to change homedir. But
+# due to the user-override in all_lang_docgen.sh, the user in the container
+# doesn't have a home dir which leads to permission denied error.
+HOME="$(mktemp -d)"
+export HOME
+
+pip install -r requirements.bazel.txt
+tools/run_tests/run_tests.py -c opt -l python --compiler python3.8 --newline_on_success -j 8 --build_only
+# shellcheck disable=SC1091
+source py38_native/bin/activate
+pip install --upgrade Sphinx
+python setup.py doc
diff --git a/tools/distrib/docgen/all_lang_docgen.sh b/tools/distrib/docgen/all_lang_docgen.sh
new file mode 100644
index 00000000..1eb1cd74
--- /dev/null
+++ b/tools/distrib/docgen/all_lang_docgen.sh
@@ -0,0 +1,120 @@
+#! /bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# A script to automatically generate API references and push to GitHub.
+# This script covers Core/C++/ObjC/C#/PHP/Python. Due to lack of tooling for
+# Cython, Python document generation unfortunately needs to compile everything.
+# So, this script will take couple minutes to run.
+#
+# Generate and push:
+#
+# tools/distrib/docgen/all_lang-docgen.sh YOUR_GITHUB_USERNAME
+#
+# Just generate:
+#
+# tools/distrib/docgen/all_lang-docgen.sh
+#
+
+set -e
+
+# Find out the gRPC version and print it
+GRPC_VERSION="$(grep -m1 -Eo ' version: .*' build_handwritten.yaml | grep -Eo '[0-9][^ ]*')"
+echo "Generating documents for version ${GRPC_VERSION}..."
+
+# Specifies your GitHub user name or generates documents locally
+if [ $# -eq 0 ]; then
+ read -r -p "- Are you sure to generate documents without pushing to GitHub? [y/N] " response
+ if [[ "${response[0]}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
+ GITHUB_USER=''
+ else
+ echo "Generation stopped"
+ exit 1
+ fi
+else
+ if [ $# -eq 1 ]; then
+ GITHUB_USER=$1
+ else
+ echo "Too many arguments!"
+ exit 1
+ fi
+fi
+
+# Exits on pending changes; please double check for unwanted code changes
+git diff --exit-code
+git submodule update --init --recursive
+
+# Changes to project root
+dir=$(dirname "${0}")
+cd "${dir}/../../.."
+
+# Clones the API reference GitHub Pages branch
+PAGES_PATH="/tmp/gh-pages"
+rm -rf "${PAGES_PATH}"
+git clone --single-branch https://github.com/grpc/grpc -b gh-pages "${PAGES_PATH}"
+
+# Generates Core / C++ / ObjC / PHP documents
+rm -rf "${PAGES_PATH}/core" "${PAGES_PATH}/cpp" "${PAGES_PATH}/objc" "${PAGES_PATH}/php"
+echo "Generating Core / C++ / ObjC / PHP documents in Docker..."
+docker run --rm -it \
+ -v "$(pwd)":/work/grpc \
+ --user "$(id -u):$(id -g)" \
+ hrektts/doxygen /work/grpc/tools/doxygen/run_doxygen.sh
+mv doc/ref/c++/html "${PAGES_PATH}/cpp"
+mv doc/ref/core/html "${PAGES_PATH}/core"
+mv doc/ref/objc/html "${PAGES_PATH}/objc"
+mv doc/ref/php/html "${PAGES_PATH}/php"
+
+# Generates C# documents
+rm -rf "${PAGES_PATH}/csharp"
+echo "Generating C# documents in Docker..."
+docker run --rm -it \
+ -v "$(pwd)":/work \
+ -w /work/src/csharp/docfx \
+ --user "$(id -u):$(id -g)" \
+ tsgkadot/docker-docfx:latest docfx
+mv src/csharp/docfx/html "${PAGES_PATH}/csharp"
+
+# Generates Python documents
+rm -rf "${PAGES_PATH}/python"
+echo "Generating Python documents in Docker..."
+docker run --rm -it \
+ -v "$(pwd)":/work \
+ -w /work \
+ --user "$(id -u):$(id -g)" \
+ python:3.8 tools/distrib/docgen/_generate_python_doc.sh
+mv doc/build "${PAGES_PATH}/python"
+
+# At this point, document generation is finished.
+echo "================================================================="
+echo " Successfully generated documents for version ${GRPC_VERSION}."
+echo "================================================================="
+
+# Uploads to GitHub
+if [[ -n "${GITHUB_USER}" ]]; then
+ BRANCH_NAME="doc-${GRPC_VERSION}"
+
+ (cd "${PAGES_PATH}"
+ git remote add "${GITHUB_USER}" "git@github.com:${GITHUB_USER}/grpc.git"
+ git checkout -b "${BRANCH_NAME}"
+ git add --all
+ git commit -m "Auto-update documentation for gRPC ${GRPC_VERSION}"
+ git push --set-upstream "${GITHUB_USER}" "${BRANCH_NAME}"
+ )
+
+ echo "Please check https://github.com/${GITHUB_USER}/grpc/tree/${BRANCH_NAME} for generated documents."
+ echo "Click https://github.com/grpc/grpc/compare/gh-pages...${GITHUB_USER}:${BRANCH_NAME} to create a PR."
+else
+ echo "Please check ${PAGES_PATH} for generated documents."
+fi
diff --git a/tools/distrib/format_bazel.sh b/tools/distrib/format_bazel.sh
new file mode 100644
index 00000000..d1c722c6
--- /dev/null
+++ b/tools/distrib/format_bazel.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Copyright 2019 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set=-ex
+
+VIRTUAL_ENV=bazel_format_virtual_environment
+
+CONFIG_PATH="$(dirname ${0})/bazel_style.cfg"
+
+python -m virtualenv ${VIRTUAL_ENV}
+PYTHON=${VIRTUAL_ENV}/bin/python
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade futures
+"$PYTHON" -m pip install yapf==0.30.0
+
+pushd "$(dirname "${0}")/../.."
+FILES=$(find . -path ./third_party -prune -o -name '*.bzl' -print)
+echo "${FILES}" | xargs "$PYTHON" -m yapf -i --style="${CONFIG_PATH}"
+
+if ! which buildifier &>/dev/null; then
+ echo 'buildifer must be installed.' >/dev/stderr
+ exit 1
+fi
+
+echo "${FILES}" | xargs buildifier --type=bzl
+
+popd
diff --git a/tools/distrib/generate_boringssl_prefix_header.sh b/tools/distrib/generate_boringssl_prefix_header.sh
new file mode 100644
index 00000000..f8d60b87
--- /dev/null
+++ b/tools/distrib/generate_boringssl_prefix_header.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generate the list of boringssl symbols that need to be renamed based on the
+# current boringssl submodule. The script should be run after a boringssl
+# upgrade in third_party/boringssl-with-bazel. Note that after the script is
+# run, you will typically need to manually upgrade the BoringSSL-GRPC podspec
+# (templates/src/objective-c/BoringSSL-GRPC.podspec.template) version and the
+# corresponding version number in gRPC-Core podspec
+# (templates/gRPC-Core.podspec.template).
+
+set -ev
+
+BORINGSSL_ROOT=third_party/boringssl-with-bazel/src
+
+cd "$(dirname $0)"
+cd ../../$BORINGSSL_ROOT
+
+BORINGSSL_COMMIT=$(git rev-parse HEAD)
+BORINGSSL_PREFIX_HEADERS_DIR=src/boringssl
+
+rm -rf build
+mkdir -p build
+cd build
+cmake ..
+make -j
+[ -f ssl/libssl.a ] || { echo "Failed to build libssl.a" ; exit 1 ; }
+[ -f crypto/libcrypto.a ] || { echo "Failed to build libcrypto.a" ; exit 1 ; }
+
+# Generates boringssl_prefix_symbols.h. The prefix header is generated by
+# BoringSSL's build system as instructed by BoringSSL build guide (see
+# https://github.com/google/boringssl/blob/367d64f84c3c1d01381c18c5a239b85eef47633c/BUILDING.md#building-with-prefixed-symbols).
+go run ../util/read_symbols.go ssl/libssl.a > ./symbols.txt
+go run ../util/read_symbols.go crypto/libcrypto.a >> ./symbols.txt
+cmake .. -DBORINGSSL_PREFIX=GRPC -DBORINGSSL_PREFIX_SYMBOLS=symbols.txt
+make boringssl_prefix_symbols
+[ -f symbol_prefix_include/boringssl_prefix_symbols.h ] || { echo "Failed to build boringssl_prefix_symbols.sh" ; exit 1 ; }
+
+cd ../../../..
+mkdir -p $BORINGSSL_PREFIX_HEADERS_DIR
+echo "// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: $BORINGSSL_COMMIT" > $BORINGSSL_PREFIX_HEADERS_DIR/boringssl_prefix_symbols.h
+echo "" >> $BORINGSSL_PREFIX_HEADERS_DIR/boringssl_prefix_symbols.h
+cat "$BORINGSSL_ROOT/build/symbol_prefix_include/boringssl_prefix_symbols.h" >> $BORINGSSL_PREFIX_HEADERS_DIR/boringssl_prefix_symbols.h
+
+# Regenerated the project
+tools/buildgen/generate_projects.sh
+
+exit 0
diff --git a/tools/distrib/guard_headers.sh b/tools/distrib/guard_headers.sh
new file mode 100644
index 00000000..fb66e55f
--- /dev/null
+++ b/tools/distrib/guard_headers.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+set -e
+
+cd `dirname $0`/../..
+
+function process_dir {
+ base_dir=$1
+ prefix=$2
+ comment_language=$3
+ (
+ cd $base_dir
+ find . -name "*.h" | while read f ; do
+ guard=${prefix}_`echo ${f#*/} | tr '[:lower:]/.-' '[:upper:]___'`
+ if [ "$comment_language" = "c++" ] ; then
+ comment="// $guard"
+ else
+ comment="/* $guard */"
+ fi
+ awk '
+ BEGIN {
+ guard = "'${guard}'";
+ comment_language = "'${comment_language}'";
+ }
+ prev ~ /^#ifndef/ && !got_first_ifndef {
+ got_first_ifndef = 1;
+ prev = "#ifndef " guard;
+ }
+ prev ~ /^#define/ && !got_first_define {
+ got_first_define = 1;
+ prev = "#define " guard;
+ }
+ NR > 1 { print prev; }
+ { prev = $0; }
+ END {
+ if (prev ~ /^#endif/) {
+ if (comment_language ~ /^c$/) {
+ print "#endif /* " guard " */";
+ } else if (comment_language ~ /^c\+\+$/) {
+ print "#endif // " guard;
+ } else {
+ print "ERROR: unknown comment language: " comment_language;
+ }
+ } else {
+ print "ERROR: file does not end with #endif";
+ }
+ }
+ ' "${f}" > "${f}.rewritten"
+ mv "${f}.rewritten" "${f}"
+ done
+ )
+}
+
+process_dir include/grpc GRPC c
+process_dir include/grpc++ GRPCXX c++
+process_dir src/core GRPC_INTERNAL_CORE c
+process_dir src/cpp GRPC_INTERNAL_CPP c++
+process_dir src/compiler GRPC_INTERNAL_COMPILER c++
+process_dir test/core GRPC_TEST_CORE c
+process_dir test/cpp GRPC_TEST_CPP c++
+process_dir examples GRPC_EXAMPLES c++
diff --git a/tools/distrib/install_all_python_modules.sh b/tools/distrib/install_all_python_modules.sh
new file mode 100644
index 00000000..8189a0ff
--- /dev/null
+++ b/tools/distrib/install_all_python_modules.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+echo "It's recommended that you run this script from a virtual environment."
+
+set -e
+
+BASEDIR=$(dirname "$0")
+BASEDIR=$(realpath "$BASEDIR")/../..
+
+(cd "$BASEDIR";
+ pip install --upgrade cython;
+ python setup.py install;
+ pushd tools/distrib/python/grpcio_tools;
+ ../make_grpcio_tools.py
+ GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .
+ popd;
+ pushd src/python;
+ for PACKAGE in ./grpcio_*; do
+ pushd "${PACKAGE}";
+ python setup.py preprocess;
+ python setup.py install;
+ popd;
+ done
+ popd;
+)
diff --git a/tools/distrib/isort_code.sh b/tools/distrib/isort_code.sh
new file mode 100644
index 00000000..897200b5
--- /dev/null
+++ b/tools/distrib/isort_code.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+ACTION=${1:---overwrite-in-place}
+[[ $ACTION == '--overwrite-in-place' ]] || [[ $ACTION == '--diff' ]]
+
+if [[ $ACTION == '--diff' ]]; then
+ ACTION="--diff --check"
+fi
+
+# Change to root
+cd "$(dirname "${0}")/../.."
+
+DIRS=(
+ 'examples/python'
+ 'src/python'
+ 'test'
+ 'tools'
+ 'setup.py'
+)
+
+VIRTUALENV=isort_virtual_environment
+
+python3 -m virtualenv $VIRTUALENV
+PYTHON=${VIRTUALENV}/bin/python
+"$PYTHON" -m pip install isort==5.9.2
+
+$PYTHON -m isort $ACTION \
+ --force-sort-within-sections \
+ --force-single-line-imports --single-line-exclusions=typing \
+ --src "examples/python/data_transmission" \
+ --src "examples/python/async_streaming" \
+ --src "tools/run_tests/xds_k8s_test_driver" \
+ --src "src/python/grpcio_tests" \
+ --src "tools/run_tests" \
+ --project "examples" \
+ --project "src" \
+ --thirdparty "grpc" \
+ --skip-glob "third_party/*" \
+ --skip-glob "*/env/*" \
+ --skip-glob "*pb2*.py" \
+ --dont-follow-links \
+ "${DIRS[@]}"
diff --git a/tools/distrib/pull_requests_interval.sh b/tools/distrib/pull_requests_interval.sh
new file mode 100644
index 00000000..7a6c702d
--- /dev/null
+++ b/tools/distrib/pull_requests_interval.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ "x$1" = "x" ] ; then
+ echo "Usage: $0 [second ref]"
+ exit 1
+else
+ first=$1
+fi
+
+if [ -n $2 ] ; then
+ second=HEAD
+fi
+
+if [ -e ~/github-credentials.vars ] ; then
+ . ~/github-credentials.vars
+fi
+
+if [ "x$github_client_id" = "x" ] || [ "x$github_client_secret" = "x" ] ; then
+ echo "Warning: you don't have github credentials set."
+ echo
+ echo "You may end up exceeding guest quota quickly."
+ echo "You can create an application for yourself,"
+ echo "and get its credentials. Go to"
+ echo
+ echo " https://github.com/settings/developers"
+ echo
+ echo "and click 'Register a new application'."
+ echo
+ echo "From the application's information, copy/paste"
+ echo "its Client ID and Client Secret, into the file"
+ echo
+ echo " ~/github-credentials.vars"
+ echo
+ echo "with the following format:"
+ echo
+ echo "github_client_id=0123456789abcdef0123"
+ echo "github_client_secret=0123456789abcdef0123456789abcdef"
+ echo
+ echo
+ addendum=""
+else
+ addendum="?client_id=$github_client_id&client_secret=$github_client_secret"
+fi
+
+unset notfirst
+echo "["
+git log --pretty=oneline $1..$2 |
+ grep '[^ ]\+ Merge pull request #[0-9]\{4,6\} ' |
+ cut -f 2 -d# |
+ cut -f 1 -d\ |
+ sort -u |
+ while read id ; do
+ if [ "x$notfirst" = "x" ] ; then
+ notfirst=true
+ else
+ echo ","
+ fi
+ echo -n " {\"url\": \"https://github.com/grpc/grpc/pull/$id\","
+ out=`mktemp`
+ curl -s "https://api.github.com/repos/grpc/grpc/pulls/$id$addendum" > $out
+ echo -n " "`grep '"title"' $out`
+ echo -n " "`grep '"login"' $out | head -1`
+ echo -n " \"pr\": $id }"
+ rm $out
+ done
+echo
+echo "]"
diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh
new file mode 100644
index 00000000..83faa932
--- /dev/null
+++ b/tools/distrib/pylint_code.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# Copyright 2017 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# NOTE(rbellevi): We ignore generated code.
+IGNORE_PATTERNS=--ignore-patterns='.*pb2\.py,.*pb2_grpc\.py'
+
+# change to root directory
+cd "$(dirname "$0")/../.."
+
+DIRS=(
+ 'src/python/grpcio/grpc'
+ 'src/python/grpcio_channelz/grpc_channelz'
+ 'src/python/grpcio_health_checking/grpc_health'
+ 'src/python/grpcio_reflection/grpc_reflection'
+ 'src/python/grpcio_testing/grpc_testing'
+ 'src/python/grpcio_status/grpc_status'
+)
+
+TEST_DIRS=(
+ 'src/python/grpcio_tests/tests'
+ 'src/python/grpcio_tests/tests_gevent'
+)
+
+VIRTUALENV=python_pylint_venv
+python3 -m virtualenv $VIRTUALENV -p $(which python3)
+
+PYTHON=$VIRTUALENV/bin/python
+
+$PYTHON -m pip install --upgrade pip==19.3.1
+
+# TODO(https://github.com/grpc/grpc/issues/23394): Update Pylint.
+$PYTHON -m pip install --upgrade astroid==2.3.3 pylint==2.2.2 "isort>=4.3.0,<5.0.0"
+
+EXIT=0
+for dir in "${DIRS[@]}"; do
+ $PYTHON -m pylint --rcfile=.pylintrc -rn "$dir" ${IGNORE_PATTERNS} || EXIT=1
+done
+
+for dir in "${TEST_DIRS[@]}"; do
+ $PYTHON -m pylint --rcfile=.pylintrc-tests -rn "$dir" ${IGNORE_PATTERNS} || EXIT=1
+done
+
+find examples/python \
+ -iname "*.py" \
+ -not -name "*_pb2.py" \
+ -not -name "*_pb2_grpc.py" \
+ | xargs $PYTHON -m pylint --rcfile=.pylintrc-examples -rn ${IGNORE_PATTERNS}
+
+exit $EXIT
diff --git a/tools/distrib/python/bazel_deps.sh b/tools/distrib/python/bazel_deps.sh
new file mode 100644
index 00000000..ce2c1147
--- /dev/null
+++ b/tools/distrib/python/bazel_deps.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cd $(dirname $0)/../../../
+
+cd third_party/protobuf
+# use tools/bazel wrapper to make sure we use the right version of bazel
+../../tools/bazel query 'deps('$1')'
diff --git a/tools/distrib/python/xds_protos/build_validate_upload.sh b/tools/distrib/python/xds_protos/build_validate_upload.sh
new file mode 100644
index 00000000..00135fca
--- /dev/null
+++ b/tools/distrib/python/xds_protos/build_validate_upload.sh
@@ -0,0 +1,39 @@
+#! /bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+WORK_DIR=$(pwd)/"$(dirname "$0")"
+cd ${WORK_DIR}
+
+# Remove existing wheels
+rm -rf ${WORK_DIR}/dist
+
+# Generate the package content then build the source wheel
+python3 build.py
+python3 setup.py bdist_wheel
+
+# Run the tests to ensure all protos are importable, also avoid confusing normal
+# imports with relative imports
+pushd $(mktemp -d '/tmp/test_xds_protos.XXXXXX')
+python3 -m virtualenv env
+env/bin/python -m pip install ${WORK_DIR}/dist/*.whl
+cp ${WORK_DIR}/generated_file_import_test.py generated_file_import_test.py
+env/bin/python generated_file_import_test.py
+popd
+
+# Upload the package
+python3 -m twine check dist/*
+python3 -m twine upload dist/*
diff --git a/tools/distrib/python_wrapper.sh b/tools/distrib/python_wrapper.sh
new file mode 100644
index 00000000..a099b2f1
--- /dev/null
+++ b/tools/distrib/python_wrapper.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+for p in python2.7 python2.6 python2 python not_found ; do
+
+ python=$(which $p || echo not_found)
+
+ if [ -x "$python" ] ; then
+ break
+ fi
+
+done
+
+if [ -x "$python" ] ; then
+ exec "$python" "$@"
+else
+ echo "No acceptable version of python found on the system"
+ exit 1
+fi
diff --git a/tools/distrib/sanitize.sh b/tools/distrib/sanitize.sh
new file mode 100644
index 00000000..7bc58eb6
--- /dev/null
+++ b/tools/distrib/sanitize.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+tools/buildgen/generate_projects.sh
+tools/distrib/check_include_guards.py --fix
+tools/distrib/check_copyright.py --fix
+tools/distrib/add-iwyu.py
+tools/distrib/check_trailing_newlines.sh --fix
+tools/run_tests/sanity/check_port_platform.py --fix
+tools/run_tests/sanity/check_include_style.py --fix || true
+tools/distrib/yapf_code.sh
+tools/distrib/isort_code.sh
+tools/distrib/clang_format_code.sh
+tools/distrib/buildifier_format_code.sh || true
+
diff --git a/tools/distrib/yapf_code.sh b/tools/distrib/yapf_code.sh
new file mode 100644
index 00000000..4e3767a6
--- /dev/null
+++ b/tools/distrib/yapf_code.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+ACTION=${1:---in-place}
+[[ $ACTION == '--in-place' ]] || [[ $ACTION == '--diff' ]]
+
+# change to root directory
+cd "$(dirname "${0}")/../.."
+
+DIRS=(
+ 'examples'
+ 'src'
+ 'test'
+ 'tools'
+ 'setup.py'
+)
+
+VIRTUALENV=yapf_virtual_environment
+
+python3 -m virtualenv $VIRTUALENV -p $(which python3)
+PYTHON=${VIRTUALENV}/bin/python
+"$PYTHON" -m pip install yapf==0.30.0
+
+$PYTHON -m yapf $ACTION --parallel --recursive --style=setup.cfg "${DIRS[@]}"
diff --git a/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh b/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh
new file mode 100644
index 00000000..0b5014c1
--- /dev/null
+++ b/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# ARGUMENTS
+# $1 - python version in "3.X.Y" format
+# $2 - python tags (as in manylinx images) e.g. "/opt/python/cp37-cp37m"
+PYTHON_VERSION="$1"
+PYTHON_RELEASE="$2"
+PYTHON_PREFIX="$3"
+
+curl -O "https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_RELEASE}.tar.xz"
+tar -xf "Python-${PYTHON_RELEASE}.tar.xz"
+pushd "Python-${PYTHON_RELEASE}"
+
+# In this step, we are building python that can run on the architecture where the build runs (x64).
+# Since the CC, CXX and other env vars are set by default to point to the crosscompilation toolchain,
+# we explicitly unset them to end up with x64 python binaries.
+(unset AS AR CC CPP CXX LD && ./configure --prefix="${PYTHON_PREFIX}" && make -j 4 && make install)
+
+# When building the crosscompiled native extension, python will automatically add its include directory
+# that contains "Python.h" and other headers. But since we are going to be crosscompiling
+# the wheels, we need the pyconfig.h that corresponds to the target architecture.
+# Since pyconfig.h is the only generated header and python itself (once built) doesn't
+# really need this header anymore, we simply generate a new pyconfig.h using our crosscompilation
+# toolchain and overwrite the current ("wrong") version in the python's include directory.
+./configure && cp pyconfig.h "${PYTHON_PREFIX}"/include/python*
+
+popd
+# remove the build directory to decrease the overall docker image size
+rm -rf "Python-${PYTHON_VERSION}"
+
+# install cython and wheel
+"${PYTHON_PREFIX}/bin/pip3" install --upgrade cython wheel
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
new file mode 100644
index 00000000..e12d5f23
--- /dev/null
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+# directories to run against
+DIRS="examples/cpp examples/android/binder src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby src/objective-c tools/distrib/python"
+
+# file matching patterns to check
+GLOB="*.h *.c *.cc *.m *.mm"
+
+# clang format command
+CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
+
+files=
+for dir in $DIRS
+do
+ for glob in $GLOB
+ do
+ files="$files `find ${CLANG_FORMAT_ROOT}/$dir -name $glob -and -not -name '*.generated.*' -and -not -name '*.upb.h' -and -not -name '*.upb.c' -and -not -name '*.upbdefs.h' -and -not -name '*.upbdefs.c' -and -not -name '*.pb.h' -and -not -name '*.pb.c' -and -not -name '*.pb.cc' -and -not -name '*.pbobjc.h' -and -not -name '*.pbobjc.m' -and -not -name '*.pbrpc.h' -and -not -name '*.pbrpc.m' -and -not -name end2end_tests.cc -and -not -name end2end_nosec_tests.cc -and -not -name public_headers_must_be_c89.c -and -not -name grpc_shadow_boringssl.h`"
+ done
+done
+
+# The CHANGED_FILES variable is used to restrict the set of files to check.
+# Here we set files to the intersection of files and CHANGED_FILES
+if [ -n "$CHANGED_FILES" ]; then
+ files=$(comm -12 <(echo $files | tr ' ' '\n' | sort -u) <(echo $CHANGED_FILES | tr ' ' '\n' | sort -u))
+fi
+
+if [ "$TEST" == "" ]
+then
+ echo $files | xargs $CLANG_FORMAT -i
+else
+ ok=yes
+ for file in $files
+ do
+ tmp=`mktemp`
+ $CLANG_FORMAT $file > $tmp
+ diff -u $file $tmp || ok=no
+ rm $tmp
+ done
+ if [ $ok == no ]
+ then
+ false
+ fi
+fi
diff --git a/tools/dockerfile/grpc_clang_tidy/clang_tidy_all_the_things.sh b/tools/dockerfile/grpc_clang_tidy/clang_tidy_all_the_things.sh
new file mode 100644
index 00000000..1127679d
--- /dev/null
+++ b/tools/dockerfile/grpc_clang_tidy/clang_tidy_all_the_things.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# clang format command
+CLANG_TIDY=${CLANG_TIDY:-clang-tidy}
+
+cd ${CLANG_TIDY_ROOT}
+
+# run clang tidy for all source files
+cat compile_commands.json | jq -r '.[].file' \
+ | grep -E "(^include/|^src/core/|^src/cpp/|^test/core/|^test/cpp/)" \
+ | grep -v -E "/upb-generated/|/upbdefs-generated/" \
+ | sort \
+ | xargs tools/distrib/run_clang_tidy.py "$@"
diff --git a/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
new file mode 100644
index 00000000..ab3382b4
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Grpc.AspNetCore.Server interop server in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-dotnet /var/local/git/grpc-dotnet
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-dotnet
+
+# If needed, update dotnet SDK and put it on path
+./build/get-dotnet.sh
+# Normally we would source ./activate.sh
+# to add dotnet to PATH, but that would only
+# work for the build and not for a subsequent
+# dotnet run from a different shell,
+# so we create a symlink instead.
+# TODO(jtattermusch): Come up with a cleaner solution.
+if [ -f $(pwd)/.dotnet/dotnet ]
+then
+ ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet
+fi
+
+# Cloning from a local path sets RepositoryUrl to a path and breaks Source Link.
+# Override RepositoryUrl to a URL to fix Source Link. The value doesn't matter.
+dotnet build --configuration Debug --output ./output/InteropTestsWebsite testassets/InteropTestsWebsite/InteropTestsWebsite.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git -p:LatestFramework=true
+dotnet build --configuration Debug --output ./output/InteropTestsClient testassets/InteropTestsClient/InteropTestsClient.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git -p:LatestFramework=true
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
new file mode 100644
index 00000000..1c25ab32
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds C# interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# build C# interop client & server
+tools/run_tests/run_tests.py -l csharp -c dbg --build_only
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/build_interop.sh
new file mode 100644
index 00000000..1c25ab32
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds C# interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# build C# interop client & server
+tools/run_tests/run_tests.py -l csharp -c dbg --build_only
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
new file mode 100644
index 00000000..54c0fa89
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds C++ interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# Install the roots.pem
+mkdir -p /usr/local/share/grpc
+cp etc/roots.pem /usr/local/share/grpc/roots.pem
+
+# build C++ interop client, interop server and http2 interop client
+mkdir -p cmake/build
+cd cmake/build
+cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ../..
+make interop_client interop_server -j4
+make http2_client -j4
diff --git a/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh
new file mode 100644
index 00000000..2b4c07ed
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Dart interop server and client in a base image.
+set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-dart /var/local/git/grpc-dart
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-dart/interop
+# De-flake attempt: run the cmd one more time in case of transient failure
+/usr/lib/dart/bin/pub get --verbose || /usr/lib/dart/bin/pub get --verbose
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
new file mode 100644
index 00000000..309340cb
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Go interop server and client in a base image.
+set -e
+
+# Turn on support for Go modules.
+export GO111MODULE=on
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.11/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go1.11/build_interop.sh
new file mode 100644
index 00000000..309340cb
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.11/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Go interop server and client in a base image.
+set -e
+
+# Turn on support for Go modules.
+export GO111MODULE=on
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh
new file mode 100644
index 00000000..309340cb
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Go interop server and client in a base image.
+set -e
+
+# Turn on support for Go modules.
+export GO111MODULE=on
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.8/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go1.8/build_interop.sh
new file mode 100644
index 00000000..b11ace3a
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.8/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Go interop server and client in a base image.
+set -e
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# Get all gRPC Go dependencies
+(cd src/google.golang.org/grpc && make deps && make testdeps)
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
new file mode 100644
index 00000000..c1bafd26
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds http2 interop client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# compile the tests
+(cd /var/local/git/grpc/tools/http2_interop && go test -c)
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
new file mode 100644
index 00000000..06f2d121
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Java interop server and client in a base image.
+set -e
+
+cp -r /var/local/jenkins/grpc-java /tmp/grpc-java
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+pushd /tmp/grpc-java
+# make two attempts; downloads can fail. See https://github.com/grpc/grpc/issues/18892
+./gradlew --no-daemon :grpc-interop-testing:installDist -PskipCodegen=true -PskipAndroid=true || \
+ ./gradlew --no-daemon :grpc-interop-testing:installDist -PskipCodegen=true -PskipAndroid=true
+
+mkdir -p /var/local/git/grpc-java/
+cp -r --parents -t /var/local/git/grpc-java/ \
+ interop-testing/build/install/ \
+ run-test-client.sh \
+ run-test-server.sh
+
+popd
+rm -r /tmp/grpc-java
+rm -r "$HOME/.gradle"
+
+# enable extra java logging
+mkdir -p /var/local/grpc_java_logging
+echo "handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = ALL
+.level = FINE
+io.grpc.netty.NettyClientHandler = ALL
+io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
new file mode 100644
index 00000000..aeb82e0c
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Node interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-node /var/local/git/grpc-node
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc-node/ && git submodule foreach 'cd /var/local/git/grpc-node \
+&& git submodule update --init --recursive --reference /var/local/jenkins/grpc-node/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-node
+
+# build Node interop client & server
+./setup_interop.sh
diff --git a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh
new file mode 100644
index 00000000..db55f5a1
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Node interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-node /var/local/git/grpc-node
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc-node/ && git submodule foreach 'cd /var/local/git/grpc-node \
+&& git submodule update --init --recursive --reference /var/local/jenkins/grpc-node/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-node
+
+# build Node interop client & server
+./setup_interop_purejs.sh
diff --git a/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
new file mode 100644
index 00000000..0ef722d8
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds PHP interop server and client in a base image.
+set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+grpc_root="$(pwd)"
+
+# Install gRPC C core
+make -j4 shared_c static_c
+
+# Build gRPC PHP native extension
+pushd src/php/ext/grpc
+phpize
+GRPC_LIB_SUBDIR=libs/opt ./configure --enable-grpc="${grpc_root}"
+make -j4
+popd
+
+cd src/php
+
+DONE=0
+for ((i = 0; i < 5; i++)); do
+ php -d extension=ext/grpc/modules/grpc.so /usr/local/bin/composer install && DONE=1 && break
+done
+
+if [ "$DONE" != "1" ]
+then
+ echo "Failed to do composer install"
+ exit 1
+fi
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
new file mode 100644
index 00000000..c6818285
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Python interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# interop tests only run using python3.9 currently (and python build is slow)
+tools/run_tests/run_tests.py -l python --compiler python3.9 -c opt --build_only
diff --git a/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/build_interop.sh
new file mode 100644
index 00000000..c6818285
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/build_interop.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Python interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+
+# interop tests only run using python3.9 currently (and python build is slow)
+tools/run_tests/run_tests.py -l python --compiler python3.9 -c opt --build_only
diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
new file mode 100644
index 00000000..e71ad914
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Ruby interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc
+rvm --default use ruby-2.5
+
+# build Ruby interop client and server
+(cd src/ruby && gem install bundler -v 1.17.3 && bundle && rake compile)
diff --git a/tools/dockerfile/push_testing_images.sh b/tools/dockerfile/push_testing_images.sh
new file mode 100644
index 00000000..3c9ad50d
--- /dev/null
+++ b/tools/dockerfile/push_testing_images.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds selected testing docker images and pushes them to dockerhub.
+# Useful for testing environments where it's impractical (or impossible)
+# to rely on docker images being cached locally after they've been built
+# for the first time (which might be costly especially for some images).
+# NOTE: gRPC docker images intended to be used by end users are NOT
+# pushed using this script (they're built automatically by dockerhub).
+# This script is only for "internal" images we use when testing gRPC.
+
+set -ex
+
+cd $(dirname $0)/../..
+git_root=$(pwd)
+cd -
+
+DOCKERHUB_ORGANIZATION=grpctesting
+
+for DOCKERFILE_DIR in tools/dockerfile/test/* tools/dockerfile/grpc_artifact_* tools/dockerfile/interoptest/* tools/dockerfile/distribtest/* third_party/rake-compiler-dock/*/
+do
+ # Generate image name based on Dockerfile checksum. That works well as long
+ # as can count on dockerfiles being written in a way that changing the logical
+ # contents of the docker image always changes the SHA (e.g. using "ADD file"
+ # cmd in the dockerfile in not ok as contents of the added file will not be
+ # reflected in the SHA).
+ DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)
+ DOCKER_IMAGE_TAG=$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+
+ # skip the image if it already exists in the repo
+ curl --silent -f -lSL https://registry.hub.docker.com/v2/repositories/${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}/tags/${DOCKER_IMAGE_TAG} > /dev/null \
+ && continue
+
+ docker build -t ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} ${DOCKERFILE_DIR}
+
+ # "docker login" needs to be run in advance
+ docker push ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}
+done
diff --git a/tools/doxygen/run_doxygen.sh b/tools/doxygen/run_doxygen.sh
new file mode 100644
index 00000000..645686d5
--- /dev/null
+++ b/tools/doxygen/run_doxygen.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../..
+
+src/php/bin/php_extension_to_php_doc.sh generate
+
+for i in core c++ core.internal c++.internal objc objc.internal php
+do
+ rm -rf doc/ref/$i
+ mkdir -p doc/ref/$i
+ doxygen tools/doxygen/Doxyfile.$i
+done
+
+src/php/bin/php_extension_to_php_doc.sh cleanup
diff --git a/tools/gce/create_linux_kokoro_performance_worker.sh b/tools/gce/create_linux_kokoro_performance_worker.sh
new file mode 100644
index 00000000..62e0fdf4
--- /dev/null
+++ b/tools/gce/create_linux_kokoro_performance_worker.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a performance worker on GCE to be used on Kokoro.
+
+# IMPORTANT: Instructions for updating
+# If the VM configuration / installed software is updated,
+# - all existing performance worker VMs need to be updated to reflect the changes
+# - a new GCE image named "grpc-performance-kokoro-v1" needs to be created,
+# incrementing the version number.
+# - kokoro jobs need to be reconfigured to use the new image version
+
+set -ex
+
+cd "$(dirname "$0")"
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b # this zone allows 32core machines
+
+INSTANCE_NAME="${1:-grpc-kokoro-performance-server1}"
+MACHINE_TYPE=e2-standard-32
+
+gcloud compute instances create "$INSTANCE_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --machine-type $MACHINE_TYPE \
+ --image-project ubuntu-os-cloud \
+ --image-family ubuntu-1804-lts \
+ --boot-disk-size 300 \
+ --scopes https://www.googleapis.com/auth/bigquery \
+ --tags=allow-ssh
+
+echo 'Created GCE instance, waiting 60 seconds for it to come online.'
+sleep 60
+
+gcloud compute copy-files \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ kokoro_performance.pub linux_kokoro_performance_worker_init.sh "kbuilder@${INSTANCE_NAME}":~
+
+gcloud compute ssh \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ "kbuilder@${INSTANCE_NAME}" --command "./linux_kokoro_performance_worker_init.sh"
diff --git a/tools/gce/create_linux_kokoro_performance_worker_from_image.sh b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
new file mode 100644
index 00000000..412015f8
--- /dev/null
+++ b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a performance worker on GCE from an image that's used for kokoro
+# perf workers.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b # this zone allows 32core machines
+LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v5 # update if newer image exists
+
+INSTANCE_NAME="${1:-grpc-kokoro-performance-server}"
+MACHINE_TYPE="${2:-e2-standard-32}"
+
+gcloud compute instances create "$INSTANCE_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --machine-type "$MACHINE_TYPE" \
+ --image-project "$CLOUD_PROJECT" \
+ --image "$LATEST_PERF_WORKER_IMAGE" \
+ --boot-disk-size 300 \
+ --scopes https://www.googleapis.com/auth/bigquery \
+ --tags=allow-ssh
diff --git a/tools/gce/create_win2019_container_vm.sh b/tools/gce/create_win2019_container_vm.sh
new file mode 100644
index 00000000..02db428e
--- /dev/null
+++ b/tools/gce/create_win2019_container_vm.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a worker for debugging/experiments.
+# The worker will have all the prerequisites that are installed on kokoro
+# windows workers.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b
+
+if [ "$1" != "" ]
+then
+ INSTANCE_NAME="$1"
+else
+ INSTANCE_NAME="${USER}-win2019-for-containers-test1"
+fi
+
+MACHINE_TYPE=e2-standard-8
+
+# The image version might need updating.
+gcloud compute instances create "$INSTANCE_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --machine-type "$MACHINE_TYPE" \
+ --boot-disk-size=400GB \
+ --boot-disk-type pd-ssd \
+ --image-project=windows-cloud \
+ --image-family=windows-2019-for-containers
+
+# or use --image-family=windows-2019-core-for-containers
diff --git a/tools/gce/create_windows_debug_worker.sh b/tools/gce/create_windows_debug_worker.sh
new file mode 100644
index 00000000..fe8168c1
--- /dev/null
+++ b/tools/gce/create_windows_debug_worker.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a worker for debugging/experiments.
+# The worker will have all the prerequisites that are installed on kokoro
+# windows workers.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b
+
+if [ "$1" != "" ]
+then
+ INSTANCE_NAME="$1"
+else
+ INSTANCE_NAME="${USER}-windows-kokoro-debug1"
+fi
+
+MACHINE_TYPE=e2-standard-8
+TMP_DISK_NAME="$INSTANCE_NAME-temp-disk"
+
+gcloud compute disks create "$TMP_DISK_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --image-project google.com:kokoro \
+ --image empty-100g-image \
+ --type pd-ssd
+
+echo 'Created scratch disk, waiting for it to become available.'
+sleep 15
+
+# The image version might need updating.
+gcloud compute instances create "$INSTANCE_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --machine-type "$MACHINE_TYPE" \
+ --image-project google.com:kokoro \
+ --image kokoro-winserver2016-v2m-prod-debug \
+ --boot-disk-size 500 \
+ --boot-disk-type pd-ssd \
+ --tags=allow-ssh \
+ --disk "auto-delete=yes,boot=no,name=$TMP_DISK_NAME"
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
new file mode 100644
index 00000000..14083a2c
--- /dev/null
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -0,0 +1,231 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Initializes a fresh GCE VM to become a Kokoro Linux performance worker.
+# You shouldn't run this script on your own,
+# use create_linux_kokoro_performance_worker.sh instead.
+
+set -ex
+
+sudo apt-get update
+
+# Install Java 8 JDK (to build gRPC Java)
+sudo apt-get install -y openjdk-8-jdk
+sudo apt-get install -y unzip lsof
+
+sudo apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ gcc \
+ gcc-multilib \
+ git \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libcurl4-openssl-dev \
+ libgtest-dev \
+ libreadline-dev \
+ libssl-dev \
+ libtool \
+ make \
+ strace \
+ python-dev \
+ python-pip \
+ python-setuptools \
+ python-yaml \
+ python3-dev \
+ python3-pip \
+ python3-setuptools \
+ python3-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip \
+ zlib1g-dev
+
+# perftools
+sudo apt-get install -y google-perftools libgoogle-perftools-dev
+
+# netperf
+sudo apt-get install -y netperf
+
+# required to run kokoro_log_reader.py
+sudo apt-get install -y python-psutil python3-psutil
+
+# gcloud tools, including gsutil
+sudo apt-get install -y google-cloud-sdk
+
+# C++ dependencies
+sudo apt-get install -y libgtest-dev libc++-dev clang
+
+# Python dependencies
+sudo pip install --upgrade pip==19.3.1
+sudo pip install tabulate
+sudo pip install google-api-python-client oauth2client
+sudo pip install virtualenv
+
+# pypy is used instead of python for postprocessing benchmark outputs
+# because some reports are huge and pypy is much faster.
+# TODO(jtattermusch): get rid of pypy once possible, it's hard to
+# keep track of all the installed variants of python.
+sudo apt-get install -y pypy pypy-dev
+curl -O https://bootstrap.pypa.io/get-pip.py
+sudo pypy get-pip.py
+sudo pypy -m pip install tabulate
+sudo pypy -m pip install google-api-python-client oauth2client
+# TODO(jtattermusch): for some reason, we need psutil installed
+# in pypy for kokoro_log_reader.py (strange, because the command is
+# "python kokoro_log_reader.py" and pypy is not the system default)
+sudo pypy -m pip install psutil
+
+# Node dependencies (nvm has to be installed under user kbuilder)
+touch .profile
+curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# silence shellcheck as it cannot follow the following `source` path statically:
+# shellcheck disable=SC1090
+source ~/.nvm/nvm.sh
+nvm install 0.12 && npm config set cache /tmp/npm-cache
+nvm install 4 && npm config set cache /tmp/npm-cache
+nvm install 5 && npm config set cache /tmp/npm-cache
+nvm alias default 4
+
+# C# dependencies
+sudo apt-get install -y cmake
+
+# C# mono dependencies (http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives)
+sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
+sudo apt-get update
+sudo apt-get install -y mono-devel
+
+# C# .NET Core dependencies (https://www.microsoft.com/net/download)
+wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
+sudo dpkg -i packages-microsoft-prod.deb
+
+sudo apt-get install -y apt-transport-https
+sudo apt-get update
+sudo apt-get install -y dotnet-sdk-2.1
+
+# Install .NET Core 1.0.5 Runtime (required to run netcoreapp1.0)
+wget -q https://download.microsoft.com/download/2/4/A/24A06858-E8AC-469B-8AE6-D0CEC9BA982A/dotnet-ubuntu.16.04-x64.1.0.5.tar.gz
+mkdir -p dotnet105_download
+tar zxf dotnet-ubuntu.16.04-x64.1.0.5.tar.gz -C dotnet105_download
+sudo cp -r dotnet105_download/shared/Microsoft.NETCore.App/1.0.5/ /usr/share/dotnet/shared/Microsoft.NETCore.App/
+# To prevent "Failed to initialize CoreCLR, HRESULT: 0x80131500" with .NET Core 1.0.5 runtime
+wget -q http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu55_55.1-7ubuntu0.4_amd64.deb
+sudo dpkg -i libicu55_55.1-7ubuntu0.4_amd64.deb
+
+# Install .NET Core 1.1.10 runtime (required to run netcoreapp1.1)
+wget -q -O dotnet_old.tar.gz https://download.visualstudio.microsoft.com/download/pr/b25b5650-0cb8-4699-a347-48d73650da0b/920966211e9bb1907232bbda1faa895a/dotnet-ubuntu.18.04-x64.1.1.10.tar.gz
+mkdir -p dotnet_old
+tar zxf dotnet_old.tar.gz -C dotnet_old
+sudo cp -r dotnet_old/shared/Microsoft.NETCore.App/1.1.10/ /usr/share/dotnet/shared/Microsoft.NETCore.App/
+
+# Ruby dependencies
+gpg --keyserver hkp://pgp.mit.edu --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+curl -sSL https://get.rvm.io | bash -s stable --ruby
+# silence shellcheck as it cannot follow the following `source` path statically:
+# shellcheck disable=SC1090
+source ~/.rvm/scripts/rvm
+
+git clone https://github.com/rbenv/rbenv.git ~/.rbenv
+export PATH="$HOME/.rbenv/bin:$PATH"
+eval "$(rbenv init -)"
+
+git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
+export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
+
+rbenv install 2.4.0
+rbenv global 2.4.0
+ruby -v
+
+# Install bundler (prerequisite for gRPC Ruby)
+gem install bundler
+
+# PHP dependencies
+sudo apt-get install -y php7.2 php7.2-dev php-pear unzip zlib1g-dev
+sudo wget https://phar.phpunit.de/phpunit-8.5.8.phar && \
+ sudo mv phpunit-8.5.8.phar /usr/local/bin/phpunit && \
+ sudo chmod +x /usr/local/bin/phpunit
+curl -sS https://getcomposer.org/installer | php
+sudo mv composer.phar /usr/local/bin/composer
+
+# Java dependencies - nothing as we already have Java JDK 8
+
+# Go dependencies
+# Currently, the golang package available via apt-get doesn't have the latest go.
+# Significant performance improvements with grpc-go have been observed after
+# upgrading from go 1.5 to a later version, so a later go version is preferred.
+# Following go install instructions from https://golang.org/doc/install
+GO_VERSION=1.10
+OS=linux
+ARCH=amd64
+curl -O https://storage.googleapis.com/golang/go${GO_VERSION}.${OS}-${ARCH}.tar.gz
+sudo tar -C /usr/local -xzf go$GO_VERSION.$OS-$ARCH.tar.gz
+# Put go on the PATH, keep the usual installation dir
+sudo ln -s /usr/local/go/bin/go /usr/bin/go
+rm go$GO_VERSION.$OS-$ARCH.tar.gz
+
+# Install perf, to profile benchmarks. (need to get the right linux-tools-<> for kernel version)
+sudo apt-get install -y linux-tools-common linux-tools-generic "linux-tools-$(uname -r)"
+# see http://unix.stackexchange.com/questions/14227/do-i-need-root-admin-permissions-to-run-userspace-perf-tool-perf-events-ar
+echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
+# see http://stackoverflow.com/questions/21284906/perf-couldnt-record-kernel-reference-relocation-symbol
+echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
+
+# qps workers under perf appear to need a lot of mmap pages under certain scenarios and perf args in
+# order to not lose perf events or time out
+echo 4096 | sudo tee /proc/sys/kernel/perf_event_mlock_kb
+
+# Fetch scripts to generate flame graphs from perf data collected
+# on benchmarks
+git clone -v https://github.com/brendangregg/FlameGraph ~/FlameGraph
+
+# Install scipy and numpy for benchmarking scripts
+sudo apt-get install -y python3-scipy python3-numpy
+
+# Install docker
+curl -sSL https://get.docker.com/ | sh
+# Enable kbuilder to use docker without sudo:
+sudo usermod -aG docker kbuilder
+
+# Add pubkey of Kokoro driver VM to allow SSH
+# silence false-positive shellcheck warning ("< redirect does not affect sudo")
+# shellcheck disable=SC2024
+sudo tee --append ~kbuilder/.ssh/authorized_keys < kokoro_performance.pub
+
+# Kokoro requires /tmpfs/READY file to exist the directory and file itself should
+# be owned by kbuilder.
+sudo mkdir /tmpfs
+sudo chown kbuilder /tmpfs
+touch /tmpfs/READY
+
+# Disable automatic updates to prevent spurious apt-get install failures
+# See https://github.com/grpc/grpc/issues/17794
+sudo sed -i 's/APT::Periodic::Update-Package-Lists "1"/APT::Periodic::Update-Package-Lists "0"/' /etc/apt/apt.conf.d/10periodic
+sudo sed -i 's/APT::Periodic::AutocleanInterval "1"/APT::Periodic::AutocleanInterval "0"/' /etc/apt/apt.conf.d/10periodic
+sudo sed -i 's/APT::Periodic::Update-Package-Lists "1"/APT::Periodic::Update-Package-Lists "0"/' /etc/apt/apt.conf.d/20auto-upgrades
+sudo sed -i 's/APT::Periodic::Unattended-Upgrade "1"/APT::Periodic::Unattended-Upgrade "0"/' /etc/apt/apt.conf.d/20auto-upgrades
+
+# Restart for VM to pick up kernel update
+echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
+sleep 10
+sudo reboot
diff --git a/tools/gource/gen-all-logs.sh b/tools/gource/gen-all-logs.sh
new file mode 100644
index 00000000..154162cf
--- /dev/null
+++ b/tools/gource/gen-all-logs.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+outdir=`pwd`
+
+tmpdir=`mktemp -d`
+mkdir -p $tmpdir/logs
+repos="grpc grpc-common grpc-go grpc-java grpc.github.io"
+for repo in $repos
+do
+ cd $tmpdir
+ git clone https://github.com/grpc/$repo.git
+ cd $repo
+ gource --output-custom-log $tmpdir/logs/$repo
+ sed -i "s,|/,|/$repo/,g" $tmpdir/logs/$repo
+done
+cat $tmpdir/logs/* | sort -n > $outdir/all-logs.txt
diff --git a/tools/gource/gource.sh b/tools/gource/gource.sh
new file mode 100644
index 00000000..248404aa
--- /dev/null
+++ b/tools/gource/gource.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+gource \
+ --multi-sampling \
+ -s 0.1 \
+ --max-file-lag 0.05 \
+ --max-files 0 \
+ -e 0.01 \
+ --hide filenames,dirnames,mouse,progress \
+ --disable-auto-rotate \
+ --file-filter '/grpc/doc/ref' \
+ $*
diff --git a/tools/gource/make-video.sh b/tools/gource/make-video.sh
new file mode 100644
index 00000000..b5b6c404
--- /dev/null
+++ b/tools/gource/make-video.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+dst=$1
+shift
+$(dirname $0)/gource.sh \
+ --disable-progress \
+ --stop-at-end \
+ --output-ppm-stream - \
+ $@ | \
+avconv \
+ -y \
+ -r 60 \
+ -f image2pipe \
+ -vcodec ppm \
+ -i - \
+ -vcodec libx264 \
+ $dst
diff --git a/tools/internal_ci/helper_scripts/delete_nonartifacts.sh b/tools/internal_ci/helper_scripts/delete_nonartifacts.sh
new file mode 100644
index 00000000..01e9427e
--- /dev/null
+++ b/tools/internal_ci/helper_scripts/delete_nonartifacts.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+# After kokoro build finishes, the workspace gets rsync'ed to another machine,
+# from where the artifacts and reports are processed.
+# Especially on Windows, the rsync can take long time, so we cleanup the workspace
+# after finishing each build. We only leave files we want to keep:
+# - reports and artifacts
+# - directory containing the kokoro scripts to prevent deleting a script while being executed.
+time find . -type f -not -iname "*sponge_log.*" -not -path "./reports/*" -not -path "./artifacts/*" -not -path "./tools/internal_ci/*" -exec rm -f {} +
diff --git a/tools/internal_ci/linux/aws/grpc_aws_experiment_remote.sh b/tools/internal_ci/linux/aws/grpc_aws_experiment_remote.sh
new file mode 100644
index 00000000..66a661e5
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_aws_experiment_remote.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+#install ubuntu pre-requisites
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+cd grpc
+
+# without port server running, many tests will fail
+python tools/run_tests/start_port_server.py
+
+# build with bazel
+tools/bazel build --config=opt //test/...
diff --git a/tools/internal_ci/linux/aws/grpc_aws_run_remote_test.sh b/tools/internal_ci/linux/aws/grpc_aws_run_remote_test.sh
new file mode 100644
index 00000000..ad95eae2
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_aws_run_remote_test.sh
@@ -0,0 +1,147 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# WARNING: this script has been reviewed by the security team, so
+# any changes need to be made with great care.
+# Contact @jtattermusch or @amidlash if in doubt.
+
+# This script is responsible for remotely running tests on an ARM instance.
+# At the start, it provisions a new AWS ARM64 instance and then uses
+# it to execute a test script (and cleans up afterwards).
+# It should return a status code useful to the kokoro infrastructure.
+
+# TODO(jtattermusch): make the script safe to run under "set -ex"
+set -e
+
+if [ -z "$KOKORO_KEYSTORE_DIR" ]; then
+ echo "KOKORO_KEYSTORE_DIR is unset. This must be run from kokoro"
+ exit 1
+fi
+
+AWS_CREDENTIALS=${KOKORO_KEYSTORE_DIR}/73836_grpc_aws_ec2_credentials
+
+# Setup aws cli
+curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
+unzip -q awscliv2.zip
+sudo ./aws/install
+aws --version
+
+# authenticate with aws cli
+mkdir ~/.aws/
+echo "[default]" >> ~/.aws/config
+ln -s $AWS_CREDENTIALS ~/.aws/credentials
+
+# setup instance
+sudo apt update && sudo apt install -y jq
+
+# ubuntu 18.04 lts(arm64)
+# https://aws.amazon.com/amazon-linux-ami/
+AWS_MACHINE_IMAGE=ami-026141f3d5c6d2d0c
+# use 4-core instance by default
+AWS_INSTANCE_TYPE=${AWS_INSTANCE_TYPE:-t4g.xlarge}
+AWS_SECURITY_GROUP=sg-021240e886feba750
+# Max allowed lifespan of the AWS instance. After this period of time, the instance will
+# self-terminate (delete itself). This is very important to ensure that there will
+# be no orphaned AWS instances if the initiating kokoro job fails / gets cancelled etc.
+AWS_INSTANCE_MAX_LIFESPAN_MINS=120
+# increase the size of the root volume so that builds don't run out of disk space
+AWS_STORAGE_SIZE_GB=75
+AWS_DEVICE_MAPPING="DeviceName='/dev/sda1',Ebs={VolumeSize=${AWS_STORAGE_SIZE_GB}}"
+AWS_INSTANCE_TAGS="ResourceType='instance',Tags=[{Key='kokoro_job_name',Value='${KOKORO_JOB_NAME}'},{Key='kokoro_build_number',Value='${KOKORO_BUILD_NUMBER}'},{Key='kokoro_aws_integration',Value='true'}]"
+
+ssh-keygen -N '' -t rsa -b 4096 -f ~/.ssh/temp_client_key
+ssh-keygen -N '' -t ecdsa -b 256 -f ~/.ssh/temp_server_key
+SERVER_PRIVATE_KEY=$(cat ~/.ssh/temp_server_key | sed 's/\(.*\)/ \1/')
+SERVER_PUBLIC_KEY=$(cat ~/.ssh/temp_server_key.pub | awk '{print $1 " " $2 " root@localhost"}')
+SERVER_HOST_KEY_ENTRY=$(cat ~/.ssh/temp_server_key.pub | awk '{print $1 " " $2}')
+CLIENT_PUBLIC_KEY=$(cat ~/.ssh/temp_client_key.pub)
+
+echo '#cloud-config' > userdata
+echo 'ssh_authorized_keys:' >> userdata
+echo " - $CLIENT_PUBLIC_KEY" >> userdata
+echo 'ssh_keys:' >> userdata
+echo ' ecdsa_private: |' >> userdata
+echo "$SERVER_PRIVATE_KEY" >> userdata
+echo " ecdsa_public: $SERVER_PUBLIC_KEY" >> userdata
+echo '' >> userdata
+echo 'runcmd:' >> userdata
+echo " - sleep ${AWS_INSTANCE_MAX_LIFESPAN_MINS}m" >> userdata
+echo ' - shutdown' >> userdata
+
+ID=$(aws ec2 run-instances --image-id $AWS_MACHINE_IMAGE --instance-initiated-shutdown-behavior=terminate \
+ --instance-type $AWS_INSTANCE_TYPE \
+ --security-group-ids $AWS_SECURITY_GROUP \
+ --user-data file://userdata \
+ --block-device-mapping "$AWS_DEVICE_MAPPING" \
+ --tag-specifications "$AWS_INSTANCE_TAGS" \
+ --region us-east-2 | jq .Instances[0].InstanceId | sed 's/"//g')
+echo "instance-id=$ID"
+echo "Waiting 1m for instance ip..."
+sleep 1m
+IP=$(aws ec2 describe-instances \
+ --instance-id=$ID \
+ --region us-east-2 | jq .Reservations[0].Instances[0].NetworkInterfaces[0].Association.PublicIp | sed 's/"//g')
+SERVER_HOST_KEY_ENTRY="$IP $SERVER_HOST_KEY_ENTRY"
+echo $SERVER_HOST_KEY_ENTRY >> ~/.ssh/known_hosts
+echo "Waiting 2m for instance to initialize..."
+sleep 2m
+
+echo "Copying workspace to remote instance..."
+# use rsync over ssh since it's much faster than scp
+time rsync -e "ssh -i ~/.ssh/temp_client_key" -a github/grpc ubuntu@$IP:~/workspace
+echo "Beginning CI workload..."
+
+# filename of the test script to execute remotely, relative to gRPC repository root
+# use a default value if the env variable is not set
+REMOTE_WORKLOAD_SCRIPT=${REMOTE_WORKLOAD_SCRIPT:-tools/internal_ci/linux/aws/grpc_aws_experiment_remote.sh}
+
+# run remote workload script in the background, with redirected stdout and stderr
+# to avoid problems with ssh session not closing after the remote script finishes
+# but stdout and stderr are still open because the remote has spawned subprocesses
+# that keep stdout and stderr open.
+# * PID of the process that executes the remote script will be stored in aws_build.pid
+# * stderr and stdout will be streamed to aws_build.log
+# * once done, the exitcode of the remote script will be in aws_build.exitcode
+REMOTE_WORKLOAD_COMMAND="nohup bash -c '(bash grpc/${REMOTE_WORKLOAD_SCRIPT}; echo \$? >/tmp/aws_build.exitcode) >>/tmp/aws_build.log 2>&1' >/dev/null 2>&1 & echo \$! >/tmp/aws_build.pid"
+
+# the tail command simply streams the contents of aws_build.log as they become available
+# and stops when the remote workload exits (determined based on the PID)
+SSH_COMMAND='uname -a; rm -f /tmp/aws_build.log /tmp/aws_build.exitcode /tmp/aws_build.pid; touch /tmp/aws_build.log; cd ~/workspace; '"${REMOTE_WORKLOAD_COMMAND};"' tail -f /tmp/aws_build.log --pid $(cat /tmp/aws_build.pid); exit $(cat /tmp/aws_build.exitcode)'
+
+REMOTE_SCRIPT_EXITCODE=0
+time ssh -i ~/.ssh/temp_client_key ubuntu@$IP "${SSH_COMMAND}" || REMOTE_SCRIPT_EXITCODE=$?
+
+echo "Copying artifacts from the remote instance..."
+ARTIFACT_RSYNC_PATTERN="**/*sponge_log.*"
+# NOTE: the include "*/" rule and --prune-empty-dirs are important for not
+# excluding parent directories that contain artifacts before they have
+# get a chance to be examined (see man rsync)
+COPY_ARTIFACTS_EXITCODE=0
+time rsync -av -e "ssh -i ~/.ssh/temp_client_key" --include="${ARTIFACT_RSYNC_PATTERN}" --include="*/" --exclude="*" --prune-empty-dirs ubuntu@$IP:~/workspace/grpc github || COPY_ARTIFACTS_EXITCODE=$?
+
+# Regardless of the remote script's result (success or failure), initiate shutdown of AWS instance a minute from now.
+# The small delay is useful to make sure the ssh session doesn't hang up on us if shutdown happens too quickly.
+echo "Shutting down instance $ID."
+ssh -i ~/.ssh/temp_client_key ubuntu@$IP "sudo shutdown +1" || echo "WARNING: Failed to initiate AWS instance shutdown."
+
+if [ "$REMOTE_SCRIPT_EXITCODE" == "0" ] && [ "$COPY_ARTIFACTS_EXITCODE" != "0" ]
+then
+ echo "Exiting with exitcode $COPY_ARTIFACTS_EXITCODE since remote script has passed, but copying artifacts has failed."
+ exit $COPY_ARTIFACTS_EXITCODE
+fi
+
+# Match exitcode
+echo "Exiting with exitcode $REMOTE_SCRIPT_EXITCODE based on remote script output."
+exit $REMOTE_SCRIPT_EXITCODE
diff --git a/tools/internal_ci/linux/aws/grpc_aws_run_remote_test_8core.sh b/tools/internal_ci/linux/aws/grpc_aws_run_remote_test_8core.sh
new file mode 100644
index 00000000..257d0831
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_aws_run_remote_test_8core.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+AWS_INSTANCE_TYPE="t4g.2xlarge" "$(dirname $0)/grpc_aws_run_remote_test.sh"
diff --git a/tools/internal_ci/linux/aws/grpc_bazel_test_c_cpp_aarch64.sh b/tools/internal_ci/linux/aws/grpc_bazel_test_c_cpp_aarch64.sh
new file mode 100644
index 00000000..f6855be0
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_bazel_test_c_cpp_aarch64.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# install pre-requisites for gRPC C core build
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+cd grpc
+
+# tests require port server to be running
+python tools/run_tests/start_port_server.py
+
+# test gRPC C/C++ with bazel
+tools/bazel test --config=opt --test_output=errors --test_tag_filters=-no_linux,-no_arm64 --build_tag_filters=-no_linux,-no_arm64 --flaky_test_attempts=1 --runs_per_test=1 //test/...
diff --git a/tools/internal_ci/linux/aws/grpc_run_basictests_csharp_aarch64.sh b/tools/internal_ci/linux/aws/grpc_run_basictests_csharp_aarch64.sh
new file mode 100644
index 00000000..ef1aa2cd
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_run_basictests_csharp_aarch64.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# install pre-requisites for gRPC C core build
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+# install gRPC C# pre-requisites
+curl -sSL -o dotnet-install.sh https://dot.net/v1/dotnet-install.sh
+chmod u+x dotnet-install.sh
+./dotnet-install.sh --channel 2.1 # needed for the netcoreapp2.1 targets
+./dotnet-install.sh --channel 5.0
+export PATH="$HOME/.dotnet:$PATH"
+
+# Disable some unwanted dotnet options
+export NUGET_XMLDOC_MODE=skip
+export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
+export DOTNET_CLI_TELEMETRY_OPTOUT=true
+
+dotnet --list-sdks
+
+cd grpc
+
+git submodule update --init
+
+# build and test C#
+tools/run_tests/run_tests.py -l csharp -c opt --compiler coreclr -t -x run_tests/csharp_linux_aarch64_opt_native/sponge_log.xml --report_suite_name csharp_linux_aarch64_opt_native --report_multi_target
diff --git a/tools/internal_ci/linux/aws/grpc_run_basictests_php_aarch64.sh b/tools/internal_ci/linux/aws/grpc_run_basictests_php_aarch64.sh
new file mode 100644
index 00000000..6c98881b
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_run_basictests_php_aarch64.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# install pre-requisites for gRPC C core build
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+# install gRPC Ruby pre-requisites
+sudo apt install -y php7.2-cli php7.2-dev
+sudo apt install -y composer phpunit
+sudo apt install -y php-bcmath # required by protobuf PHP, is it really needed for gRPC?
+
+cd grpc
+
+git submodule update --init
+
+# build and test php
+tools/run_tests/run_tests.py -l php7 -c opt -t -x run_tests/php7_linux_aarch64_opt_native/sponge_log.xml --report_suite_name php7_linux_aarch64_opt_native --report_multi_target
diff --git a/tools/internal_ci/linux/aws/grpc_run_basictests_python_aarch64.sh b/tools/internal_ci/linux/aws/grpc_run_basictests_python_aarch64.sh
new file mode 100644
index 00000000..231e393b
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_run_basictests_python_aarch64.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# install pre-requisites for gRPC C core build
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+# install python3.6 and pip
+sudo apt install -y python3 python3-pip
+python3 --version
+
+cd grpc
+
+git submodule update --init
+
+# build and test python (currently we only test with python3.6, but that's ok since our aarch64 testing resources are limited)
+tools/run_tests/run_tests.py -l python --compiler python3.6 -c opt --iomgr_platform native -t -x run_tests/python_linux_opt_native/sponge_log.xml --report_suite_name python_linux_opt_native --report_multi_target || FAILED=true
+tools/run_tests/run_tests.py -l python --compiler python3.6 -c opt --iomgr_platform asyncio -t -x run_tests/python_linux_opt_asyncio/sponge_log.xml --report_suite_name python_linux_opt_asyncio --report_multi_target || FAILED=true
+tools/run_tests/run_tests.py -l python --compiler python3.6 -c opt --iomgr_platform gevent -t -x run_tests/python_linux_opt_gevent/sponge_log.xml --report_suite_name python_linux_opt_gevent --report_multi_target || FAILED=true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/aws/grpc_run_basictests_ruby_aarch64.sh b/tools/internal_ci/linux/aws/grpc_run_basictests_ruby_aarch64.sh
new file mode 100644
index 00000000..54707e2e
--- /dev/null
+++ b/tools/internal_ci/linux/aws/grpc_run_basictests_ruby_aarch64.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# install pre-requisites for gRPC C core build
+sudo apt update
+sudo apt install -y build-essential autoconf libtool pkg-config cmake python python-pip clang
+sudo pip install six
+
+# install gRPC Ruby pre-requisites
+sudo apt install -y ruby ruby-dev
+sudo gem install bundler
+ruby --version
+
+cd grpc
+
+git submodule update --init
+
+# build and test ruby
+tools/run_tests/run_tests.py -l ruby -c opt -t -x run_tests/ruby_linux_aarch64_opt_native/sponge_log.xml --report_suite_name ruby_linux_aarch64_opt_native --report_multi_target
diff --git a/tools/internal_ci/linux/grpc_android.sh b/tools/internal_ci/linux/grpc_android.sh
new file mode 100644
index 00000000..e0bee1cb
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_android.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# Accept the Android SDK licences.
+yes | /opt/android-sdk/current/tools/bin/sdkmanager --licenses
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+REPO_ROOT="$(pwd)"
+
+git submodule update --init
+
+# Build protoc and grpc_cpp_plugin. Codegen is not cross-compiled to Android
+mkdir -p cmake/build
+pushd cmake/build
+cmake -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release ../..
+make protoc grpc_cpp_plugin -j2
+popd
+
+PROTOC=${REPO_ROOT}/cmake/build/third_party/protobuf/protoc
+PLUGIN=${REPO_ROOT}/cmake/build/grpc_cpp_plugin
+
+# Build and run interop instrumentation tests on Firebase Test Lab
+
+cd "${REPO_ROOT}/src/android/test/interop/"
+./gradlew assembleDebug \
+ "-Pprotoc=${PROTOC}" \
+ "-Pgrpc_cpp_plugin=${PLUGIN}"
+./gradlew assembleDebugAndroidTest \
+ "-Pprotoc=${PROTOC}" \
+ "-Pgrpc_cpp_plugin=${PLUGIN}"
+gcloud firebase test android run \
+ --type instrumentation \
+ --app app/build/outputs/apk/debug/app-debug.apk \
+ --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
+ --device model=Nexus6P,version=27,locale=en,orientation=portrait \
+ --device model=Nexus6P,version=26,locale=en,orientation=portrait \
+ --device model=Nexus6P,version=25,locale=en,orientation=portrait \
+ --device model=Nexus6P,version=24,locale=en,orientation=portrait \
+ --device model=Nexus6P,version=23,locale=en,orientation=portrait \
+ --device model=Nexus6,version=22,locale=en,orientation=portrait \
+ --device model=Nexus6,version=21,locale=en,orientation=portrait \
+ --device model=walleye,version=28,locale=en,orientation=portrait
+
+
+# Build hello world example
+
+cd "${REPO_ROOT}/examples/android/helloworld"
+./gradlew build \
+ "-Pprotoc=${PROTOC}" \
+ "-Pgrpc_cpp_plugin=${PLUGIN}"
diff --git a/tools/internal_ci/linux/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
new file mode 100644
index 00000000..87ec60c7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan --cache_test_results=no
+
diff --git a/tools/internal_ci/linux/grpc_bazel.sh b/tools/internal_ci/linux/grpc_bazel.sh
new file mode 100644
index 00000000..2b17fa84
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=$BAZEL_SCRIPT
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
new file mode 100644
index 00000000..21c4bb24
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Test basic Bazel features
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+# Build all basic targets using the strict warning option which leverages the
+# clang compiler to check if sources can pass a set of warning options.
+# For now //examples/android/binder/ are excluded because it needs Android
+# SDK/NDK to be installed to build
+bazel build --define=use_strict_warning=true \
+ -- \
+ :all \
+ //src/core/... \
+ //src/compiler/... \
+ //test/... \
+ //examples/... \
+ -//examples/android/binder/...
+
+# TODO(jtattersmusch): Adding a build here for --define=grpc_no_xds is not ideal
+# and we should find a better place for this. Refer
+# https://github.com/grpc/grpc/pull/24536#pullrequestreview-517466531 for more
+# details.
+# Test that builds with --define=grpc_no_xds=true work.
+bazel build //test/cpp/end2end:end2end_test --define=grpc_no_xds=true
+# Test that builds that need xDS do not build with --define=grpc_no_xds=true
+EXIT_CODE=0
+bazel build //test/cpp/end2end:xds_end2end_test --define=grpc_no_xds=true || EXIT_CODE=$?
+if [ $EXIT_CODE -eq 0 ]
+then
+ echo "Building xds_end2end_test succeeded even with --define=grpc_no_xds=true"
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_bazel_distribtest.sh b/tools/internal_ci/linux/grpc_bazel_distribtest.sh
new file mode 100644
index 00000000..34a99454
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_distribtest.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build portability tests with an updated submodule
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=test/distrib/bazel/run_bazel_distrib_test.sh
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_bazel_distribtest_latest.sh b/tools/internal_ci/linux/grpc_bazel_distribtest_latest.sh
new file mode 100644
index 00000000..11de6638
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_distribtest_latest.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build portability tests with an updated submodule
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=/test/distrib/bazel/test_latest_bazel_version.sh
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
new file mode 100644
index 00000000..d5b38de3
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# make sure bazel is available
+tools/bazel version
+
+# to get "bazel" link for kokoro build, we need to generate
+# invocation UUID, set a flag for bazel to use it
+# and upload "bazel_invocation_ids" file as artifact.
+BAZEL_INVOCATION_ID="$(uuidgen)"
+echo "${BAZEL_INVOCATION_ID}" >"${KOKORO_ARTIFACTS_DIR}/bazel_invocation_ids"
+
+tools/bazel \
+ --bazelrc=tools/remote_build/kokoro.bazelrc \
+ test \
+ --invocation_id="${BAZEL_INVOCATION_ID}" \
+ --workspace_status_command=tools/remote_build/workspace_status_kokoro.sh \
+ $@ \
+ -- //test/... || FAILED="true"
+
+if [ "$UPLOAD_TEST_RESULTS" != "" ]
+then
+ # Sleep to let ResultStore finish writing results before querying
+ sleep 60
+ python ./tools/run_tests/python_utils/upload_rbe_results.py
+fi
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
new file mode 100644
index 00000000..06b93f3d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+EXTRA_FLAGS="--config=dbg --cache_test_results=no"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
new file mode 100644
index 00000000..66effabf
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+EXTRA_FLAGS="--config=opt --cache_test_results=no"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_bazel_privileged_docker.sh b/tools/internal_ci/linux/grpc_bazel_privileged_docker.sh
new file mode 100644
index 00000000..ae1056d7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_privileged_docker.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2019 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=$BAZEL_SCRIPT
+# NET_ADMIN capability allows tests to manipulate network interfaces
+exec tools/run_tests/dockerize/build_and_run_docker.sh --cap-add NET_ADMIN
diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh
new file mode 100644
index 00000000..85b82443
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# Use bazelisk to download the right bazel version
+wget https://github.com/bazelbuild/bazelisk/releases/download/v0.0.7/bazelisk-linux-amd64
+chmod u+x bazelisk-linux-amd64
+
+# We want bazelisk to run the latest stable version
+export USE_BAZEL_VERSION=latest
+# Use bazelisk instead of our usual //tools/bazel wrapper
+mv bazelisk-linux-amd64 github/grpc/tools/bazel
+
+EXTRA_FLAGS="--config=opt --cache_test_results=no"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
new file mode 100644
index 00000000..639a0855
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Test full Bazel
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+bazel test //test/...
+bazel test //test/cpp/end2end:admin_services_end2end_test --define=grpc_no_xds=true
diff --git a/tools/internal_ci/linux/grpc_binder_transport_apk.sh b/tools/internal_ci/linux/grpc_binder_transport_apk.sh
new file mode 100644
index 00000000..d85474a5
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_binder_transport_apk.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/binder_transport_apk
+export DOCKER_RUN_SCRIPT=$BAZEL_SCRIPT
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_binder_transport_apk_build_in_docker.sh b/tools/internal_ci/linux/grpc_binder_transport_apk_build_in_docker.sh
new file mode 100644
index 00000000..454e2fe1
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_binder_transport_apk_build_in_docker.sh
@@ -0,0 +1,44 @@
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!/usr/bin/env bash
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+echo $ANDROID_HOME
+echo $ANDROID_NDK_HOME
+
+# Build all targets using the strict warning option which leverages the
+# clang compiler to check if sources can pass a set of warning options.
+# CPU are specified because gRPC does not build with 32bit NDK (which has socklen_t
+# defined as int due to an accident).
+# The python option is for disabling python2 enforcement when packing APK
+bazel build --define=use_strict_warning=true \
+ --fat_apk_cpu=x86_64,arm64-v8a \
+ --extra_toolchains=@rules_python//python:autodetecting_toolchain_nonstrict \
+ //examples/android/binder/java/io/grpc/binder/cpp/exampleclient:app \
+ //examples/android/binder/java/io/grpc/binder/cpp/exampleserver:app
+
+# Make sure the Java code that will be invoked by binder transport
+# implementation builds
+bazel build --define=use_strict_warning=true \
+ @binder_transport_android_helper//io/grpc/binder/cpp:connection_helper
diff --git a/tools/internal_ci/linux/grpc_build_artifacts.sh b/tools/internal_ci/linux/grpc_build_artifacts.sh
new file mode 100644
index 00000000..985243e9
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_artifacts.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+tools/run_tests/task_runner.py -f artifact linux -j 6
diff --git a/tools/internal_ci/linux/grpc_build_artifacts_extra.sh b/tools/internal_ci/linux/grpc_build_artifacts_extra.sh
new file mode 100644
index 00000000..718123d7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_artifacts_extra.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+tools/run_tests/task_runner.py -f artifact linux_extra armv7 -j 6
diff --git a/tools/internal_ci/linux/grpc_build_packages.sh b/tools/internal_ci/linux/grpc_build_packages.sh
new file mode 100644
index 00000000..ff71298a
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_packages.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+# Move artifacts generated by the previous step in the build chain to a place
+# where they can be accessed from within a docker container that builds
+# the packages
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+chmod +x input_artifacts/protoc*/* || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f package linux -j 6
diff --git a/tools/internal_ci/linux/grpc_build_submodule_at_head.sh b/tools/internal_ci/linux/grpc_build_submodule_at_head.sh
new file mode 100644
index 00000000..58aa5e7a
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_submodule_at_head.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build portability tests with an updated submodule
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# Submodule name is passed as the RUN_TESTS_FLAGS variable
+SUBMODULE_NAME="${RUN_TESTS_FLAGS}"
+
+# Name of branch to checkout is passed as BAZEL_FLAGS variable
+# If unset, "master" is used by default.
+SUBMODULE_BRANCH_NAME="${BAZEL_FLAGS:-master}"
+
+# Update submodule to be tested at HEAD
+(cd "third_party/${SUBMODULE_NAME}" && git fetch origin && git checkout "origin/${SUBMODULE_BRANCH_NAME}")
+
+echo "This suite tests whether gRPC HEAD builds with HEAD of submodule '${SUBMODULE_NAME}'"
+echo "If a test breaks, either"
+echo "1) some change in the grpc repository has caused the failure"
+echo "2) some change that was just merged in the submodule head has caused the failure."
+
+echo ""
+echo "submodule '${SUBMODULE_NAME}' is at commit: $(cd third_party/${SUBMODULE_NAME}; git rev-parse --verify HEAD)"
+
+if [ "${SUBMODULE_NAME}" == "abseil-cpp" ]
+then
+ src/abseil-cpp/preprocessed_builds.yaml.gen.py
+fi
+
+tools/buildgen/generate_projects.sh
+
+if [ "${SUBMODULE_NAME}" == "protobuf" ]
+then
+ tools/distrib/python/make_grpcio_tools.py
+fi
+
+# commit so that changes are passed to Docker
+git -c user.name='foo' -c user.email='foo@google.com' commit -a -m 'Update submodule' --allow-empty
+
+tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 8 -j 4 --internal_ci --build_only
diff --git a/tools/internal_ci/linux/grpc_coverage.sh b/tools/internal_ci/linux/grpc_coverage.sh
new file mode 100644
index 00000000..a91cffdf
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_coverage.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+python tools/run_tests/run_tests.py \
+ -l c c++ -x coverage_cpp/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l python -x coverage_python/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l ruby -x coverage_ruby/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+python tools/run_tests/run_tests.py \
+ -l php -x coverage_php/sponge_log.xml \
+ --use_docker -t -c gcov -j 2 || FAILED="true"
+
+# HTML reports can't be easily displayed in GCS, so create a zip archive
+# and put it under reports directory to get it uploaded as an artifact.
+zip -q -r coverage_report.zip reports || true
+rm -rf reports || true
+mkdir reports || true
+mv coverage_report.zip reports || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_distribtests.sh b/tools/internal_ci/linux/grpc_distribtests.sh
new file mode 100644
index 00000000..b2ec2bf3
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+# Move packages generated by the previous step in the build chain to a place
+# where they can be accessed from within a docker container that run the
+# distribtests
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f distribtest linux -j 6
diff --git a/tools/internal_ci/linux/grpc_distribtests_php.sh b/tools/internal_ci/linux/grpc_distribtests_php.sh
new file mode 100644
index 00000000..a0de6701
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests_php.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# Build all PHP linux artifacts
+tools/run_tests/task_runner.py -f artifact linux php -j 4 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+rm -rf artifacts_from_build_artifacts_step
+mv artifacts artifacts_from_build_artifacts_step || true
+
+# This step mostly just copies artifacts from input_artifacts (but it also does some wheel stripping)
+tools/run_tests/task_runner.py -f package linux php -x build_packages/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+
+# Run all PHP linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest linux php -j 4 -x distribtests/sponge_log.xml || FAILED="true"
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_distribtests_python.sh b/tools/internal_ci/linux/grpc_distribtests_python.sh
new file mode 100644
index 00000000..7192fcc7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests_python.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
+# Build all python linux artifacts (this step actually builds all the binary wheels and source archives)
+tools/run_tests/task_runner.py -f artifact linux python -j 6 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+rm -rf artifacts_from_build_artifacts_step
+mv artifacts artifacts_from_build_artifacts_step || true
+
+# This step only copies artifacts from input_artifacts
+tools/run_tests/task_runner.py -f package linux python -x build_packages/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+
+# Run all python linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest linux python -j 6 -x distribtests/sponge_log.xml || FAILED="true"
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_distribtests_ruby.sh b/tools/internal_ci/linux/grpc_distribtests_ruby.sh
new file mode 100644
index 00000000..bb794e7f
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests_ruby.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+# Build all ruby linux artifacts (this step actually builds all the binary wheels and source archives)
+tools/run_tests/task_runner.py -f artifact linux ruby -j 6 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# Ruby "build_package" step is basically just a passthough for the "grpc" gems, so it's enough to just
+# copy the native gems directly to the "distribtests" step and skip the "build_package" phase entirely.
+# Note that by skipping the "build_package" step, we are also skipping the build of "grpc-tools" gem
+# but that's fine since the distribtests only test the "grpc" native gems.
+
+# The next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts.
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/ruby_native_gem_*/* input_artifacts/ || true
+
+# Run all ruby linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest linux ruby -j 6 -x distribtests/sponge_log.xml || FAILED="true"
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_distribtests_standalone.sh b/tools/internal_ci/linux/grpc_distribtests_standalone.sh
new file mode 100644
index 00000000..084daa9b
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests_standalone.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+tools/run_tests/task_runner.py -f distribtest linux cpp -j 6
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_gke.sh b/tools/internal_ci/linux/grpc_e2e_performance_gke.sh
new file mode 100644
index 00000000..89d37f29
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_e2e_performance_gke.sh
@@ -0,0 +1,133 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root.
+cd "$(dirname "$0")/../../.."
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# This is to ensure we can push and pull images from gcr.io. We do not
+# necessarily need it to run load tests, but will need it when we employ
+# pre-built images in the optimization.
+gcloud auth configure-docker
+
+# Connect to benchmarks-prod2 cluster.
+gcloud config set project grpc-testing
+gcloud container clusters get-credentials benchmarks-prod2 \
+ --zone us-central1-b --project grpc-testing
+
+# Set up environment variables.
+LOAD_TEST_PREFIX="${KOKORO_BUILD_INITIATOR}"
+# BEGIN differentiate experimental configuration from master configuration.
+if [[ "${KOKORO_BUILD_INITIATOR%%-*}" == kokoro ]]; then
+ LOAD_TEST_PREFIX=kokoro
+fi
+# Use the "official" BQ tables so that the measurements will show up in the
+# "official" public dashboard.
+BIGQUERY_TABLE_8CORE=e2e_benchmarks.ci_master_results_8core
+BIGQUERY_TABLE_32CORE=e2e_benchmarks.ci_master_results_32core
+# END differentiate experimental configuration from master configuration.
+CLOUD_LOGGING_URL="https://source.cloud.google.com/results/invocations/${KOKORO_BUILD_ID}"
+PREBUILT_IMAGE_PREFIX="gcr.io/grpc-testing/e2etesting/pre_built_workers/${LOAD_TEST_PREFIX}"
+UNIQUE_IDENTIFIER="$(date +%Y%m%d%H%M%S)"
+ROOT_DIRECTORY_OF_DOCKERFILES="../test-infra/containers/pre_built_workers/"
+# Head of the workspace checked out by Kokoro.
+GRPC_GITREF="$(git show --format="%H" --no-patch)"
+# Prebuilt workers for core languages are always built from grpc/grpc.
+if [[ "${KOKORO_GITHUB_COMMIT_URL%/*}" == "https://github.com/grpc/grpc/commit" ]]; then
+ GRPC_CORE_GITREF="${KOKORO_GIT_COMMIT}"
+else
+ GRPC_CORE_GITREF="$(git ls-remote https://github.com/grpc/grpc.git master | cut -f1)"
+fi
+GRPC_GO_GITREF="$(git ls-remote https://github.com/grpc/grpc-go.git master | cut -f1)"
+GRPC_JAVA_GITREF="$(git ls-remote https://github.com/grpc/grpc-java.git master | cut -f1)"
+# Kokoro jobs run on dedicated pools.
+DRIVER_POOL=drivers-ci
+WORKER_POOL_8CORE=workers-c2-8core-ci
+# c2-standard-30 is the closest machine spec to 32 core there is
+WORKER_POOL_32CORE=workers-c2-30core-ci
+
+# Update go version.
+TEST_INFRA_GOVERSION=go1.17.1
+go get "golang.org/dl/${TEST_INFRA_GOVERSION}"
+"${TEST_INFRA_GOVERSION}" download
+
+# Fetch test-infra repository and build all tools.
+# Note: Submodules are not required for tools build.
+pushd ..
+git clone --depth 1 https://github.com/grpc/test-infra.git
+cd test-infra
+git log -1 --oneline
+make GOCMD="${TEST_INFRA_GOVERSION}" all-tools
+popd
+
+# Build test configurations.
+buildConfigs() {
+ local -r pool="$1"
+ local -r table="$2"
+ shift 2
+ tools/run_tests/performance/loadtest_config.py "$@" \
+ -t ./tools/run_tests/performance/templates/loadtest_template_prebuilt_all_languages.yaml \
+ -s driver_pool="${DRIVER_POOL}" -s driver_image= \
+ -s client_pool="${pool}" -s server_pool="${pool}" \
+ -s big_query_table="${table}" -s timeout_seconds=900 \
+ -s prebuilt_image_prefix="${PREBUILT_IMAGE_PREFIX}" \
+ -a ci_buildNumber="${KOKORO_BUILD_NUMBER}" \
+ -a ci_buildUrl="${CLOUD_LOGGING_URL}" \
+ -a ci_jobName="${KOKORO_JOB_NAME}" \
+ -a ci_gitCommit="${GRPC_GITREF}" \
+ -a ci_gitCommit_go="${GRPC_GO_GITREF}" \
+ -a ci_gitCommit_java="${GRPC_JAVA_GITREF}" \
+ -a ci_gitActualCommit="${KOKORO_GIT_COMMIT}" \
+ -s prebuilt_image_tag="${UNIQUE_IDENTIFIER}" \
+ --prefix="${LOAD_TEST_PREFIX}" -u "${UNIQUE_IDENTIFIER}" -u "${pool}" \
+ -a pool="${pool}" --category=scalable \
+ --allow_client_language=c++ --allow_server_language=c++ \
+ -o "./loadtest_with_prebuilt_workers_${pool}.yaml"
+}
+
+buildConfigs "${WORKER_POOL_8CORE}" "${BIGQUERY_TABLE_8CORE}" -l c++ -l csharp -l go -l java -l php7 -l php7_protobuf_c -l python -l ruby
+buildConfigs "${WORKER_POOL_32CORE}" "${BIGQUERY_TABLE_32CORE}" -l c++ -l csharp -l go -l java
+
+# Delete prebuilt images on exit.
+deleteImages() {
+ echo "deleting images on exit"
+ ../test-infra/bin/delete_prebuilt_workers \
+ -p "${PREBUILT_IMAGE_PREFIX}" \
+ -t "${UNIQUE_IDENTIFIER}"
+}
+trap deleteImages EXIT
+
+# Build and push prebuilt images for running tests.
+time ../test-infra/bin/prepare_prebuilt_workers \
+ -l "cxx:${GRPC_CORE_GITREF}" \
+ -l "csharp:${GRPC_CORE_GITREF}" \
+ -l "go:${GRPC_GO_GITREF}" \
+ -l "java:${GRPC_JAVA_GITREF}" \
+ -l "php7:${GRPC_CORE_GITREF}" \
+ -l "python:${GRPC_CORE_GITREF}" \
+ -l "ruby:${GRPC_CORE_GITREF}" \
+ -p "${PREBUILT_IMAGE_PREFIX}" \
+ -t "${UNIQUE_IDENTIFIER}" \
+ -r "${ROOT_DIRECTORY_OF_DOCKERFILES}"
+
+# Run tests.
+time ../test-infra/bin/runner \
+ -i "../grpc/loadtest_with_prebuilt_workers_${WORKER_POOL_8CORE}.yaml" \
+ -i "../grpc/loadtest_with_prebuilt_workers_${WORKER_POOL_32CORE}.yaml" \
+ -delete-successful-tests \
+ -c "${WORKER_POOL_8CORE}:2" -c "${WORKER_POOL_32CORE}:2" \
+ -o "runner/sponge_log.xml"
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
new file mode 100644
index 00000000..d0ba3ac9
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
+
+# "smoketest" scenarios on a single VM (=no remote VM for running qps_workers)
+# TODO(jtattermusch): add back "node" language once the scenarios are passing again
+# See https://github.com/grpc/grpc/issues/20234
+tools/run_tests/run_performance_tests.py \
+ -l c++ csharp ruby java python python_asyncio go php7 php7_protobuf_c \
+ --netperf \
+ --category smoketest \
+ -u kbuilder \
+ --bq_result_table performance_test.performance_experiment_singlevm \
+ --xml_report run_performance_tests/singlemachine/sponge_log.xml
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_v2.sh b/tools/internal_ci/linux/grpc_e2e_performance_v2.sh
new file mode 100644
index 00000000..4e85cd3f
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_e2e_performance_v2.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root.
+cd "$(dirname "$0")/../../.."
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# This is to ensure we can push and pull images from gcr.io. We do not
+# necessarily need it to run load tests, but will need it when we employ
+# pre-built images in the optimization.
+gcloud auth configure-docker
+
+# Connect to benchmarks-prod2 cluster.
+gcloud config set project grpc-testing
+gcloud container clusters get-credentials benchmarks-prod2 \
+ --zone us-central1-b --project grpc-testing
+
+# Set up environment variables.
+LOAD_TEST_PREFIX="${KOKORO_BUILD_INITIATOR}"
+# BEGIN differentiate experimental configuration from master configuration.
+if [[ "${KOKORO_BUILD_INITIATOR%%-*}" == kokoro ]]; then
+ LOAD_TEST_PREFIX=kokoro-test
+fi
+BIGQUERY_TABLE_8CORE=e2e_benchmarks.experimental_results
+BIGQUERY_TABLE_32CORE=e2e_benchmarks.experimental_results_32core
+# END differentiate experimental configuration from master configuration.
+CLOUD_LOGGING_URL="https://source.cloud.google.com/results/invocations/${KOKORO_BUILD_ID}"
+PREBUILT_IMAGE_PREFIX="gcr.io/grpc-testing/e2etesting/pre_built_workers/${LOAD_TEST_PREFIX}"
+UNIQUE_IDENTIFIER="$(date +%Y%m%d%H%M%S)"
+ROOT_DIRECTORY_OF_DOCKERFILES="../test-infra/containers/pre_built_workers/"
+# Head of the workspace checked out by Kokoro.
+GRPC_GITREF="$(git show --format="%H" --no-patch)"
+# Prebuilt workers for core languages are always built from grpc/grpc.
+if [[ "${KOKORO_GITHUB_COMMIT_URL%/*}" == "https://github.com/grpc/grpc/commit" ]]; then
+ GRPC_CORE_GITREF="${KOKORO_GIT_COMMIT}"
+else
+ GRPC_CORE_GITREF="$(git ls-remote https://github.com/grpc/grpc.git master | cut -f1)"
+fi
+GRPC_GO_GITREF="$(git ls-remote https://github.com/grpc/grpc-go.git master | cut -f1)"
+GRPC_JAVA_GITREF="$(git ls-remote https://github.com/grpc/grpc-java.git master | cut -f1)"
+# Kokoro jobs run on dedicated pools.
+DRIVER_POOL=drivers-ci
+WORKER_POOL_8CORE=workers-c2-8core-ci
+# c2-standard-30 is the closest machine spec to 32 core there is
+WORKER_POOL_32CORE=workers-c2-30core-ci
+
+# Update go version.
+TEST_INFRA_GOVERSION=go1.17.1
+go get "golang.org/dl/${TEST_INFRA_GOVERSION}"
+"${TEST_INFRA_GOVERSION}" download
+
+# Fetch test-infra repository and build all tools.
+# Note: Submodules are not required for tools build.
+pushd ..
+git clone --depth 1 https://github.com/grpc/test-infra.git
+cd test-infra
+git log -1 --oneline
+make GOCMD="${TEST_INFRA_GOVERSION}" all-tools
+popd
+
+# Build test configurations.
+buildConfigs() {
+ local -r pool="$1"
+ local -r table="$2"
+ shift 2
+ tools/run_tests/performance/loadtest_config.py "$@" \
+ -t ./tools/run_tests/performance/templates/loadtest_template_prebuilt_all_languages.yaml \
+ -s driver_pool="${DRIVER_POOL}" -s driver_image= \
+ -s client_pool="${pool}" -s server_pool="${pool}" \
+ -s big_query_table="${table}" -s timeout_seconds=900 \
+ -s prebuilt_image_prefix="${PREBUILT_IMAGE_PREFIX}" \
+ -s prebuilt_image_tag="${UNIQUE_IDENTIFIER}" \
+ -a ci_buildNumber="${KOKORO_BUILD_NUMBER}" \
+ -a ci_buildUrl="${CLOUD_LOGGING_URL}" \
+ -a ci_jobName="${KOKORO_JOB_NAME}" \
+ -a ci_gitCommit="${GRPC_GITREF}" \
+ -a ci_gitCommit_go="${GRPC_GO_GITREF}" \
+ -a ci_gitCommit_java="${GRPC_JAVA_GITREF}" \
+ -a ci_gitActualCommit="${KOKORO_GIT_COMMIT}" \
+ --prefix="${LOAD_TEST_PREFIX}" -u "${UNIQUE_IDENTIFIER}" -u "${pool}" \
+ -a pool="${pool}" --category=scalable \
+ --allow_client_language=c++ --allow_server_language=c++ \
+ -o "./loadtest_with_prebuilt_workers_${pool}.yaml"
+}
+
+buildConfigs "${WORKER_POOL_8CORE}" "${BIGQUERY_TABLE_8CORE}" -l c++ -l csharp -l go -l java -l php7 -l php7_protobuf_c -l python -l ruby
+buildConfigs "${WORKER_POOL_32CORE}" "${BIGQUERY_TABLE_32CORE}" -l c++ -l csharp -l go -l java
+
+# Delete prebuilt images on exit.
+deleteImages() {
+ echo "deleting images on exit"
+ ../test-infra/bin/delete_prebuilt_workers \
+ -p "${PREBUILT_IMAGE_PREFIX}" \
+ -t "${UNIQUE_IDENTIFIER}"
+}
+trap deleteImages EXIT
+
+# Build and push prebuilt images for running tests.
+time ../test-infra/bin/prepare_prebuilt_workers \
+ -l "cxx:${GRPC_CORE_GITREF}" \
+ -l "csharp:${GRPC_CORE_GITREF}" \
+ -l "go:${GRPC_GO_GITREF}" \
+ -l "java:${GRPC_JAVA_GITREF}" \
+ -l "php7:${GRPC_CORE_GITREF}" \
+ -l "python:${GRPC_CORE_GITREF}" \
+ -l "ruby:${GRPC_CORE_GITREF}" \
+ -p "${PREBUILT_IMAGE_PREFIX}" \
+ -t "${UNIQUE_IDENTIFIER}" \
+ -r "${ROOT_DIRECTORY_OF_DOCKERFILES}"
+
+# Run tests.
+time ../test-infra/bin/runner \
+ -i "../grpc/loadtest_with_prebuilt_workers_${WORKER_POOL_8CORE}.yaml" \
+ -i "../grpc/loadtest_with_prebuilt_workers_${WORKER_POOL_32CORE}.yaml" \
+ -delete-successful-tests \
+ -c "${WORKER_POOL_8CORE}:2" -c "${WORKER_POOL_32CORE}:2" \
+ -o "runner/sponge_log.xml"
diff --git a/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh b/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh
new file mode 100644
index 00000000..ce8e21c7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Run the flaky network test
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc/test/cpp/end2end
+
+# iptables is used to drop traffic between client and server
+apt-get install -y iptables
+
+bazel test --test_output=all --test_timeout=1200 :flaky_network_test --test_env=GRPC_TRACE=http --test_env=GRPC_VERBOSITY=DEBUG
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.sh b/tools/internal_ci/linux/grpc_full_performance_master.sh
new file mode 100644
index 00000000..019707fc
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_full_performance_master.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
+
+# run 8core client vs 8core server
+tools/run_tests/run_performance_tests.py \
+ -l c++ csharp ruby java python python_asyncio go php7 php7_protobuf_c node \
+ --netperf \
+ --category scalable \
+ --remote_worker_host grpc-kokoro-performance-server-8core grpc-kokoro-performance-client-8core grpc-kokoro-performance-client2-8core \
+ -u kbuilder \
+ --bq_result_table performance_test.performance_experiment \
+ --xml_report run_performance_tests/8core/sponge_log.xml \
+ || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports -e run_performance_tests
+
+# scalability with 32cores (and upload to a different BQ table)
+tools/run_tests/run_performance_tests.py \
+ -l c++ java csharp go \
+ --netperf \
+ --category scalable \
+ --remote_worker_host grpc-kokoro-performance-server-32core grpc-kokoro-performance-client-32core grpc-kokoro-performance-client2-32core \
+ -u kbuilder \
+ --bq_result_table performance_test.performance_experiment_32core \
+ --xml_report run_performance_tests/32core/sponge_log.xml \
+ || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports -e run_performance_tests
+
+exit $EXIT_CODE
diff --git a/tools/internal_ci/linux/grpc_full_performance_release.sh b/tools/internal_ci/linux/grpc_full_performance_release.sh
new file mode 100644
index 00000000..7da5a74c
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_full_performance_release.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
+
+# run 8core client vs 8core server
+tools/run_tests/run_performance_tests.py \
+ -l c++ csharp ruby java python python_asyncio go php7 php7_protobuf_c \
+ --netperf \
+ --category scalable \
+ --remote_worker_host grpc-kokoro-performance-server-8core grpc-kokoro-performance-client-8core grpc-kokoro-performance-client2-8core \
+ -u kbuilder \
+ --bq_result_table performance_released.performance_experiment \
+ --xml_report run_performance_tests/8core/sponge_log.xml \
+ || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports -e run_performance_tests
+
+# scalability with 32cores (and upload to a different BQ table)
+tools/run_tests/run_performance_tests.py \
+ -l c++ java csharp go \
+ --netperf \
+ --category scalable \
+ --remote_worker_host grpc-kokoro-performance-server-32core grpc-kokoro-performance-client-32core grpc-kokoro-performance-client2-32core \
+ -u kbuilder \
+ --bq_result_table performance_released.performance_experiment_32core \
+ --xml_report run_performance_tests/32core/sponge_log.xml \
+ || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports -e run_performance_tests
+
+exit $EXIT_CODE
diff --git a/tools/internal_ci/linux/grpc_interop_matrix.sh b/tools/internal_ci/linux/grpc_interop_matrix.sh
new file mode 100644
index 00000000..5f1f69db
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_interop_matrix.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export LANG=en_US.UTF-8
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# TODO(jtattermusch): Diagnose out of disk space problems. Remove once not needed.
+df -h
+
+tools/interop_matrix/run_interop_matrix_tests.py $RUN_TESTS_FLAGS || FAILED="true"
+
+# TODO(jtattermusch): Diagnose out of disk space problems. Remove once not needed.
+df -h
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_microbenchmark_diff.sh b/tools/internal_ci/linux/grpc_microbenchmark_diff.sh
new file mode 100644
index 00000000..580c184b
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_microbenchmark_diff.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by Jenkins and runs a diff on the microbenchmarks
+set -ex
+
+# List of benchmarks that provide good signal for analyzing performance changes in pull requests
+BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong bm_fullstack_streaming_pump bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata"
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
+
+tools/run_tests/start_port_server.py
+tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/bloat/bloat_diff.py \
+ -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" || FAILED="true"
+tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \
+ -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \
+ -b $BENCHMARKS_TO_RUN || FAILED="true"
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
new file mode 100644
index 00000000..c7e4b1fa
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_performance_profile_daily.sh b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
new file mode 100644
index 00000000..013f1ab8
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
+
+CPUS=`python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())'`
+
+./tools/run_tests/start_port_server.py || true
+
+tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload || FAILED="true"
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_performance_profile_master.sh b/tools/internal_ci/linux/grpc_performance_profile_master.sh
new file mode 100644
index 00000000..93454b7f
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_performance_profile_master.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
+
+tools/internal_ci/linux/run_performance_profile_hourly.sh || FAILED="true"
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
+
diff --git a/tools/internal_ci/linux/grpc_publish_packages.sh b/tools/internal_ci/linux/grpc_publish_packages.sh
new file mode 100644
index 00000000..1cf639be
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_publish_packages.sh
@@ -0,0 +1,249 @@
+#!/bin/bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+shopt -s nullglob
+
+cd "$(dirname "$0")/../../.."
+
+GRPC_VERSION=$(grep -e "^ *version: " build_handwritten.yaml | head -n 1 | sed 's/.*: //')
+
+INPUT_ARTIFACTS=$KOKORO_GFILE_DIR/github/grpc/artifacts
+INDEX_FILENAME=index.xml
+
+BUILD_ID=${KOKORO_BUILD_ID:-$(uuidgen)}
+BUILD_BRANCH_NAME=master
+BUILD_GIT_COMMIT=${KOKORO_GIT_COMMIT:-unknown}
+BUILD_TIMESTAMP=$(date -Iseconds)
+BUILD_RELPATH=$(date "+%Y/%m")/$BUILD_GIT_COMMIT-$BUILD_ID/
+
+GCS_ROOT=gs://packages.grpc.io/
+GCS_ARCHIVE_PREFIX=archive/
+GCS_ARCHIVE_ROOT=$GCS_ROOT$GCS_ARCHIVE_PREFIX
+GCS_INDEX=$GCS_ROOT$INDEX_FILENAME
+
+LOCAL_STAGING_TEMPDIR=$(mktemp -d)
+LOCAL_BUILD_ROOT=$LOCAL_STAGING_TEMPDIR/$BUILD_RELPATH
+LOCAL_BUILD_INDEX=$LOCAL_BUILD_ROOT$INDEX_FILENAME
+
+mkdir -p "$LOCAL_BUILD_ROOT"
+
+find "$INPUT_ARTIFACTS" -type f
+
+# protoc Plugins
+PROTOC_PLUGINS_ZIPPED_PACKAGES=$(mktemp -d)
+for zip_dir in protoc_windows_{x86,x64}
+do
+ zip -jr "$PROTOC_PLUGINS_ZIPPED_PACKAGES/grpc-$zip_dir-$GRPC_VERSION.zip" "$INPUT_ARTIFACTS/$zip_dir/"*
+done
+for tar_dir in protoc_linux_{x86,x64} protoc_macos_x64
+do
+ chmod +x "$INPUT_ARTIFACTS/$tar_dir"/*
+ tar -cvzf "$PROTOC_PLUGINS_ZIPPED_PACKAGES/grpc-$tar_dir-$GRPC_VERSION.tar.gz" -C "$INPUT_ARTIFACTS/$tar_dir" .
+done
+
+PROTOC_PACKAGES=(
+ "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_windows_{x86,x64}-"$GRPC_VERSION.zip"
+ "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_linux_{x86,x64}-"$GRPC_VERSION.tar.gz"
+ "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_macos_x64-"$GRPC_VERSION.tar.gz"
+)
+
+# C#
+UNZIPPED_CSHARP_PACKAGES=$(mktemp -d)
+unzip "$INPUT_ARTIFACTS/csharp_nugets_windows_dotnetcli.zip" -d "$UNZIPPED_CSHARP_PACKAGES"
+CSHARP_PACKAGES=(
+ "$UNZIPPED_CSHARP_PACKAGES"/*
+ "$INPUT_ARTIFACTS"/grpc_unity_package.[0-9]*.zip
+)
+
+# Python
+PYTHON_GRPCIO_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpcio-[0-9]*.tar.gz
+ "$INPUT_ARTIFACTS"/grpcio-[0-9]*.whl
+ "$INPUT_ARTIFACTS"/python_linux_extra_arm*/grpcio-[0-9]*.whl
+)
+PYTHON_GRPCIO_TOOLS_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpcio-tools-[0-9]*.tar.gz
+ "$INPUT_ARTIFACTS"/grpcio_tools-[0-9]*.whl
+ "$INPUT_ARTIFACTS"/python_linux_extra_arm*/grpcio_tools-[0-9]*.whl
+)
+PYTHON_GRPCIO_HEALTH_CHECKING_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpcio-health-checking-[0-9]*.tar.gz
+)
+PYTHON_GRPCIO_REFLECTION_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpcio-reflection-[0-9]*.tar.gz
+)
+PYTHON_GRPCIO_TESTING_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpcio-testing-[0-9]*.tar.gz
+)
+
+# PHP
+PHP_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpc-[0-9]*.tgz
+)
+
+# Ruby
+RUBY_PACKAGES=(
+ "$INPUT_ARTIFACTS"/grpc-[0-9]*.gem
+ "$INPUT_ARTIFACTS"/grpc-tools-[0-9]*.gem
+)
+
+function add_to_manifest() {
+ local artifact_type=$1
+ local artifact_file=$2
+ local artifact_prefix=$3
+ local artifact_name
+ artifact_name=$(basename "$artifact_file")
+ local artifact_size
+ artifact_size=$(stat -c%s "$artifact_file")
+ local artifact_sha256
+ artifact_sha256=$(openssl sha256 -r "$artifact_file" | cut -d " " -f 1)
+ local artifact_target=$LOCAL_BUILD_ROOT/$artifact_type/$artifact_prefix
+ mkdir -p "$artifact_target"
+ cp "$artifact_file" "$artifact_target"
+ cat <
+EOF
+}
+
+{
+ cat <
+
+
+
+ gRPC
+ https://github.com/grpc/grpc
+ $BUILD_BRANCH_NAME
+ $BUILD_GIT_COMMIT
+
+
+EOF
+
+ for pkg in "${PROTOC_PACKAGES[@]}"; do add_to_manifest protoc "$pkg"; done
+ for pkg in "${CSHARP_PACKAGES[@]}"; do add_to_manifest csharp "$pkg"; done
+ for pkg in "${PHP_PACKAGES[@]}"; do add_to_manifest php "$pkg"; done
+ for pkg in "${PYTHON_GRPCIO_PACKAGES[@]}"; do add_to_manifest python "$pkg" grpcio/; done
+ for pkg in "${PYTHON_GRPCIO_TOOLS_PACKAGES[@]}"; do add_to_manifest python "$pkg" grpcio-tools/; done
+ for pkg in "${PYTHON_GRPCIO_HEALTH_CHECKING_PACKAGES[@]}"; do add_to_manifest python "$pkg" grpcio-health-checking/; done
+ for pkg in "${PYTHON_GRPCIO_REFLECTION_PACKAGES[@]}"; do add_to_manifest python "$pkg" grpcio-reflection/; done
+ for pkg in "${PYTHON_GRPCIO_TESTING_PACKAGES[@]}"; do add_to_manifest python "$pkg" grpcio-testing/; done
+ for pkg in "${RUBY_PACKAGES[@]}"; do add_to_manifest ruby "$pkg"; done
+
+ cat <
+
+EOF
+}> "$LOCAL_BUILD_INDEX"
+
+LOCAL_BUILD_INDEX_SIZE=$(stat -c%s "$LOCAL_BUILD_INDEX")
+LOCAL_BUILD_INDEX_SHA256=$(openssl sha256 -r "$LOCAL_BUILD_INDEX" | cut -d " " -f 1)
+
+OLD_INDEX=$(mktemp)
+NEW_INDEX=$(mktemp)
+
+# Download the current /index.xml into $OLD_INDEX
+gsutil cp "$GCS_INDEX" "$OLD_INDEX"
+
+{
+ # we want to add an entry as the first child under tag
+ # we can get by without a real XML parser by rewriting the header,
+ # injecting our new tag, and then dumping the rest of the file as is.
+ cat <
+
+
+
+
+EOF
+ tail --lines=+5 "$OLD_INDEX"
+}> "$NEW_INDEX"
+
+
+function generate_directory_index()
+{
+ local target_dir=$1
+ local current_directory_name
+ current_directory_name=$(basename "$target_dir")
+ cat <
+
+
+
+ Index of $current_directory_name - packages.grpc.io
+
+
+
+
"
+ done
+)
+
+cat <
+
+
+EOF
+}
+
+# Upload the current build artifacts
+gsutil -m cp -r "$LOCAL_STAGING_TEMPDIR/${BUILD_RELPATH%%/*}" "$GCS_ARCHIVE_ROOT"
+# Upload directory indices for subdirectories
+(
+ cd "$LOCAL_BUILD_ROOT"
+ find * -type d | while read -r directory
+ do
+ generate_directory_index "$directory" | gsutil -h 'Content-Type:text/html' cp - "$GCS_ARCHIVE_ROOT$BUILD_RELPATH$directory/$INDEX_FILENAME"
+ done
+)
+# Upload the new /index.xml
+gsutil -h "Content-Type:application/xml" cp "$NEW_INDEX" "$GCS_INDEX"
+
+# Upload C# nugets to the dev nuget feed
+pushd "$UNZIPPED_CSHARP_PACKAGES"
+docker pull mcr.microsoft.com/dotnet/core/sdk:2.1
+for nugetfile in *.nupkg
+do
+ echo "Going to push $nugetfile"
+ # use nuget from a docker container to push the nupkg
+ set +x # IMPORTANT: avoid revealing the nuget api key by the command echo
+ docker run -v "$(pwd):/nugets:ro" --rm=true mcr.microsoft.com/dotnet/core/sdk:2.1 bash -c "dotnet nuget push /nugets/$nugetfile -k $(cat ${KOKORO_GFILE_DIR}/artifactory_grpc_nuget_dev_api_key) --source https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev"
+ set -ex
+done
+popd
diff --git a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
new file mode 100644
index 00000000..7724ca66
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Test full Bazel
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc/test
+TEST_TARGETS="//src/python/... //tools/distrib/python/grpcio_tools/... //examples/python/..."
+BAZEL_FLAGS="--test_output=errors"
+bazel test ${BAZEL_FLAGS} ${TEST_TARGETS}
+bazel test --config=python_single_threaded_unary_stream ${BAZEL_FLAGS} ${TEST_TARGETS}
+bazel test --config=python_poller_engine ${BAZEL_FLAGS} ${TEST_TARGETS}
+
+
+# TODO(https://github.com/grpc/grpc/issues/19854): Move this to a new Kokoro
+# job.
+(cd /var/local/git/grpc/bazel/test/python_test_repo;
+ bazel test --test_output=errors //...
+)
diff --git a/tools/internal_ci/linux/grpc_run_interop_tests.sh b/tools/internal_ci/linux/grpc_run_interop_tests.sh
new file mode 100644
index 00000000..1f4eda2d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_run_interop_tests.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export LANG=en_US.UTF-8
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+source tools/internal_ci/helper_scripts/prepare_build_interop_rc
+
+tools/run_tests/run_interop_tests.py $RUN_TESTS_FLAGS
diff --git a/tools/internal_ci/linux/grpc_run_tests_matrix.sh b/tools/internal_ci/linux/grpc_run_tests_matrix.sh
new file mode 100644
index 00000000..a0ce71ae
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_run_tests_matrix.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
+if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ] && [ -n "$RUN_TESTS_FLAGS" ]; then
+ export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"
+fi
+
+tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true"
+
+echo 'Exiting gRPC main test script.'
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_trickle_diff.sh b/tools/internal_ci/linux/grpc_trickle_diff.sh
new file mode 100644
index 00000000..a7640956
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_trickle_diff.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by Jenkins and runs a diff on the microbenchmarks
+set -ex
+
+# List of benchmarks that provide good signal for analyzing performance changes in pull requests
+BENCHMARKS_TO_RUN="cli_transport_stalls_per_iteration cli_stream_stalls_per_iteration svr_transport_stalls_per_iteration svr_stream_stalls_per_iteration"
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
+
+tools/run_tests/start_port_server.py
+tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \
+ -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \
+ -b bm_fullstack_trickle \
+ -l 4 \
+ -t $BENCHMARKS_TO_RUN \
+ --no-counters \
+ --pr_comment_name trickle || FAILED="true"
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
new file mode 100644
index 00000000..fcf3095d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
new file mode 100644
index 00000000..f45be4d1
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_xds.sh b/tools/internal_ci/linux/grpc_xds.sh
new file mode 100644
index 00000000..6de65880
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=$BAZEL_SCRIPT
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
new file mode 100644
index 00000000..4d8daff2
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trap 'date' DEBUG
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+python3 -m pip install virtualenv
+VIRTUAL_ENV=$(mktemp -d)
+python3 -m virtualenv "$VIRTUAL_ENV" -p python3
+PYTHON="$VIRTUAL_ENV"/bin/python
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
+
+# Prepare generated Python code.
+TOOLS_DIR=tools/run_tests
+PROTO_SOURCE_DIR=src/proto/grpc/testing
+PROTO_DEST_DIR="$TOOLS_DIR"/"$PROTO_SOURCE_DIR"
+mkdir -p "$PROTO_DEST_DIR"
+touch "$TOOLS_DIR"/src/__init__.py
+touch "$TOOLS_DIR"/src/proto/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out="$TOOLS_DIR" \
+ --grpc_python_out="$TOOLS_DIR" \
+ "$PROTO_SOURCE_DIR"/test.proto \
+ "$PROTO_SOURCE_DIR"/messages.proto \
+ "$PROTO_SOURCE_DIR"/empty.proto
+
+HEALTH_PROTO_SOURCE_DIR=src/proto/grpc/health/v1
+HEALTH_PROTO_DEST_DIR=${TOOLS_DIR}/${HEALTH_PROTO_SOURCE_DIR}
+mkdir -p ${HEALTH_PROTO_DEST_DIR}
+touch "$TOOLS_DIR"/src/proto/grpc/health/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/health/v1/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${HEALTH_PROTO_SOURCE_DIR}/health.proto
+
+bazel build //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client
+
+# Test cases "path_matching" and "header_matching" are not included in "all",
+# because not all interop clients in all languages support these new tests.
+export PYTHONUNBUFFERED=true
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+ tools/run_tests/run_xds_tests.py \
+ --halt_after_fail \
+ --test_case="ping_pong" \
+ --project_id=grpc-testing \
+ --project_num=830293263384 \
+ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+ --gcp_suffix=$(date '+%s') \
+ --verbose \
+ ${XDS_V3_OPT-} \
+ --client_cmd='bazel run //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {rpcs_to_send} {metadata_to_send}'
diff --git a/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh
new file mode 100644
index 00000000..b820193e
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trap 'date' DEBUG
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+python3 -m pip install virtualenv
+VIRTUAL_ENV=$(mktemp -d)
+python3 -m virtualenv "$VIRTUAL_ENV" -p python3
+PYTHON="$VIRTUAL_ENV"/bin/python
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
+
+# Prepare generated Python code.
+TOOLS_DIR=tools/run_tests
+PROTO_SOURCE_DIR=src/proto/grpc/testing
+PROTO_DEST_DIR="$TOOLS_DIR"/"$PROTO_SOURCE_DIR"
+mkdir -p "$PROTO_DEST_DIR"
+touch "$TOOLS_DIR"/src/__init__.py
+touch "$TOOLS_DIR"/src/proto/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out="$TOOLS_DIR" \
+ --grpc_python_out="$TOOLS_DIR" \
+ "$PROTO_SOURCE_DIR"/test.proto \
+ "$PROTO_SOURCE_DIR"/messages.proto \
+ "$PROTO_SOURCE_DIR"/empty.proto
+
+HEALTH_PROTO_SOURCE_DIR=src/proto/grpc/health/v1
+HEALTH_PROTO_DEST_DIR=${TOOLS_DIR}/${HEALTH_PROTO_SOURCE_DIR}
+mkdir -p ${HEALTH_PROTO_DEST_DIR}
+touch "$TOOLS_DIR"/src/proto/grpc/health/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/health/v1/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${HEALTH_PROTO_SOURCE_DIR}/health.proto
+
+bazel build test/cpp/interop:xds_interop_client
+
+# Test cases "path_matching" and "header_matching" are not included in "all",
+# because not all interop clients in all languages support these new tests.
+#
+# TODO: remove "path_matching" and "header_matching" from --test_case after
+# they are added into "all".
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+ tools/run_tests/run_xds_tests.py \
+ --halt_after_fail \
+ --test_case="ping_pong" \
+ --project_id=grpc-testing \
+ --project_num=830293263384 \
+ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+ --gcp_suffix=$(date '+%s') \
+ --verbose \
+ ${XDS_V3_OPT-} \
+ --client_cmd='bazel-bin/test/cpp/interop/xds_interop_client --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} \
+ {rpcs_to_send} \
+ {metadata_to_send}'
diff --git a/tools/internal_ci/linux/grpc_xds_k8s.sh b/tools/internal_ci/linux/grpc_xds_k8s.sh
new file mode 100644
index 00000000..71bcdb70
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_k8s.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test server/client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+# BUILD_APP_PATH
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+ echo "Building C++ xDS interop test app Docker images"
+ docker build -f "${SRC_DIR}/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client" -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" "${SRC_DIR}"
+ docker build -f "${SRC_DIR}/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_server" -t "${SERVER_IMAGE_NAME}:${GIT_COMMIT}" "${SRC_DIR}"
+ gcloud -q auth configure-docker
+ docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+ docker push "${SERVER_IMAGE_NAME}:${GIT_COMMIT}"
+ if [[ -n $KOKORO_JOB_NAME ]]; then
+ branch_name=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/core/([^/]+)/.*|\1|')
+ tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}"
+ tag_and_push_docker_image "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}"
+ fi
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# FORCE_IMAGE_BUILD
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+ # Check if images already exist
+ server_tags="$(gcloud_gcr_list_image_tags "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Server image: %s:%s\n" "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${server_tags:-Server image not found}"
+
+ client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${client_tags:-Client image not found}"
+
+ # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+ if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${server_tags}" || -z "${client_tags}" ]]; then
+ build_test_app_docker_images
+ else
+ echo "Skipping C++ test app build"
+ fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local test_name="${1:?Usage: run_test test_name}"
+ set -x
+ python -m "tests.${test_name}" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --server_image="${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+ --force_cleanup \
+ --nocheck_local_certs
+ set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_SECURITY
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ else
+ local_setup_test_driver "${script_dir}"
+ fi
+ build_docker_images_if_needed
+ # Run tests
+ cd "${TEST_DRIVER_FULL_DIR}"
+ run_test baseline_test
+ run_test security_test
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh b/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
new file mode 100644
index 00000000..bb333c3f
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
@@ -0,0 +1,457 @@
+#!/usr/bin/env bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# TODO(sergiitk): move to grpc/grpc when implementing support of other languages
+set -eo pipefail
+
+# Constants
+readonly PYTHON_VERSION="3.6"
+# Test driver
+readonly TEST_DRIVER_REPO_NAME="grpc"
+readonly TEST_DRIVER_REPO_URL="https://github.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc.git"
+readonly TEST_DRIVER_BRANCH="${TEST_DRIVER_BRANCH:-master}"
+readonly TEST_DRIVER_PATH="tools/run_tests/xds_k8s_test_driver"
+readonly TEST_DRIVER_PROTOS_PATH="src/proto/grpc/testing"
+
+# GKE cluster identifiers.
+readonly GKE_CLUSTER_PSM_LB="psm-lb"
+readonly GKE_CLUSTER_PSM_SECURITY="psm-security"
+readonly GKE_CLUSTER_PSM_BASIC="psm-basic"
+
+#######################################
+# Determines the cluster name and zone based on the given cluster identifier.
+# Globals:
+# GKE_CLUSTER_NAME: Set to reflect the cluster name to use
+# GKE_CLUSTER_ZONE: Set to reflect the cluster zone to use.
+# Arguments:
+# The cluster identifier
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+activate_gke_cluster() {
+ case $1 in
+ GKE_CLUSTER_PSM_LB)
+ GKE_CLUSTER_NAME="interop-test-psm-lb-v1-us-central1-a"
+ GKE_CLUSTER_ZONE="us-central1-a"
+ ;;
+ GKE_CLUSTER_PSM_SECURITY)
+ GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-central1-a"
+ GKE_CLUSTER_ZONE="us-central1-a"
+ ;;
+ GKE_CLUSTER_PSM_BASIC)
+ GKE_CLUSTER_NAME="interop-test-psm-basic"
+ GKE_CLUSTER_ZONE="us-central1-c"
+ ;;
+ *)
+ echo "Unknown GKE cluster: ${1}"
+ exit 1
+ ;;
+ esac
+ echo "Activated GKE cluster: GKE_CLUSTER_NAME=${GKE_CLUSTER_NAME} GKE_CLUSTER_ZONE=${GKE_CLUSTER_ZONE}"
+}
+
+#######################################
+# Determines the secondary cluster name and zone based on the given cluster
+# identifier.
+# Globals:
+# GKE_CLUSTER_NAME: Set to reflect the cluster name to use
+# GKE_CLUSTER_ZONE: Set to reflect the cluster zone to use.
+# Arguments:
+# The cluster identifier
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+activate_secondary_gke_cluster() {
+ case $1 in
+ GKE_CLUSTER_PSM_LB)
+ SECONDARY_GKE_CLUSTER_NAME="interop-test-psm-lb-v1-us-west1-b"
+ SECONDARY_GKE_CLUSTER_ZONE="us-west1-b"
+ ;;
+ GKE_CLUSTER_PSM_SECURITY)
+ SECONDARY_GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-west1-b"
+ SECONDARY_GKE_CLUSTER_ZONE="us-west1-b"
+ ;;
+ *)
+ echo "Unknown secondary GKE cluster: ${1}"
+ exit 1
+ ;;
+ esac
+ echo "Activated secondary GKE cluster: GKE_CLUSTER_NAME=${GKE_CLUSTER_NAME} GKE_CLUSTER_ZONE=${GKE_CLUSTER_ZONE}"
+}
+
+#######################################
+# Run command end report its exit code. Doesn't exit on non-zero exit code.
+# Globals:
+# None
+# Arguments:
+# Command to execute
+# Outputs:
+# Writes the output of given command to stdout, stderr
+#######################################
+run_ignore_exit_code() {
+ local exit_code=-1
+ "$@" || exit_code=$?
+ echo "Exit code: ${exit_code}"
+}
+
+#######################################
+# Parses information about git repository at given path to global variables.
+# Globals:
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# Arguments:
+# Git source dir
+#######################################
+parse_src_repo_git_info() {
+ local src_dir="${SRC_DIR:?SRC_DIR must be set}"
+ readonly GIT_ORIGIN_URL=$(git -C "${src_dir}" remote get-url origin)
+ readonly GIT_COMMIT=$(git -C "${src_dir}" rev-parse HEAD)
+ readonly GIT_COMMIT_SHORT=$(git -C "${src_dir}" rev-parse --short HEAD)
+}
+
+#######################################
+# List GCR image tags matching given tag name.
+# Arguments:
+# Image name
+# Tag name
+# Outputs:
+# Writes the table with the list of found tags to stdout.
+# If no tags found, the output is an empty string.
+#######################################
+gcloud_gcr_list_image_tags() {
+ gcloud container images list-tags --format="table[box](tags,digest,timestamp.date())" --filter="tags:$2" "$1"
+}
+
+#######################################
+# A helper to execute `gcloud -q components update`.
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud` command to stdout, stderr
+#######################################
+gcloud_update() {
+ echo "Update gcloud components:"
+ gcloud -q components update
+}
+
+#######################################
+# Create kube context authenticated with GKE cluster, saves context name.
+# to KUBE_CONTEXT
+# Globals:
+# GKE_CLUSTER_NAME
+# GKE_CLUSTER_ZONE
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# SECONDARY_KUBE_CONTEXT: Populated with name of kubectl context with secondary GKE cluster access, if any
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud` command to stdout, stderr
+# Writes authorization info $HOME/.kube/config
+#######################################
+gcloud_get_cluster_credentials() {
+ if [[ -n "${SECONDARY_GKE_CLUSTER_NAME}" && -n "${SECONDARY_GKE_CLUSTER_ZONE}" ]]; then
+ gcloud container clusters get-credentials "${SECONDARY_GKE_CLUSTER_NAME}" --zone "${SECONDARY_GKE_CLUSTER_ZONE}"
+ readonly SECONDARY_KUBE_CONTEXT="$(kubectl config current-context)"
+ else
+ readonly SECONDARY_KUBE_CONTEXT=""
+ fi
+ gcloud container clusters get-credentials "${GKE_CLUSTER_NAME}" --zone "${GKE_CLUSTER_ZONE}"
+ readonly KUBE_CONTEXT="$(kubectl config current-context)"
+}
+
+#######################################
+# Clone the source code of the test driver to $TEST_DRIVER_REPO_DIR, unless
+# given folder exists.
+# Globals:
+# TEST_DRIVER_REPO_URL
+# TEST_DRIVER_BRANCH
+# TEST_DRIVER_REPO_DIR: path to the repo containing the test driver
+# TEST_DRIVER_REPO_DIR_USE_EXISTING: set non-empty value to use exiting
+# clone of the driver repo located at $TEST_DRIVER_REPO_DIR.
+# Useful for debugging the build script locally.
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `git` command to stdout, stderr
+# Writes driver source code to $TEST_DRIVER_REPO_DIR
+#######################################
+test_driver_get_source() {
+ if [[ -n "${TEST_DRIVER_REPO_DIR_USE_EXISTING}" && -d "${TEST_DRIVER_REPO_DIR}" ]]; then
+ echo "Using exiting driver directory: ${TEST_DRIVER_REPO_DIR}."
+ else
+ echo "Cloning driver to ${TEST_DRIVER_REPO_URL} branch ${TEST_DRIVER_BRANCH} to ${TEST_DRIVER_REPO_DIR}"
+ git clone -b "${TEST_DRIVER_BRANCH}" --depth=1 "${TEST_DRIVER_REPO_URL}" "${TEST_DRIVER_REPO_DIR}"
+ fi
+}
+
+#######################################
+# Install Python modules from required in $TEST_DRIVER_FULL_DIR/requirements.txt
+# to Python virtual environment. Creates and activates Python venv if necessary.
+# Globals:
+# TEST_DRIVER_FULL_DIR
+# PYTHON_VERSION
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `python`, `pip` commands to stdout, stderr
+# Writes the list of installed modules to stdout
+#######################################
+test_driver_pip_install() {
+ echo "Install python dependencies"
+ cd "${TEST_DRIVER_FULL_DIR}"
+
+ # Create and activate virtual environment unless already using one
+ if [[ -z "${VIRTUAL_ENV}" ]]; then
+ local venv_dir="${TEST_DRIVER_FULL_DIR}/venv"
+ if [[ -d "${venv_dir}" ]]; then
+ echo "Found python virtual environment directory: ${venv_dir}"
+ else
+ echo "Creating python virtual environment: ${venv_dir}"
+ "python${PYTHON_VERSION}" -m venv "${venv_dir}"
+ fi
+ # Intentional: No need to check python venv activate script.
+ # shellcheck source=/dev/null
+ source "${venv_dir}/bin/activate"
+ fi
+
+ pip install -r requirements.txt
+ echo "Installed Python packages:"
+ pip list
+}
+
+#######################################
+# Compile proto-files needed for the test driver
+# Globals:
+# TEST_DRIVER_REPO_DIR
+# TEST_DRIVER_FULL_DIR
+# TEST_DRIVER_PROTOS_PATH
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `python -m grpc_tools.protoc` to stdout, stderr
+# Writes the list if compiled python code to stdout
+# Writes compiled python code with proto messages and grpc services to
+# $TEST_DRIVER_FULL_DIR/src/proto
+#######################################
+test_driver_compile_protos() {
+ declare -a protos
+ protos=(
+ "${TEST_DRIVER_PROTOS_PATH}/test.proto"
+ "${TEST_DRIVER_PROTOS_PATH}/messages.proto"
+ "${TEST_DRIVER_PROTOS_PATH}/empty.proto"
+ )
+ echo "Generate python code from grpc.testing protos: ${protos[*]}"
+ cd "${TEST_DRIVER_REPO_DIR}"
+ python -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out="${TEST_DRIVER_FULL_DIR}" \
+ --grpc_python_out="${TEST_DRIVER_FULL_DIR}" \
+ "${protos[@]}"
+ local protos_out_dir="${TEST_DRIVER_FULL_DIR}/${TEST_DRIVER_PROTOS_PATH}"
+ echo "Generated files ${protos_out_dir}:"
+ ls -Fl "${protos_out_dir}"
+}
+
+#######################################
+# Installs the test driver and it's requirements.
+# https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#installation
+# Globals:
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# Arguments:
+# The directory for test driver's source code
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+test_driver_install() {
+ readonly TEST_DRIVER_REPO_DIR="${1:?Usage test_driver_install TEST_DRIVER_REPO_DIR}"
+ readonly TEST_DRIVER_FULL_DIR="${TEST_DRIVER_REPO_DIR}/${TEST_DRIVER_PATH}"
+ test_driver_get_source
+ test_driver_pip_install
+ test_driver_compile_protos
+}
+
+#######################################
+# Outputs Kokoro image version and Ubuntu's lsb_release
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout
+#######################################
+kokoro_print_version() {
+ echo "Kokoro VM version:"
+ if [[ -f /VERSION ]]; then
+ cat /VERSION
+ fi
+ run_ignore_exit_code lsb_release -a
+}
+
+#######################################
+# Report extra information about the job via sponge properties.
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GIT_ORIGIN_URL
+# GIT_COMMIT_SHORT
+# TESTGRID_EXCLUDE
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout
+# Writes job properties to $KOKORO_ARTIFACTS_DIR/custom_sponge_config.csv
+#######################################
+kokoro_write_sponge_properties() {
+ # CSV format: "property_name","property_value"
+ # Bump TESTS_FORMAT_VERSION when reported test name changed enough to when it
+ # makes more sense to discard previous test results from a testgrid board.
+ # Use GIT_ORIGIN_URL to exclude test runs executed against repo forks from
+ # testgrid reports.
+ cat >"${KOKORO_ARTIFACTS_DIR}/custom_sponge_config.csv" < 0 )); then
+ exit 1
+ fi
+
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh b/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh
new file mode 100644
index 00000000..7cf7318e
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server:13171a8b293837517c0446ec0e149e9d10ea3d10"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+readonly LANGUAGE_NAME="Python"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+# BUILD_APP_PATH
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+ echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images"
+
+ pushd "${SRC_DIR}"
+ docker build \
+ -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \
+ -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ .
+
+ popd
+
+ gcloud -q auth configure-docker
+
+ docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# FORCE_IMAGE_BUILD
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+ # Check if images already exist
+ client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${client_tags:-Client image not found}"
+
+ # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+ if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then
+ build_test_app_docker_images
+ else
+ echo "Skipping ${LANGUAGE_NAME} test app build"
+ fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# SECONDARY_KUBE_CONTEXT: The name of kubectl context with secondary GKE cluster access, if any
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local test_name="${1:?Usage: run_test test_name}"
+ python -m "tests.${test_name}" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --secondary_kube_context="${SECONDARY_KUBE_CONTEXT}" \
+ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ --server_image="${SERVER_IMAGE_NAME}" \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml"
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# SECONDARY_KUBE_CONTEXT: Populated with name of kubectl context with secondary GKE cluster access, if any
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_SECURITY
+ activate_secondary_gke_cluster GKE_CLUSTER_PSM_SECURITY
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ else
+ local_setup_test_driver "${script_dir}"
+ fi
+ build_docker_images_if_needed
+
+ # Run tests
+ cd "${TEST_DRIVER_FULL_DIR}"
+ local failed_tests=0
+ test_suites=("change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test")
+ for test in "${test_suites[@]}"; do
+ run_test $test || (( failed_tests++ ))
+ done
+ echo "Failed test suites: ${failed_tests}"
+ if (( failed_tests > 0 )); then
+ exit 1
+ fi
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_python.sh b/tools/internal_ci/linux/grpc_xds_k8s_python.sh
new file mode 100644
index 00000000..7911596b
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_k8s_python.sh
@@ -0,0 +1,172 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test server/client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-server"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+readonly LANGUAGE_NAME="Python"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+# BUILD_APP_PATH
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+ echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images"
+
+ pushd "${SRC_DIR}"
+ docker build \
+ -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \
+ -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ .
+
+ docker build \
+ -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server \
+ -t "${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+ .
+
+ popd
+
+ gcloud -q auth configure-docker
+
+ docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+ docker push "${SERVER_IMAGE_NAME}:${GIT_COMMIT}"
+
+ if [[ -n $KOKORO_JOB_NAME ]]; then
+ branch_name=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/core/([^/]+)/.*|\1|')
+ tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}"
+ tag_and_push_docker_image "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}"
+ fi
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# FORCE_IMAGE_BUILD
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+ # Check if images already exist
+ server_tags="$(gcloud_gcr_list_image_tags "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Server image: %s:%s\n" "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${server_tags:-Server image not found}"
+
+ client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${client_tags:-Client image not found}"
+
+ # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+ if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${server_tags}" || -z "${client_tags}" ]]; then
+ build_test_app_docker_images
+ else
+ echo "Skipping ${LANGUAGE_NAME} test app build"
+ fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local test_name="${1:?Usage: run_test test_name}"
+ set -x
+ python -m "tests.${test_name}" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --server_image="${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+ --force_cleanup \
+ --nocheck_local_certs
+ set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_SECURITY
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ else
+ local_setup_test_driver "${script_dir}"
+ fi
+ build_docker_images_if_needed
+ # Run tests
+ cd "${TEST_DRIVER_FULL_DIR}"
+ run_test baseline_test
+ run_test security_test
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh b/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh
new file mode 100644
index 00000000..abf4fadc
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test server/client Docker images
+readonly IMAGE_REPO="gcr.io/grpc-testing/xds-interop"
+readonly SERVER_LANG="cpp go java"
+readonly CLIENT_LANG="cpp go java"
+readonly VERSION_TAG="v1.41.x"
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# SERVER_IMAGE_NAME: Test server Docker image name
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local tag="${1:?Usage: run_test tag server_lang client_lang}"
+ local slang="${2:?Usage: run_test tag server_lang client_lang}"
+ local clang="${3:?Usage: run_test tag server_lang client_lang}"
+ local server_image_name="${IMAGE_REPO}/${slang}-server:${tag}"
+ local client_image_name="${IMAGE_REPO}/${clang}-client:${tag}"
+ # TODO(sanjaypujare): skip test if image not found (by using gcloud_gcr_list_image_tags)
+ set -x
+ python -m "tests.security_test" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --server_image="${server_image_name}" \
+ --client_image="${client_image_name}" \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${tag}/${clang}-${slang}/sponge_log.xml" \
+ --force_cleanup \
+ --nocheck_local_certs
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_SECURITY
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ cd "${TEST_DRIVER_FULL_DIR}"
+ else
+ local_setup_test_driver "${script_dir}"
+ cd "${SRC_DIR}/${TEST_DRIVER_PATH}"
+ fi
+
+ local failed_tests=0
+ local successful_string
+ local failed_string
+ # Run tests
+ for TAG in ${VERSION_TAG}
+ do
+ for CLANG in ${CLIENT_LANG}
+ do
+ for SLANG in ${SERVER_LANG}
+ do
+ if [ "${CLANG}" != "${SLANG}" ]; then
+ if run_test "${TAG}" "${SLANG}" "${CLANG}"; then
+ successful_string="${successful_string} ${TAG}/${CLANG}-${SLANG}"
+ else
+ failed_tests=$((failed_tests+1))
+ failed_string="${failed_string} ${TAG}/${CLANG}-${SLANG}"
+ fi
+ fi
+ done
+ echo "Failed test suites: ${failed_tests}"
+ done
+ done
+ set +x
+ echo "Failed test suites list: ${failed_string}"
+ echo "Successful test suites list: ${successful_string}"
+ if (( failed_tests > 0 )); then
+ exit 1
+ fi
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_php.sh b/tools/internal_ci/linux/grpc_xds_php.sh
new file mode 100644
index 00000000..8b643430
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_php.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/php73_zts_stretch_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
new file mode 100644
index 00000000..b18f306d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trap 'date' DEBUG
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+VIRTUAL_ENV=$(mktemp -d)
+virtualenv "$VIRTUAL_ENV" -p python3
+PYTHON="$VIRTUAL_ENV"/bin/python
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
+
+# Prepare generated Python code.
+TOOLS_DIR=tools/run_tests
+PROTO_SOURCE_DIR=src/proto/grpc/testing
+PROTO_DEST_DIR="$TOOLS_DIR"/"$PROTO_SOURCE_DIR"
+mkdir -p "$PROTO_DEST_DIR"
+touch "$TOOLS_DIR"/src/__init__.py
+touch "$TOOLS_DIR"/src/proto/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out="$TOOLS_DIR" \
+ --grpc_python_out="$TOOLS_DIR" \
+ "$PROTO_SOURCE_DIR"/test.proto \
+ "$PROTO_SOURCE_DIR"/messages.proto \
+ "$PROTO_SOURCE_DIR"/empty.proto
+
+HEALTH_PROTO_SOURCE_DIR=src/proto/grpc/health/v1
+HEALTH_PROTO_DEST_DIR=${TOOLS_DIR}/${HEALTH_PROTO_SOURCE_DIR}
+mkdir -p ${HEALTH_PROTO_DEST_DIR}
+touch "$TOOLS_DIR"/src/proto/grpc/health/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/health/v1/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${HEALTH_PROTO_SOURCE_DIR}/health.proto
+
+# Generate and compile the PHP extension.
+(pear package && \
+ find . -name grpc-*.tgz | xargs -I{} pecl install {})
+
+# Prepare generated PHP code.
+export CC=/usr/bin/gcc
+./tools/bazel build @com_google_protobuf//:protoc
+./tools/bazel build src/compiler:grpc_php_plugin
+(cd src/php && \
+ composer install && \
+ ./bin/generate_proto_php.sh)
+
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+ tools/run_tests/run_xds_tests.py \
+ --halt_after_fail \
+ --test_case="timeout,fault_injection" \
+ --project_id=grpc-testing \
+ --project_num=830293263384 \
+ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+ --gcp_suffix=$(date '+%s') \
+ --verbose \
+ --qps=20 \
+ ${XDS_V3_OPT-} \
+ --client_cmd='./src/php/bin/run_xds_client.sh --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
+
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+ tools/run_tests/run_xds_tests.py \
+ --halt_after_fail \
+ --test_case="all,path_matching,header_matching" \
+ --project_id=grpc-testing \
+ --project_num=830293263384 \
+ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+ --gcp_suffix=$(date '+%s') \
+ --verbose \
+ ${XDS_V3_OPT-} \
+ --client_cmd='php -d extension=grpc.so -d extension=pthreads.so src/php/tests/interop/xds_client.php --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
diff --git a/tools/internal_ci/linux/grpc_xds_ruby.sh b/tools/internal_ci/linux/grpc_xds_ruby.sh
new file mode 100644
index 00000000..e1df4971
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_ruby.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/ruby_buster_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
new file mode 100644
index 00000000..c6d89756
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trap 'date' DEBUG
+set -ex -o igncr || set -ex
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+
+VIRTUAL_ENV=$(mktemp -d)
+virtualenv "$VIRTUAL_ENV" -p python3
+PYTHON="$VIRTUAL_ENV"/bin/python
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
+
+# Prepare generated Python code.
+TOOLS_DIR=tools/run_tests
+PROTO_SOURCE_DIR=src/proto/grpc/testing
+PROTO_DEST_DIR="$TOOLS_DIR"/"$PROTO_SOURCE_DIR"
+mkdir -p "$PROTO_DEST_DIR"
+touch "$TOOLS_DIR"/src/__init__.py
+touch "$TOOLS_DIR"/src/proto/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out="$TOOLS_DIR" \
+ --grpc_python_out="$TOOLS_DIR" \
+ "$PROTO_SOURCE_DIR"/test.proto \
+ "$PROTO_SOURCE_DIR"/messages.proto \
+ "$PROTO_SOURCE_DIR"/empty.proto
+
+HEALTH_PROTO_SOURCE_DIR=src/proto/grpc/health/v1
+HEALTH_PROTO_DEST_DIR=${TOOLS_DIR}/${HEALTH_PROTO_SOURCE_DIR}
+mkdir -p ${HEALTH_PROTO_DEST_DIR}
+touch "$TOOLS_DIR"/src/proto/grpc/health/__init__.py
+touch "$TOOLS_DIR"/src/proto/grpc/health/v1/__init__.py
+
+"$PYTHON" -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${HEALTH_PROTO_SOURCE_DIR}/health.proto
+
+(cd src/ruby && bundle && rake compile)
+
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+ tools/run_tests/run_xds_tests.py \
+ --halt_after_fail \
+ --test_case="all,circuit_breaking,timeout,fault_injection" \
+ --project_id=grpc-testing \
+ --project_num=830293263384 \
+ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+ --gcp_suffix=$(date '+%s') \
+ --verbose \
+ ${XDS_V3_OPT-} \
+ --client_cmd='ruby src/ruby/pb/test/xds_client.rb --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
diff --git a/tools/internal_ci/linux/grpc_xds_url_map.sh b/tools/internal_ci/linux/grpc_xds_url_map.sh
new file mode 100644
index 00000000..696ef97d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_url_map.sh
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test client Docker images
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+# BUILD_APP_PATH
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+ echo "Building C++ xDS interop test app Docker images"
+ docker build -f "${SRC_DIR}/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client" -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" "${SRC_DIR}"
+ gcloud -q auth configure-docker
+ docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# FORCE_IMAGE_BUILD
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+ # Check if images already exist
+ client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${client_tags:-Client image not found}"
+
+ # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+ if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then
+ build_test_app_docker_images
+ else
+ echo "Skipping C++ test app build"
+ fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local test_name="${1:?Usage: run_test test_name}"
+ set -x
+ python -m "tests.${test_name}" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ --testing_version=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/core/([^/]+)/.*|\1|') \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+ --flagfile="config/url-map.cfg"
+ set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_BASIC
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ else
+ local_setup_test_driver "${script_dir}"
+ fi
+ build_docker_images_if_needed
+ # Run tests
+ cd "${TEST_DRIVER_FULL_DIR}"
+ run_test url_map
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_url_map_python.sh b/tools/internal_ci/linux/grpc_xds_url_map_python.sh
new file mode 100644
index 00000000..7316df95
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_url_map_python.sh
@@ -0,0 +1,150 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eo pipefail
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh"
+## xDS test client Docker images
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+readonly LANGUAGE_NAME="Python"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+# BUILD_APP_PATH
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# None
+# Outputs:
+# Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+ echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images"
+
+ pushd "${SRC_DIR}"
+ docker build \
+ -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \
+ -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ .
+
+ popd
+
+ gcloud -q auth configure-docker
+
+ docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# FORCE_IMAGE_BUILD
+# Arguments:
+# None
+# Outputs:
+# Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+ # Check if images already exist
+ client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+ printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+ echo "${client_tags:-Client image not found}"
+
+ # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+ if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then
+ build_test_app_docker_images
+ else
+ echo "Skipping ${LANGUAGE_NAME} test app build"
+ fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+# KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+# CLIENT_IMAGE_NAME: Test client Docker image name
+# GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+# Test case name
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+ # Test driver usage:
+ # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+ local test_name="${1:?Usage: run_test test_name}"
+ set -x
+ python -m "tests.${test_name}" \
+ --flagfile="${TEST_DRIVER_FLAGFILE}" \
+ --kube_context="${KUBE_CONTEXT}" \
+ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+ --testing_version=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/core/([^/]+)/.*|\1|') \
+ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+ --flagfile="config/url-map.cfg"
+ set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+# KOKORO_ARTIFACTS_DIR
+# GITHUB_REPOSITORY_NAME
+# SRC_DIR: Populated with absolute path to the source repo
+# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+# the test driver
+# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+# GIT_COMMIT: Populated with the SHA-1 of git commit being built
+# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+# None
+# Outputs:
+# Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+ local script_dir
+ script_dir="$(dirname "$0")"
+
+ # Source the test driver from the master branch.
+ echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}"
+ source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")"
+
+ activate_gke_cluster GKE_CLUSTER_PSM_BASIC
+
+ set -x
+ if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+ kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+ else
+ local_setup_test_driver "${script_dir}"
+ fi
+ build_docker_images_if_needed
+ # Run tests
+ cd "${TEST_DRIVER_FULL_DIR}"
+ run_test url_map
+}
+
+main "$@"
diff --git a/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh
new file mode 100644
index 00000000..dcaeceae
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_bazel_python_test_in_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh
new file mode 100644
index 00000000..d7218aab
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_bazel_test_in_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_v3_php.sh b/tools/internal_ci/linux/grpc_xds_v3_php.sh
new file mode 100644
index 00000000..eebbc285
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_php.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/php73_zts_stretch_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
new file mode 100644
index 00000000..23337deb
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_php_test_in_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_v3_ruby.sh b/tools/internal_ci/linux/grpc_xds_v3_ruby.sh
new file mode 100644
index 00000000..32aee712
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_ruby.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/ruby_buster_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh b/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
new file mode 100644
index 00000000..c380e334
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_ruby_test_in_docker.sh
diff --git a/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
new file mode 100644
index 00000000..00f92921
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan
+
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
new file mode 100644
index 00000000..6cf7a881
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+EXTRA_FLAGS="--config=dbg"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
new file mode 100644
index 00000000..76df0b24
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+EXTRA_FLAGS="--config=opt"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
new file mode 100644
index 00000000..c85a837a
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan
diff --git a/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
new file mode 100644
index 00000000..f3e98e63
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan
diff --git a/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
new file mode 100644
index 00000000..b94935ea
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan
diff --git a/tools/internal_ci/linux/run_if_c_cpp_modified.sh b/tools/internal_ci/linux/run_if_c_cpp_modified.sh
new file mode 100644
index 00000000..c0e782a7
--- /dev/null
+++ b/tools/internal_ci/linux/run_if_c_cpp_modified.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by a pull request job and executes all
+# args passed to this script if the pull request affect C/C++ code
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+AFFECTS_C_CPP=`python3 -c 'import os; \
+ import sys; \
+ sys.path.insert(0, "tools/run_tests/python_utils"); \
+ import filter_pull_request_tests as filter; \
+ github_target_branch = os.environ.get("KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"); \
+ print(filter.affects_c_cpp("origin/%s" % github_target_branch))'`
+
+if [ $AFFECTS_C_CPP == "False" ] ; then
+ echo "This pull request does not affect C/C++. Tests do not need to be run."
+else
+ $@
+fi
diff --git a/tools/internal_ci/linux/run_performance_profile_daily.sh b/tools/internal_ci/linux/run_performance_profile_daily.sh
new file mode 100644
index 00000000..45c7a998
--- /dev/null
+++ b/tools/internal_ci/linux/run_performance_profile_daily.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+# try to use pypy for generating reports
+# each trace dumps 7-8gig of text to disk, and processing this into a report is
+# heavyweight - so any speed boost is worthwhile
+# TODO(ctiller): consider rewriting report generation in C++ for performance
+if which pypy >/dev/null; then
+ PYTHON=pypy
+else
+ PYTHON=python2.7
+fi
+
+BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong bm_fullstack_streaming_pump bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata"
+
+./tools/run_tests/start_port_server.py || true
+
+$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency -b $BENCHMARKS_TO_RUN
diff --git a/tools/internal_ci/linux/run_performance_profile_hourly.sh b/tools/internal_ci/linux/run_performance_profile_hourly.sh
new file mode 100644
index 00000000..bcb4ea23
--- /dev/null
+++ b/tools/internal_ci/linux/run_performance_profile_hourly.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+./tools/run_tests/start_port_server.py || true
+
+CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+
+tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload
diff --git a/tools/internal_ci/macos/grpc_basictests_csharp.sh b/tools/internal_ci/macos/grpc_basictests_csharp.sh
new file mode 100644
index 00000000..c66e5c77
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_csharp.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export PREPARE_BUILD_INSTALL_DEPS_CSHARP=true
+$(dirname $0)/grpc_run_tests_matrix.sh
diff --git a/tools/internal_ci/macos/grpc_basictests_php.sh b/tools/internal_ci/macos/grpc_basictests_php.sh
new file mode 100644
index 00000000..38fdbf32
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_php.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2020 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export PREPARE_BUILD_INSTALL_DEPS_PHP=true
+$(dirname $0)/grpc_run_tests_matrix.sh
diff --git a/tools/internal_ci/macos/grpc_basictests_python.sh b/tools/internal_ci/macos/grpc_basictests_python.sh
new file mode 100644
index 00000000..a0dabbd3
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_python.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export PREPARE_BUILD_INSTALL_DEPS_PYTHON=true
+$(dirname $0)/grpc_run_tests_matrix.sh
diff --git a/tools/internal_ci/macos/grpc_basictests_ruby.sh b/tools/internal_ci/macos/grpc_basictests_ruby.sh
new file mode 100644
index 00000000..d83cd1e6
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_ruby.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export PREPARE_BUILD_INSTALL_DEPS_RUBY=true
+$(dirname $0)/grpc_run_tests_matrix.sh
diff --git a/tools/internal_ci/macos/grpc_build_artifacts.sh b/tools/internal_ci/macos/grpc_build_artifacts.sh
new file mode 100644
index 00000000..02b2331f
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_build_artifacts.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+export PREPARE_BUILD_INSTALL_DEPS_CSHARP=true
+export PREPARE_BUILD_INSTALL_DEPS_PYTHON=true
+export PREPARE_BUILD_INSTALL_DEPS_RUBY=true
+export PREPARE_BUILD_INSTALL_DEPS_PHP=true
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+# install cython for all python versions
+python2.7 -m pip install -U cython setuptools==44.1.1 wheel --user
+python3.5 -m pip install -U cython setuptools==44.1.1 wheel --user
+python3.6 -m pip install -U cython setuptools==44.1.1 wheel --user
+python3.7 -m pip install -U cython setuptools==44.1.1 wheel --user
+python3.8 -m pip install -U cython setuptools==44.1.1 wheel --user
+python3.9 -m pip install -U cython setuptools==44.1.1 wheel --user
+
+# needed to build ruby artifacts
+time bash tools/distrib/build_ruby_environment_macos.sh
+
+gem install rubygems-update
+update_rubygems
+
+tools/run_tests/task_runner.py -f artifact macos || FAILED="true"
+
+tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_distribtests.sh b/tools/internal_ci/macos/grpc_distribtests.sh
new file mode 100644
index 00000000..cf2ba090
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_distribtests.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+export PREPARE_BUILD_INSTALL_DEPS_CSHARP=true
+export PREPARE_BUILD_INSTALL_DEPS_PHP=true
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+# Move packages generated by the previous step in the build chain.
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f distribtest macos || FAILED="true"
+
+tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_distribtests_php.sh b/tools/internal_ci/macos/grpc_distribtests_php.sh
new file mode 100644
index 00000000..a6c33285
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_distribtests_php.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+export PREPARE_BUILD_INSTALL_DEPS_PHP=true
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+# Build all PHP macos artifacts
+tools/run_tests/task_runner.py -f artifact macos php -j 4 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# PHP's "build_package" step is basically just a passthough, so the build artifacts can be used
+# directly by the "distribtests" step (and we skip the "build_package" phase entirely on mac).
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/php_pecl_package_macos_*/* input_artifacts/ || true
+
+# Run all PHP linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest macos php -j 4 -x distribtests/sponge_log.xml || FAILED="true"
+
+tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_interop_toprod.sh b/tools/internal_ci/macos/grpc_interop_toprod.sh
new file mode 100644
index 00000000..c4d300d4
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_interop_toprod.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+source tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
+
+# build C++ interop client and server
+mkdir -p cmake/build
+pushd cmake/build
+cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ../..
+make interop_client interop_server -j4
+popd
+
+export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH="$(pwd)/etc/roots.pem"
+
+# NOTE: only tests a subset of languages for time & dependency constraints
+# building all languages in the same working copy can also lead to conflicts
+# due to different compilation flags
+tools/run_tests/run_interop_tests.py -l c++ \
+ --cloud_to_prod --cloud_to_prod_auth \
+ --google_default_creds_use_key_file \
+ --prod_servers default gateway_v4 \
+ --service_account_key_file="${KOKORO_KEYSTORE_DIR}/73836_interop_to_prod_tests_service_account_key" \
+ --default_service_account="interop-to-prod-tests@grpc-testing.iam.gserviceaccount.com" \
+ --skip_compute_engine_creds --internal_ci -t -j 4 || FAILED="true"
+
+tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_ios_binary_size.sh b/tools/internal_ci/macos/grpc_ios_binary_size.sh
new file mode 100644
index 00000000..523e3ae8
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_ios_binary_size.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by Jenkins and runs a diff on the microbenchmarks
+set -ex
+
+# List of benchmarks that provide good signal for analyzing performance changes in pull requests
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+export PREPARE_BUILD_INSTALL_DEPS_OBJC=true
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+tools/profiling/ios_bin/binary_size.py \
+ -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"
diff --git a/tools/internal_ci/macos/grpc_run_bazel_c_cpp_tests.sh b/tools/internal_ci/macos/grpc_run_bazel_c_cpp_tests.sh
new file mode 100644
index 00000000..bfe1c8c2
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_run_bazel_c_cpp_tests.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+# TODO(jtattermusch): most of the prepare steps should not be needed for bazel
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+# make sure bazel is available
+tools/bazel version
+
+./tools/run_tests/start_port_server.py
+
+# to get "bazel" link for kokoro build, we need to generate
+# invocation UUID, set a flag for bazel to use it
+# and upload "bazel_invocation_ids" file as artifact.
+# NOTE: UUID needs to be in lowercase for the result link to work
+# (on mac "uuidgen" outputs uppercase UUID)
+BAZEL_INVOCATION_ID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
+echo "${BAZEL_INVOCATION_ID}" >"${KOKORO_ARTIFACTS_DIR}/bazel_invocation_ids"
+
+# run all C/C++ tests
+tools/bazel \
+ --bazelrc=tools/remote_build/mac.bazelrc \
+ test \
+ --invocation_id="${BAZEL_INVOCATION_ID}" \
+ --workspace_status_command=tools/remote_build/workspace_status_kokoro.sh \
+ --google_credentials="${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json" \
+ $BAZEL_FLAGS \
+ -- //test/... || FAILED="true"
+
+if [ "$UPLOAD_TEST_RESULTS" != "" ]
+then
+ # Sleep to let ResultStore finish writing results before querying
+ sleep 60
+ PYTHONHTTPSVERIFY=0 python ./tools/run_tests/python_utils/upload_rbe_results.py
+fi
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_run_bazel_cpp_ios_tests.sh b/tools/internal_ci/macos/grpc_run_bazel_cpp_ios_tests.sh
new file mode 100644
index 00000000..c6523408
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_run_bazel_cpp_ios_tests.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+./tools/run_tests/start_port_server.py
+
+dirs=(end2end server client common codegen util grpclb test)
+for dir in ${dirs[*]}; do
+ echo $dir
+ out=`tools/bazel query "kind(ios_unit_test, tests(//test/cpp/$dir/...))" 2>/dev/null | grep '^//'`
+ for test in $out; do
+ echo "Running: $test"
+ tools/bazel test --test_summary=detailed --test_output=all $test
+ done
+done
diff --git a/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh b/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
new file mode 100644
index 00000000..e213105d
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+./tools/run_tests/start_port_server.py
+
+# run cfstream_test separately because it messes with the network
+# The "local" execution strategy is required because the test runs sudo and that doesn't work in a sandboxed environment (the default on mac)
+tools/bazel test $RUN_TESTS_FLAGS --genrule_strategy=local --test_output=all --copt="-DGRPC_CFSTREAM=1" //test/cpp/end2end:cfstream_test
+
+# Missing the /var/db/ntp-kod file may breaks the ntp synchronization.
+# Create the file and change the ownership to root before NTP sync.
+# TODO(yulin-liang): investigate how to run time_jump_test without needing to mess with the system time directly.
+# See b/166245303
+sudo touch /var/db/ntp-kod
+sudo chown root:wheel /var/db/ntp-kod
+# Make sure time is in sync before running time_jump_test because the test does
+# NTP sync before exiting. Bazel gets confused if test end time < start time.
+sudo sntp -sS pool.ntp.org
+
+# run time_jump_test separately because it changes system time
+# The "local" execution strategy is required because the test runs sudo and that doesn't work in a sandboxed environment (the default on mac)
+tools/bazel test $RUN_TESTS_FLAGS --genrule_strategy=local --test_output=all //test/cpp/common:time_jump_test
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
diff --git a/tools/internal_ci/macos/grpc_run_tests_matrix.sh b/tools/internal_ci/macos/grpc_run_tests_matrix.sh
new file mode 100644
index 00000000..b74508b7
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_run_tests_matrix.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true"
+
+# kill port_server.py to prevent the build from freezing
+ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
+
+tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/internal_ci/macos/grpc_run_tests_matrix_objc.sh b/tools/internal_ci/macos/grpc_run_tests_matrix_objc.sh
new file mode 100644
index 00000000..72cd1954
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_run_tests_matrix_objc.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export PREPARE_BUILD_INSTALL_DEPS_OBJC=true
+$(dirname $0)/grpc_run_tests_matrix.sh
diff --git a/tools/interop_matrix/create_testcases.sh b/tools/interop_matrix/create_testcases.sh
new file mode 100644
index 00000000..5074a8ab
--- /dev/null
+++ b/tools/interop_matrix/create_testcases.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates test cases for a language by running run_interop_test in manual mode
+# and save the generated output under ./testcases/__.
+#
+# Params:
+# LANG - The language.
+# SKIP_TEST - If set, skip running the test cases for sanity.
+# RELEASE - Create testcase for specific release, default to 'master'.
+# KEEP_IMAGE - Do not clean local docker image created for the test cases.
+
+set -e
+
+cd $(dirname $0)/../..
+GRPC_ROOT=$(pwd)
+CMDS_SH="${GRPC_ROOT}/interop_client_cmds.sh"
+TESTCASES_DIR=${GRPC_ROOT}/tools/interop_matrix/testcases
+
+echo "Create '$LANG' test cases for gRPC release '${RELEASE:=master}'"
+
+# Clean up
+function cleanup {
+ [ -z "$testcase" ] && testcase=$CMDS_SH
+ echo "testcase: $testcase"
+ if [ -e $testcase ]; then
+ # The script should generate a line with "${docker_image:=...}".
+ eval docker_image=$(grep -oe '${docker_image:=.*}' $testcase)
+ if [ -z "$KEEP_IMAGE" ]; then
+ echo "Clean up docker_image $docker_image"
+ docker rmi -f $docker_image
+ else
+ echo "Kept docker_image $docker_image"
+ fi
+ fi
+ [ -e "$CMDS_SH" ] && rm $CMDS_SH
+}
+
+function createtests {
+# Invoke run_interop_test in manual mode.
+# TODO(adelez): Add cloud_gateways when we figure out how to skip them if not
+# running in GCE.
+if [ $1 == "cxx" ]; then
+client_lang="c++"
+else
+client_lang=$1
+fi
+echo $client_lang
+
+${GRPC_ROOT}/tools/run_tests/run_interop_tests.py -l $client_lang --use_docker \
+ --cloud_to_prod --prod_servers default gateway_v4 --manual_run --custom_credentials_type tls
+
+trap cleanup EXIT
+# TODO(adelez): add test auth tests but do not run if not testing on GCE.
+# Running the testcases as sanity unless we are asked to skip.
+[ -z "$SKIP_TEST" ] && (echo "Running test cases: $CMDS_SH"; sh $CMDS_SH)
+
+mkdir -p $TESTCASES_DIR
+testcase=$TESTCASES_DIR/$1__$RELEASE
+if [ -e $testcase ]; then
+ echo "Updating: $testcase"
+ diff $testcase $CMDS_SH || true
+fi
+mv $CMDS_SH $testcase
+chmod a+x $testcase
+echo "Test cases created: $testcase"
+}
+
+if [ $LANG == "csharp" ]; then
+createtests "csharp"
+createtests "csharpcoreclr"
+else
+createtests $LANG
+fi
diff --git a/tools/package_hosting/upload_web_assets.sh b/tools/package_hosting/upload_web_assets.sh
new file mode 100644
index 00000000..dcf258e3
--- /dev/null
+++ b/tools/package_hosting/upload_web_assets.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+GCS_WEB_ASSETS=gs://packages.grpc.io/web-assets/
+
+WEB_ASSETS=(
+ 404.html
+ build-201807.xsl
+ dirindex.css
+ home.xsl
+ style.css
+)
+
+gsutil -m cp "${WEB_ASSETS[@]}" "$GCS_WEB_ASSETS"
diff --git a/tools/profiling/perf/run_perf_unconstrained.sh b/tools/profiling/perf/run_perf_unconstrained.sh
new file mode 100644
index 00000000..af8c8dbc
--- /dev/null
+++ b/tools/profiling/perf/run_perf_unconstrained.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# format argument via
+# $ echo '{...}' | python -mjson.tool
+read -r -d '' SCENARIOS_JSON_ARG <<'EOF'
+{
+ "scenarios": [
+ {
+ "benchmark_seconds": 60,
+ "warmup_seconds": 5,
+ "client_config": {
+ "client_channels": 100,
+ "client_type": "ASYNC_CLIENT",
+ "histogram_params": {
+ "max_possible": 60000000000.0,
+ "resolution": 0.01
+ },
+ "load_params": {
+ "closed_loop": {}
+ },
+ "outstanding_rpcs_per_channel": 100,
+ "payload_config": {
+ "simple_params": {
+ "req_size": 0,
+ "resp_size": 0
+ }
+ },
+ "rpc_type": "UNARY",
+ "security_params": null
+ },
+ "name": "name_goes_here",
+ "num_clients": 1,
+ "num_servers": 1,
+ "server_config": {
+ "security_params": null,
+ "server_type": "ASYNC_SERVER"
+ },
+ "spawn_local_worker_count": -2
+ }
+ ]
+}
+
+EOF
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+
+# try to use pypy for generating reports
+# each trace dumps 7-8gig of text to disk, and processing this into a report is
+# heavyweight - so any speed boost is worthwhile
+# TODO(ctiller): consider rewriting report generation in C++ for performance
+if which pypy >/dev/null; then
+ PYTHON=pypy
+else
+ PYTHON=python2.7
+fi
+
+export config=mutrace
+
+make CONFIG=$config -j$CPUS qps_json_driver
+
+sudo perf record -F 997 -g bins/$config/qps_json_driver --scenarios_json="$SCENARIOS_JSON_ARG"
+sudo perf report
+
diff --git a/tools/release/backport_pr.sh b/tools/release/backport_pr.sh
new file mode 100644
index 00000000..3860f372
--- /dev/null
+++ b/tools/release/backport_pr.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+#Copyright 2021 The gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+ensure_command () {
+ if command -v "$1" 1>/dev/null 2>&1; then
+ return 0
+ else
+ echo "$1 is not installed. Please install it to proceed." 1>&2
+ exit 1
+ fi
+}
+
+display_usage () {
+ cat << EOF >/dev/stderr
+USAGE: $0 PR_ID GITHUB_USER BACKPORT_BRANCHES REVIEWERS [-c PER_BACKPORT_COMMAND]
+ PR_ID: The ID of the PR to be backported.
+ GITHUB_USER: Your GitHub username.
+ BACKPORT_BRANCHES: A space-separated list of branches to which the source PR will be backported.
+ REVIEWERS: A comma-separated list of users to add as both reviewer and assignee.
+ PER_BACKPORT_COMMAND : An optional command to run after cherrypicking the PR to the target branch.
+ If you use this option, ensure your working directory is clean, as "git add -A" will be used to
+ incorporate any generated files. Try running "git clean -xdff" beforehand.
+
+Example: $0 25456 gnossen "v1.30.x v1.31.x v1.32.x v1.33.x v1.34.x v1.35.x v1.36.x" "menghanl,gnossen"
+Example: $0 25493 gnossen "\$(seq 30 33 | xargs -n1 printf 'v1.%s.x ')" "menghanl" -c ./tools/dockerfile/push_testing_images.sh
+EOF
+ exit 1
+}
+
+ensure_command "curl"
+ensure_command "egrep"
+ensure_command "hub"
+ensure_command "jq"
+
+if [ "$#" -lt "4" ]; then
+ display_usage
+fi
+
+PR_ID="$1"
+GITHUB_USER="$2"
+BACKPORT_BRANCHES="$3"
+REVIEWERS="$4"
+shift 4
+
+PER_BACKPORT_COMMAND=""
+while getopts "c:" OPT; do
+ case "$OPT" in
+ c )
+ PER_BACKPORT_COMMAND="$OPTARG"
+ ;;
+ \? )
+ echo "Invalid option: $OPTARG" >/dev/stderr
+ display_usage
+ ;;
+ : )
+ echo "Invalid option: $OPTARG requires an argument." >/dev/stderr
+ display_usage
+ ;;
+ esac
+done
+
+if [[ ! -z "$(git status --porcelain)" && ! -z "$PER_BACKPORT_COMMAND" ]]; then
+ echo "Your working directory is not clean. Try running `git clean -xdff`. Warning: This is irreversible." > /dev/stderr
+ exit 1
+fi
+
+if [ -z "$GITHUB_TOKEN" ]; then
+ echo "A GitHub token is required to run this script. See " \
+ "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token" \
+ " for more information" >/dev/stderr
+ exit 1
+fi
+
+echo "This script will create a collection of backport PRs. You will probably " \
+ "have to touch your gnubby a frustrating number of times. C'est la vie."
+printf "Press any key to continue."
+read -r RESPONSE =2.2.0 enum34>=1.0.4
+ fi
+
+ "${PYTHON}" -m pip install grpcio --no-index --find-links "file://$ARTIFACT_DIR/"
+ "${PYTHON}" -m pip install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/"
+
+ # Note(lidiz) setuptools's "sdist" command creates a source tarball, which
+ # demands an extra step of building the wheel. The building step is merely ran
+ # through setup.py, but we can optimize it with "bdist_wheel" command, which
+ # skips the wheel building step.
+
+ # Build grpcio_testing source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py preprocess \
+ sdist bdist_wheel
+ cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_channelz source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_channelz/setup.py \
+ preprocess build_package_protos sdist bdist_wheel
+ cp -r src/python/grpcio_channelz/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_health_checking source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \
+ preprocess build_package_protos sdist bdist_wheel
+ cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_reflection source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \
+ preprocess build_package_protos sdist bdist_wheel
+ cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_status source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_status/setup.py \
+ preprocess sdist bdist_wheel
+ cp -r src/python/grpcio_status/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_csds source distribution
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_csds/setup.py \
+ sdist bdist_wheel
+ cp -r src/python/grpcio_csds/dist/* "$ARTIFACT_DIR"
+
+ # Build grpcio_admin source distribution and it needs the cutting-edge version
+ # of Channelz and CSDS to be installed.
+ "${PYTHON}" -m pip install --upgrade xds-protos==0.0.8
+ "${PYTHON}" -m pip install grpcio-channelz --no-index --find-links "file://$ARTIFACT_DIR/"
+ "${PYTHON}" -m pip install grpcio-csds --no-index --find-links "file://$ARTIFACT_DIR/"
+ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_admin/setup.py \
+ sdist bdist_wheel
+ cp -r src/python/grpcio_admin/dist/* "$ARTIFACT_DIR"
+fi
diff --git a/tools/run_tests/artifacts/build_artifact_ruby.sh b/tools/run_tests/artifacts/build_artifact_ruby.sh
new file mode 100644
index 00000000..b0eecf25
--- /dev/null
+++ b/tools/run_tests/artifacts/build_artifact_ruby.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+SYSTEM=$(uname | cut -f 1 -d_)
+
+cd "$(dirname "$0")/../../.."
+set +ex
+# shellcheck disable=SC1091
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+# shellcheck disable=SC1090
+[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
+set -ex
+
+if [ "$SYSTEM" == "MSYS" ] ; then
+ SYSTEM=MINGW32
+fi
+if [ "$SYSTEM" == "MINGW64" ] ; then
+ SYSTEM=MINGW32
+fi
+
+if [ "$SYSTEM" == "MINGW32" ] ; then
+ echo "Need Linux to build the Windows ruby gem."
+ exit 1
+fi
+
+set +ex
+
+# To workaround the problem with bundler 2.1.0 and rubygems-bundler 1.4.5
+# https://github.com/bundler/bundler/issues/7488
+rvm @global
+gem uninstall rubygems-bundler
+
+rvm use default
+gem install bundler -v 1.17.3
+
+tools/run_tests/helper_scripts/bundle_install_wrapper.sh
+
+set -ex
+
+export DOCKERHUB_ORGANIZATION=grpctesting
+rake gem:native
+
+if [ "$SYSTEM" == "Darwin" ] ; then
+ # TODO: consider rewriting this to pass shellcheck
+ # shellcheck disable=SC2046,SC2010
+ rm $(ls pkg/*.gem | grep -v darwin)
+fi
+
+mkdir -p "${ARTIFACTS_OUT}"
+
+cp pkg/*.gem "${ARTIFACTS_OUT}"/
diff --git a/tools/run_tests/artifacts/build_package_php.sh b/tools/run_tests/artifacts/build_package_php.sh
new file mode 100644
index 00000000..46c3d5b8
--- /dev/null
+++ b/tools/run_tests/artifacts/build_package_php.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# All the PHP packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+mkdir -p artifacts/
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/php_pecl_package_linux_*/* artifacts/ || true
diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
new file mode 100644
index 00000000..29801a5b
--- /dev/null
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+mkdir -p artifacts/
+
+# All the python packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true
+
+# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/artifacts/build_package_ruby.sh b/tools/run_tests/artifacts/build_package_ruby.sh
new file mode 100644
index 00000000..6a6a514b
--- /dev/null
+++ b/tools/run_tests/artifacts/build_package_ruby.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+base=$(pwd)
+
+mkdir -p artifacts/
+
+# All the "grpc" gems have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+# NOTE: Besides the platform-specific native gems, all the artifact build
+# jobs will generate a grpc-X.Y.Z.gem source package, and only one of them
+# will end up in the artifacts/ directory. They should be all equivalent
+# though.
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/ruby_native_gem_*/* artifacts/ || true
+
+# Next, build the "grpc-tools" gem by collecting the protoc and grpc_ruby_plugin binaries
+# that have been built by the the artifact build phase previously.
+well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers )
+
+for arch in {x86,x64}; do
+ case $arch in
+ x64)
+ ruby_arch=x86_64
+ ;;
+ *)
+ ruby_arch=$arch
+ ;;
+ esac
+ for plat in {windows,linux,macos}; do
+ # skip non-existent macos x86 protoc artifact
+ if [[ "${plat}_${arch}" == "macos_x86" ]]
+ then
+ continue
+ fi
+ input_dir="${EXTERNAL_GIT_ROOT}/input_artifacts/protoc_${plat}_${arch}"
+ output_dir="$base/src/ruby/tools/bin/${ruby_arch}-${plat}"
+ mkdir -p "$output_dir"/google/protobuf
+ mkdir -p "$output_dir"/google/protobuf/compiler # needed for plugin.proto
+ cp "$input_dir"/protoc* "$input_dir"/grpc_ruby_plugin* "$output_dir/"
+ if [[ "$plat" != "windows" ]]
+ then
+ chmod +x "$output_dir/protoc" "$output_dir/grpc_ruby_plugin"
+ fi
+ for proto in "${well_known_protos[@]}"; do
+ cp "$base/third_party/protobuf/src/google/protobuf/$proto.proto" "$output_dir/google/protobuf/$proto.proto"
+ done
+ done
+done
+
+cd "$base/src/ruby/tools"
+gem build grpc-tools.gemspec
+cp ./grpc-tools*.gem "$base/artifacts/"
diff --git a/tools/run_tests/artifacts/run_in_workspace.sh b/tools/run_tests/artifacts/run_in_workspace.sh
new file mode 100644
index 00000000..f4719b0a
--- /dev/null
+++ b/tools/run_tests/artifacts/run_in_workspace.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Create a workspace in a subdirectory to allow running multiple builds in isolation.
+# WORKSPACE_NAME env variable needs to contain name of the workspace to create.
+# All cmdline args will be executed as a command.
+set -ex
+
+cd "$(dirname "$0")/../../.."
+repo_root=$(pwd)
+export repo_root
+
+# TODO: fix file to pass shellcheck
+
+rm -rf "${WORKSPACE_NAME}"
+git clone . "${WORKSPACE_NAME}"
+# clone gRPC submodules, use data from locally cloned submodules where possible
+# shellcheck disable=SC1004,SC2016
+git submodule foreach 'cd "${repo_root}/${WORKSPACE_NAME}" \
+ && git submodule update --init --reference ${repo_root}/${name} ${name}'
+
+echo "Running in workspace ${WORKSPACE_NAME}"
+cd "${WORKSPACE_NAME}"
+# shellcheck disable=SC2068
+$@
diff --git a/tools/run_tests/dockerize/build_and_run_docker.sh b/tools/run_tests/dockerize/build_and_run_docker.sh
new file mode 100644
index 00000000..cc5cf1a1
--- /dev/null
+++ b/tools/run_tests/dockerize/build_and_run_docker.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds docker image and runs a command under it.
+# You should never need to call this script on your own.
+
+# shellcheck disable=SC2103
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+git_root=$(pwd)
+cd -
+
+# Inputs
+# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
+# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
+# OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
+# DOCKERHUB_ORGANIZATION - If set, pull a prebuilt image from given dockerhub org.
+# $@ - Extra args to pass to docker run
+
+# Use image name based on Dockerfile location checksum
+DOCKER_IMAGE_NAME=$(basename "$DOCKERFILE_DIR"):$(sha1sum "$DOCKERFILE_DIR/Dockerfile" | cut -f1 -d\ )
+
+if [ "$DOCKERHUB_ORGANIZATION" != "" ]
+then
+ DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME
+ time docker pull "$DOCKER_IMAGE_NAME"
+else
+ # Make sure docker image has been built. Should be instantaneous if so.
+ docker build -t "$DOCKER_IMAGE_NAME" "$DOCKERFILE_DIR"
+fi
+
+# Choose random name for docker container
+CONTAINER_NAME="build_and_run_docker_$(uuidgen)"
+
+# Run command inside docker
+# TODO: use a proper array instead of $EXTRA_DOCKER_ARGS
+# shellcheck disable=SC2086
+docker run \
+ "$@" \
+ --cap-add SYS_PTRACE \
+ -e EXTERNAL_GIT_ROOT="/var/local/jenkins/grpc" \
+ -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+ -e "KOKORO_BUILD_ID=$KOKORO_BUILD_ID" \
+ -e "KOKORO_BUILD_NUMBER=$KOKORO_BUILD_NUMBER" \
+ -e "KOKORO_BUILD_URL=$KOKORO_BUILD_URL" \
+ -e "KOKORO_JOB_NAME=$KOKORO_JOB_NAME" \
+ -v "$git_root:/var/local/jenkins/grpc:ro" \
+ -w /var/local/git/grpc \
+ --name="$CONTAINER_NAME" \
+ $EXTRA_DOCKER_ARGS \
+ "$DOCKER_IMAGE_NAME" \
+ /bin/bash -l "/var/local/jenkins/grpc/$DOCKER_RUN_SCRIPT" || FAILED="true"
+
+# Copy output artifacts
+if [ "$OUTPUT_DIR" != "" ]
+then
+ # Create the artifact directory in advance to avoid a race in "docker cp" if tasks
+ # that were running in parallel finish at the same time.
+ # see https://github.com/grpc/grpc/issues/16155
+ mkdir -p "$git_root/$OUTPUT_DIR"
+ docker cp "$CONTAINER_NAME:/var/local/git/grpc/$OUTPUT_DIR" "$git_root" || FAILED="true"
+fi
+
+# remove the container, possibly killing it first
+docker rm -f "$CONTAINER_NAME" || true
+
+if [ "$FAILED" != "" ]
+then
+ exit 1
+fi
diff --git a/tools/run_tests/dockerize/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
new file mode 100644
index 00000000..4a7908b0
--- /dev/null
+++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by run_tests.py to accommodate "test under docker"
+# scenario. You should never need to call this script on your own.
+
+# shellcheck disable=SC2103
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+git_root=$(pwd)
+cd -
+
+# Inputs
+# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
+# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
+# DOCKERHUB_ORGANIZATION - If set, pull a prebuilt image from given dockerhub org.
+
+# Use image name based on Dockerfile location checksum
+DOCKER_IMAGE_NAME=$(basename "$DOCKERFILE_DIR"):$(sha1sum "$DOCKERFILE_DIR/Dockerfile" | cut -f1 -d\ )
+
+if [ "$DOCKERHUB_ORGANIZATION" != "" ]
+then
+ DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME
+ time docker pull "$DOCKER_IMAGE_NAME"
+else
+ # Make sure docker image has been built. Should be instantaneous if so.
+ docker build -t "$DOCKER_IMAGE_NAME" "$DOCKERFILE_DIR"
+fi
+
+# Choose random name for docker container
+CONTAINER_NAME="run_tests_$(uuidgen)"
+
+# Git root as seen by the docker instance
+docker_instance_git_root=/var/local/jenkins/grpc
+
+# Run tests inside docker
+DOCKER_EXIT_CODE=0
+# TODO: silence complaint about $TTY_FLAG expansion in some other way
+# shellcheck disable=SC2086,SC2154
+docker run \
+ --cap-add SYS_PTRACE \
+ -e "RUN_TESTS_COMMAND=$RUN_TESTS_COMMAND" \
+ -e "config=$config" \
+ -e "arch=$arch" \
+ -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+ -e HOST_GIT_ROOT="$git_root" \
+ -e LOCAL_GIT_ROOT=$docker_instance_git_root \
+ -e "BUILD_ID=$BUILD_ID" \
+ -e "BUILD_URL=$BUILD_URL" \
+ -e "JOB_BASE_NAME=$JOB_BASE_NAME" \
+ -e "KOKORO_BUILD_ID=$KOKORO_BUILD_ID" \
+ -e "KOKORO_BUILD_NUMBER=$KOKORO_BUILD_NUMBER" \
+ -e "KOKORO_BUILD_URL=$KOKORO_BUILD_URL" \
+ -e "KOKORO_JOB_NAME=$KOKORO_JOB_NAME" \
+ -i \
+ $TTY_FLAG \
+ --sysctl net.ipv6.conf.all.disable_ipv6=0 \
+ -v ~/.config/gcloud:/root/.config/gcloud \
+ -v "$git_root:$docker_instance_git_root" \
+ -v /tmp/npm-cache:/tmp/npm-cache \
+ -w /var/local/git/grpc \
+ --name="$CONTAINER_NAME" \
+ "$DOCKER_IMAGE_NAME" \
+ bash -l "/var/local/jenkins/grpc/$DOCKER_RUN_SCRIPT" || DOCKER_EXIT_CODE=$?
+
+# use unique name for reports.zip to prevent clash between concurrent
+# run_tests.py runs
+TEMP_REPORTS_ZIP=$(mktemp)
+docker cp "$CONTAINER_NAME:/var/local/git/grpc/reports.zip" "${TEMP_REPORTS_ZIP}" || true
+unzip -o "${TEMP_REPORTS_ZIP}" -d "$git_root" || true
+rm -f "${TEMP_REPORTS_ZIP}"
+
+# remove the container, possibly killing it first
+docker rm -f "$CONTAINER_NAME" || true
+
+exit $DOCKER_EXIT_CODE
diff --git a/tools/run_tests/dockerize/build_interop_image.sh b/tools/run_tests/dockerize/build_interop_image.sh
new file mode 100644
index 00000000..5b5bfb65
--- /dev/null
+++ b/tools/run_tests/dockerize/build_interop_image.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by run_interop_tests.py to build the docker image
+# for interop testing. You should never need to call this script on your own.
+
+set -ex
+
+# Params:
+# INTEROP_IMAGE - name of tag of the final interop image
+# BASE_NAME - base name used to locate the base Dockerfile and build script
+# TTY_FLAG - optional -t flag to make docker allocate tty
+# BUILD_INTEROP_DOCKER_EXTRA_ARGS - optional args to be passed to the
+# docker run command
+# GRPC_ROOT - grpc base directory, default to top of this tree.
+# GRPC_GO_ROOT - grpc-go base directory, default to '$GRPC_ROOT/../grpc-go'
+# GRPC_JAVA_ROOT - grpc-java base directory, default to '$GRPC_ROOT/../grpc-java'
+
+cd "$(dirname "$0")/../../.."
+echo "GRPC_ROOT: ${GRPC_ROOT:=$(pwd)}"
+MOUNT_ARGS="-v $GRPC_ROOT:/var/local/jenkins/grpc:ro"
+
+echo "GRPC_JAVA_ROOT: ${GRPC_JAVA_ROOT:=$(cd ../grpc-java && pwd)}"
+if [ -n "$GRPC_JAVA_ROOT" ]
+then
+ MOUNT_ARGS+=" -v $GRPC_JAVA_ROOT:/var/local/jenkins/grpc-java:ro"
+else
+ echo "WARNING: grpc-java not found, it won't be mounted to the docker container."
+fi
+
+echo "GRPC_GO_ROOT: ${GRPC_GO_ROOT:=$(cd ../grpc-go && pwd)}"
+if [ -n "$GRPC_GO_ROOT" ]
+then
+ MOUNT_ARGS+=" -v $GRPC_GO_ROOT:/var/local/jenkins/grpc-go:ro"
+else
+ echo "WARNING: grpc-go not found, it won't be mounted to the docker container."
+fi
+
+echo "GRPC_DART_ROOT: ${GRPC_DART_ROOT:=$(cd ../grpc-dart && pwd)}"
+if [ -n "$GRPC_DART_ROOT" ]
+then
+ MOUNT_ARGS+=" -v $GRPC_DART_ROOT:/var/local/jenkins/grpc-dart:ro"
+else
+ echo "WARNING: grpc-dart not found, it won't be mounted to the docker container."
+fi
+
+echo "GRPC_NODE_ROOT: ${GRPC_NODE_ROOT:=$(cd ../grpc-node && pwd)}"
+if [ -n "$GRPC_NODE_ROOT" ]
+then
+ MOUNT_ARGS+=" -v $GRPC_NODE_ROOT:/var/local/jenkins/grpc-node:ro"
+else
+ echo "WARNING: grpc-node not found, it won't be mounted to the docker container."
+fi
+
+echo "GRPC_DOTNET_ROOT: ${GRPC_DOTNET_ROOT:=$(cd ../grpc-dotnet && pwd)}"
+if [ -n "$GRPC_DOTNET_ROOT" ]
+then
+ MOUNT_ARGS+=" -v $GRPC_DOTNET_ROOT:/var/local/jenkins/grpc-dotnet:ro"
+else
+ echo "WARNING: grpc-dotnet not found, it won't be mounted to the docker container."
+fi
+
+# Mount service account dir if available.
+# If service_directory does not contain the service account JSON file,
+# some of the tests will fail.
+if [ -e "$HOME/service_account" ]
+then
+ MOUNT_ARGS+=" -v $HOME/service_account:/var/local/jenkins/service_account:ro"
+fi
+
+# Use image name based on Dockerfile checksum
+# on OSX use md5 instead of sha1sum
+if command -v sha1sum > /dev/null;
+then
+ BASE_IMAGE=${BASE_NAME}:$(sha1sum "tools/dockerfile/interoptest/$BASE_NAME/Dockerfile" | cut -f1 -d\ )
+else
+ BASE_IMAGE=${BASE_NAME}:$(md5 -r "tools/dockerfile/interoptest/$BASE_NAME/Dockerfile" | cut -f1 -d\ )
+fi
+
+if [ "$DOCKERHUB_ORGANIZATION" != "" ]
+then
+ BASE_IMAGE=$DOCKERHUB_ORGANIZATION/$BASE_IMAGE
+ time docker pull "$BASE_IMAGE"
+else
+ # Make sure docker image has been built. Should be instantaneous if so.
+ docker build -t "$BASE_IMAGE" --force-rm=true "tools/dockerfile/interoptest/$BASE_NAME" || exit $?
+fi
+
+CONTAINER_NAME="build_${BASE_NAME}_$(uuidgen)"
+
+# Prepare image for interop tests, commit it on success.
+# TODO: Figure out if is safe to eliminate the suppression. It's currently here
+# because $MOUNT_ARGS and $BUILD_INTEROP_DOCKER_EXTRA_ARGS can have legitimate
+# spaces, but the "correct" way to do this is to utilize proper arrays.
+# Same for $TTY_FLAG
+# shellcheck disable=SC2086
+(docker run \
+ --cap-add SYS_PTRACE \
+ -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+ -e THIS_IS_REALLY_NEEDED_ONCE_AGAIN='For issue 4835. See https://github.com/docker/docker/issues/14203 for why docker is awful' \
+ -i \
+ $TTY_FLAG \
+ $MOUNT_ARGS \
+ $BUILD_INTEROP_DOCKER_EXTRA_ARGS \
+ --name="$CONTAINER_NAME" \
+ "$BASE_IMAGE" \
+ bash -l "/var/local/jenkins/grpc/tools/dockerfile/interoptest/$BASE_NAME/build_interop.sh" \
+ && docker commit "$CONTAINER_NAME" "$INTEROP_IMAGE" \
+ && echo "Successfully built image $INTEROP_IMAGE")
+EXITCODE=$?
+
+# remove intermediate container, possibly killing it first
+docker rm -f "$CONTAINER_NAME"
+
+exit $EXITCODE
diff --git a/tools/run_tests/dockerize/docker_run.sh b/tools/run_tests/dockerize/docker_run.sh
new file mode 100644
index 00000000..e525019c
--- /dev/null
+++ b/tools/run_tests/dockerize/docker_run.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by build_docker_* inside a docker
+# container. You should never need to call this script on your own.
+
+set -ex
+
+if [ "$RELATIVE_COPY_PATH" == "" ]
+then
+ mkdir -p /var/local/git
+ git clone "$EXTERNAL_GIT_ROOT" /var/local/git/grpc
+ # clone gRPC submodules, use data from locally cloned submodules where possible
+ # TODO: figure out a way to eliminate this following shellcheck suppressions
+ # shellcheck disable=SC2016,SC1004
+ (cd "${EXTERNAL_GIT_ROOT}" && git submodule foreach 'git clone ${EXTERNAL_GIT_ROOT}/${name} /var/local/git/grpc/${name}')
+ (cd /var/local/git/grpc && git submodule init)
+else
+ mkdir -p "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+ cp -r "$EXTERNAL_GIT_ROOT/$RELATIVE_COPY_PATH"/* "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+fi
+
+$POST_GIT_STEP
+
+if [ -x "$(command -v rvm)" ]
+then
+ rvm use ruby-2.1
+fi
+
+cd /var/local/git/grpc
+
+$RUN_COMMAND
diff --git a/tools/run_tests/dockerize/docker_run_tests.sh b/tools/run_tests/dockerize/docker_run_tests.sh
new file mode 100644
index 00000000..2a3b6f53
--- /dev/null
+++ b/tools/run_tests/dockerize/docker_run_tests.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is invoked by build_docker_and_run_tests.sh inside a docker
+# container. You should never need to call this script on your own.
+
+set -e
+
+export CONFIG=${config:-opt}
+export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
+export PATH=$PATH:/usr/bin/llvm-symbolizer
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+# clone gRPC submodules, use data from locally cloned submodules where possible
+# TODO: figure out a way to eliminate this shellcheck suppression:
+# shellcheck disable=SC2016
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'git clone /var/local/jenkins/grpc/${name} /var/local/git/grpc/${name}')
+(cd /var/local/git/grpc/ && git submodule init)
+
+mkdir -p reports
+
+$POST_GIT_STEP
+
+exit_code=0
+
+$RUN_TESTS_COMMAND || exit_code=$?
+
+# The easiest way to copy all the reports files from inside of
+# the docker container is to zip them and then copy the zip.
+zip -r reports.zip reports
+find . -name report.xml -print0 | xargs -0 -r zip reports.zip
+find . -name sponge_log.xml -print0 | xargs -0 -r zip reports.zip
+find . -name 'report_*.xml' -print0 | xargs -0 -r zip reports.zip
+
+exit $exit_code
diff --git a/tools/run_tests/helper_scripts/build_csharp.sh b/tools/run_tests/helper_scripts/build_csharp.sh
new file mode 100644
index 00000000..c6bee82b
--- /dev/null
+++ b/tools/run_tests/helper_scripts/build_csharp.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../../src/csharp"
+
+if [ "$CONFIG" == "gcov" ]
+then
+ # overriding NativeDependenciesConfigurationUnix makes C# project pick up the gcov flavor of grpc_csharp_ext
+ dotnet build --configuration "$MSBUILD_CONFIG" /p:NativeDependenciesConfigurationUnix=gcov Grpc.sln
+else
+ dotnet build --configuration "$MSBUILD_CONFIG" Grpc.sln
+fi
diff --git a/tools/run_tests/helper_scripts/build_php.sh b/tools/run_tests/helper_scripts/build_php.sh
new file mode 100644
index 00000000..4add0366
--- /dev/null
+++ b/tools/run_tests/helper_scripts/build_php.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+CONFIG=${CONFIG:-opt}
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+root=$(pwd)
+export GRPC_LIB_SUBDIR=libs/$CONFIG
+export CFLAGS="-Wno-parentheses-equality"
+
+# build php
+cd src/php
+
+cd ext/grpc
+phpize
+if [ "$CONFIG" != "gcov" ] ; then
+ ./configure --enable-grpc="$root" --enable-tests
+else
+ ./configure --enable-grpc="$root" --enable-coverage --enable-tests
+fi
+make
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
new file mode 100644
index 00000000..7b928d14
--- /dev/null
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -0,0 +1,238 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+##########################
+# Portability operations #
+##########################
+
+PLATFORM=$(uname -s)
+
+function is_msys() {
+ if [ "${PLATFORM/MSYS}" != "$PLATFORM" ]; then
+ echo true
+ else
+ exit 1
+ fi
+}
+
+function is_mingw() {
+ if [ "${PLATFORM/MINGW}" != "$PLATFORM" ]; then
+ echo true
+ else
+ exit 1
+ fi
+}
+
+function is_darwin() {
+ if [ "${PLATFORM/Darwin}" != "$PLATFORM" ]; then
+ echo true
+ else
+ exit 1
+ fi
+}
+
+function is_linux() {
+ if [ "${PLATFORM/Linux}" != "$PLATFORM" ]; then
+ echo true
+ else
+ exit 1
+ fi
+}
+
+function inside_venv() {
+ if [[ -n "${VIRTUAL_ENV}" ]]; then
+ echo true
+ fi
+}
+
+# Associated virtual environment name for the given python command.
+function venv() {
+ $1 -c "import sys; print('py{}{}'.format(*sys.version_info[:2]))"
+}
+
+# Path to python executable within a virtual environment depending on the
+# system.
+function venv_relative_python() {
+ if [ "$(is_mingw)" ]; then
+ echo 'Scripts/python.exe'
+ else
+ echo 'bin/python'
+ fi
+}
+
+# Distutils toolchain to use depending on the system.
+function toolchain() {
+ if [ "$(is_mingw)" ]; then
+ echo 'mingw32'
+ else
+ echo 'unix'
+ fi
+}
+
+# TODO(jtattermusch): this adds dependency on grealpath on mac
+# (brew install coreutils) for little reason.
+# Command to invoke the linux command `realpath` or equivalent.
+function script_realpath() {
+ # Find `realpath`
+ if [ -x "$(command -v realpath)" ]; then
+ realpath "$@"
+ elif [ -x "$(command -v grealpath)" ]; then
+ grealpath "$@"
+ else
+ exit 1
+ fi
+}
+
+####################
+# Script Arguments #
+####################
+
+PYTHON=${1:-python2.7}
+VENV=${2:-$(venv "$PYTHON")}
+VENV_RELATIVE_PYTHON=${3:-$(venv_relative_python)}
+TOOLCHAIN=${4:-$(toolchain)}
+
+if [ "$(is_msys)" ]; then
+ echo "MSYS doesn't directly provide the right compiler(s);"
+ echo "switch to a MinGW shell."
+ exit 1
+fi
+
+ROOT=$(pwd)
+export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS"
+export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export LANG=en_US.UTF-8
+
+# Allow build_ext to build C/C++ files in parallel
+# by enabling a monkeypatch. It speeds up the build a lot.
+DEFAULT_PARALLEL_JOBS=$(nproc) || DEFAULT_PARALLEL_JOBS=4
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=${GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS:-$DEFAULT_PARALLEL_JOBS}
+
+# If ccache is available on Linux, use it.
+if [ "$(is_linux)" ]; then
+ # We're not on Darwin (Mac OS X)
+ if [ -x "$(command -v ccache)" ]; then
+ if [ -x "$(command -v gcc)" ]; then
+ export CC='ccache gcc'
+ elif [ -x "$(command -v clang)" ]; then
+ export CC='ccache clang'
+ fi
+ fi
+fi
+
+############################
+# Perform build operations #
+############################
+
+if [[ "$(inside_venv)" ]]; then
+ VENV_PYTHON="$PYTHON"
+else
+ # Instantiate the virtualenv from the Python version passed in.
+ $PYTHON -m pip install --user virtualenv==16.7.9
+ $PYTHON -m virtualenv "$VENV"
+ VENV_PYTHON=$(script_realpath "$VENV/$VENV_RELATIVE_PYTHON")
+fi
+
+# See https://github.com/grpc/grpc/issues/14815 for more context. We cannot rely
+# on pip to upgrade itself because if pip is too old, it may not have the required
+# TLS version to run `pip install`.
+curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | $VENV_PYTHON
+
+# pip-installs the directory specified. Used because on MSYS the vanilla Windows
+# Python gets confused when parsing paths.
+pip_install_dir() {
+ PWD=$(pwd)
+ cd "$1"
+ ($VENV_PYTHON setup.py build_ext -c "$TOOLCHAIN" || true)
+ $VENV_PYTHON -m pip install --no-deps .
+ cd "$PWD"
+}
+
+# On library/version/platforms combo that do not have a binary
+# published, we may end up building a dependency from source. In that
+# case, several of our build environment variables may disrupt the
+# third-party build process. This function pipes through only the
+# minimal environment necessary.
+pip_install() {
+ /usr/bin/env -i PATH="$PATH" "$VENV_PYTHON" -m pip install "$@"
+}
+
+case "$VENV" in
+ *py36_gevent*)
+ # TODO(https://github.com/grpc/grpc/issues/15411) unpin this
+ pip_install gevent==1.3.b1
+ ;;
+ *gevent*)
+ pip_install -U gevent
+ ;;
+esac
+
+
+pip_install --upgrade setuptools==44.1.1
+pip_install --upgrade pip==19.3.1
+pip_install --upgrade cython
+pip_install --upgrade six protobuf
+
+if [ "$("$VENV_PYTHON" -c "import sys; print(sys.version_info[0])")" == "2" ]
+then
+ pip_install --upgrade futures enum34
+fi
+
+pip_install_dir "$ROOT"
+
+$VENV_PYTHON "$ROOT/tools/distrib/python/make_grpcio_tools.py"
+pip_install_dir "$ROOT/tools/distrib/python/grpcio_tools"
+
+# Build/install Channelz
+$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_channelz"
+
+# Build/install health checking
+$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_health_checking"
+
+# Build/install reflection
+$VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_reflection"
+
+# Build/install status proto mapping
+$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_status"
+
+# Build/install csds
+pip_install_dir "$ROOT/src/python/grpcio_csds"
+
+# Build/install admin
+pip_install_dir "$ROOT/src/python/grpcio_admin"
+
+# Install testing
+pip_install_dir "$ROOT/src/python/grpcio_testing"
+
+# Build/install tests
+pip_install coverage==4.4 oauth2client==4.1.0 \
+ google-auth>=1.17.2 requests==2.14.2 \
+ googleapis-common-protos>=1.5.5 rsa==4.0
+$VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" preprocess
+$VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" build_package_protos
+pip_install_dir "$ROOT/src/python/grpcio_tests"
diff --git a/tools/run_tests/helper_scripts/build_python_msys2.sh b/tools/run_tests/helper_scripts/build_python_msys2.sh
new file mode 100644
index 00000000..f388b4bf
--- /dev/null
+++ b/tools/run_tests/helper_scripts/build_python_msys2.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+BUILD_PYTHON=$(realpath "$(dirname "$0")/build_python.sh")
+export MSYSTEM=$1
+shift 1
+bash --login "$BUILD_PYTHON" "$@"
diff --git a/tools/run_tests/helper_scripts/build_ruby.sh b/tools/run_tests/helper_scripts/build_ruby.sh
new file mode 100644
index 00000000..cc1fe928
--- /dev/null
+++ b/tools/run_tests/helper_scripts/build_ruby.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export GRPC_CONFIG=${CONFIG:-opt}
+if [ "${GRPC_CONFIG}" == "dbg" ]
+then
+ CMAKE_CONFIG=Debug
+else
+ CMAKE_CONFIG=Release
+fi
+
+# change to grpc's ruby directory
+cd "$(dirname "$0")/../../.."
+
+rm -rf ./tmp
+rake compile
+
+# build grpc_ruby_plugin
+mkdir -p cmake/build
+pushd cmake/build
+cmake -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=${CMAKE_CONFIG} ../..
+make protoc grpc_ruby_plugin -j2
+popd
+
+# unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake build)
+# see https://github.com/madler/zlib/issues/133
+(cd third_party/zlib; git checkout zconf.h)
diff --git a/tools/run_tests/helper_scripts/bundle_install_wrapper.sh b/tools/run_tests/helper_scripts/bundle_install_wrapper.sh
new file mode 100644
index 00000000..ab31dd5c
--- /dev/null
+++ b/tools/run_tests/helper_scripts/bundle_install_wrapper.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+SYSTEM=$(uname | cut -f 1 -d_)
+
+if [ "$SYSTEM" == "Darwin" ] ; then
+ # Workaround for crash during bundle install
+ # See suggestion in https://github.com/bundler/bundler/issues/3692
+ BUNDLE_SPECIFIC_PLATFORM=true bundle install
+else
+ bundle install
+fi
+
diff --git a/tools/run_tests/helper_scripts/post_tests_c.sh b/tools/run_tests/helper_scripts/post_tests_c.sh
new file mode 100644
index 00000000..e4ab2035
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_c.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+root=$(readlink -f "$(dirname "$0")/../../..")
+out=$root/reports/c_cxx_coverage
+tmp1=$(mktemp)
+tmp2=$(mktemp)
+cd "$root"
+lcov --capture --directory . --output-file "$tmp1"
+lcov --extract "$tmp1" "$root/src/*" "$root/include/*" --output-file "$tmp2"
+genhtml "$tmp2" --output-directory "$out"
+rm "$tmp2"
+rm "$tmp1"
+
diff --git a/tools/run_tests/helper_scripts/post_tests_csharp.sh b/tools/run_tests/helper_scripts/post_tests_csharp.sh
new file mode 100644
index 00000000..6473dfd0
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_csharp.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+# change to gRPC repo root
+cd "$(dirname "$0")/../../.."
+
+# Generate the csharp extension coverage report
+gcov objs/gcov/src/csharp/ext/*.o
+lcov --base-directory . --directory . -c -o coverage.info
+lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
+genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
+ -t 'gRPC C# native extension test coverage' coverage.info \
+ --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
diff --git a/tools/run_tests/helper_scripts/post_tests_php.sh b/tools/run_tests/helper_scripts/post_tests_php.sh
new file mode 100644
index 00000000..b23e4bd1
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_php.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+root=$(readlink -f "$(dirname "$0")/../../..")
+out=$root/reports/php_ext_coverage
+tmp1=$(mktemp)
+tmp2=$(mktemp)
+cd "$root"
+lcov --capture --directory . --output-file "$tmp1"
+lcov --extract "$tmp1" "$root/src/php/ext/grpc/*" --output-file "$tmp2"
+genhtml "$tmp2" --output-directory "$out"
+rm "$tmp2"
+rm "$tmp1"
+
+# todo(mattkwong): generate coverage report for php and copy to reports/php
diff --git a/tools/run_tests/helper_scripts/post_tests_python.sh b/tools/run_tests/helper_scripts/post_tests_python.sh
new file mode 100644
index 00000000..bca9b20e
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_python.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+# change to directory of Python coverage files
+cd "$(dirname "$0")/../../../src/python/grpcio_tests/"
+
+coverage combine .
+coverage html -i -d ./../../../reports/python
diff --git a/tools/run_tests/helper_scripts/post_tests_ruby.sh b/tools/run_tests/helper_scripts/post_tests_ruby.sh
new file mode 100644
index 00000000..f0860015
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_ruby.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+root=$(readlink -f "$(dirname "$0")/../../..")
+out=$root/reports/ruby_ext_coverage
+tmp1=$(mktemp)
+tmp2=$(mktemp)
+cd "$root"
+lcov --capture --directory . --output-file "$tmp1"
+lcov --extract "$tmp1" "$root/src/ruby/*" --output-file "$tmp2"
+genhtml "$tmp2" --output-directory "$out"
+rm "$tmp2"
+rm "$tmp1"
+
+cp -rv "$root/coverage" "$root/reports/ruby"
diff --git a/tools/run_tests/helper_scripts/pre_build_cmake.sh b/tools/run_tests/helper_scripts/pre_build_cmake.sh
new file mode 100644
index 00000000..62eaf1f4
--- /dev/null
+++ b/tools/run_tests/helper_scripts/pre_build_cmake.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+mkdir -p cmake/build
+cd cmake/build
+
+# MSBUILD_CONFIG's values are suitable for cmake as well
+cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE="${MSBUILD_CONFIG}" "$@" ../..
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.sh b/tools/run_tests/helper_scripts/pre_build_csharp.sh
new file mode 100644
index 00000000..e334d7e8
--- /dev/null
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# cd to repository root
+cd "$(dirname "$0")/../../.."
+
+mkdir -p cmake/build
+cd cmake/build
+
+cmake -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE="${MSBUILD_CONFIG}" -DgRPC_XDS_USER_AGENT_IS_CSHARP=ON ../..
+
+cd ../../src/csharp
+
+dotnet restore Grpc.sln
diff --git a/tools/run_tests/helper_scripts/pre_build_ruby.sh b/tools/run_tests/helper_scripts/pre_build_ruby.sh
new file mode 100644
index 00000000..b5740963
--- /dev/null
+++ b/tools/run_tests/helper_scripts/pre_build_ruby.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+export GRPC_CONFIG=${CONFIG:-opt}
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+tools/run_tests/helper_scripts/bundle_install_wrapper.sh
diff --git a/tools/run_tests/helper_scripts/prep_xds.sh b/tools/run_tests/helper_scripts/prep_xds.sh
new file mode 100644
index 00000000..64e7c40e
--- /dev/null
+++ b/tools/run_tests/helper_scripts/prep_xds.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trap 'date' DEBUG
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+sudo apt-get install -y python3-pip
+sudo python3 -m pip install --upgrade pip
+sudo python3 -m pip install --upgrade setuptools
+sudo python3 -m pip install --upgrade grpcio==1.31.0 grpcio-tools==1.31.0 protobuf google-api-python-client google-auth-httplib2 oauth2client xds-protos
+
+# Prepare generated Python code.
+TOOLS_DIR=tools/run_tests
+PROTO_SOURCE_DIR=src/proto/grpc/testing
+PROTO_DEST_DIR=${TOOLS_DIR}/${PROTO_SOURCE_DIR}
+mkdir -p ${PROTO_DEST_DIR}
+
+python3 -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${PROTO_SOURCE_DIR}/test.proto \
+ ${PROTO_SOURCE_DIR}/messages.proto \
+ ${PROTO_SOURCE_DIR}/empty.proto
+
+HEALTH_PROTO_SOURCE_DIR=src/proto/grpc/health/v1
+HEALTH_PROTO_DEST_DIR=${TOOLS_DIR}/${HEALTH_PROTO_SOURCE_DIR}
+mkdir -p ${HEALTH_PROTO_DEST_DIR}
+
+python3 -m grpc_tools.protoc \
+ --proto_path=. \
+ --python_out=${TOOLS_DIR} \
+ --grpc_python_out=${TOOLS_DIR} \
+ ${HEALTH_PROTO_SOURCE_DIR}/health.proto
diff --git a/tools/run_tests/helper_scripts/run_grpc-node.sh b/tools/run_tests/helper_scripts/run_grpc-node.sh
new file mode 100644
index 00000000..f54d69e9
--- /dev/null
+++ b/tools/run_tests/helper_scripts/run_grpc-node.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script runs grpc/grpc-node tests with their grpc submodule updated
+# to this reference
+
+set -ex
+
+# cd to gRPC root directory
+cd "$(dirname "$0")/../../.."
+
+CURRENT_COMMIT="$(git rev-parse --verify HEAD)"
+
+rm -rf ./../grpc-node
+git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
+cd ./../grpc-node
+
+echo "TODO(jtattermusch): Skipping grpc-node's ./test-grpc-submodule.sh $CURRENT_COMMIT"
+echo "because it currently doesn't provide any useful signal."
+echo "See b/152833238"
+#./test-grpc-submodule.sh "$CURRENT_COMMIT"
diff --git a/tools/run_tests/helper_scripts/run_python.sh b/tools/run_tests/helper_scripts/run_python.sh
new file mode 100644
index 00000000..2b7321e5
--- /dev/null
+++ b/tools/run_tests/helper_scripts/run_python.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+PYTHON=$(realpath "${1:-py27/bin/python}")
+
+ROOT=$(pwd)
+
+$PYTHON "$ROOT/src/python/grpcio_tests/setup.py" "$2"
+
+mkdir -p "$ROOT/reports"
+rm -rf "$ROOT/reports/python-coverage"
+(mv -T "$ROOT/htmlcov" "$ROOT/reports/python-coverage") || true
+
diff --git a/tools/run_tests/helper_scripts/run_ruby.sh b/tools/run_tests/helper_scripts/run_ruby.sh
new file mode 100644
index 00000000..4e9c2128
--- /dev/null
+++ b/tools/run_tests/helper_scripts/run_ruby.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd "$(dirname "$0")/../../.."
+
+rake
diff --git a/tools/run_tests/helper_scripts/run_tests_in_workspace.sh b/tools/run_tests/helper_scripts/run_tests_in_workspace.sh
new file mode 100644
index 00000000..fa7a7aac
--- /dev/null
+++ b/tools/run_tests/helper_scripts/run_tests_in_workspace.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Create a workspace in a subdirectory to allow running multiple builds in isolation.
+# WORKSPACE_NAME env variable needs to contain name of the workspace to create.
+# All cmdline args will be passed to run_tests.py script (executed in the
+# newly created workspace)
+set -ex
+
+cd "$(dirname "$0")/../../.."
+repo_root="$(pwd)"
+export repo_root
+
+rm -rf "${WORKSPACE_NAME}"
+git clone . "${WORKSPACE_NAME}"
+# clone gRPC submodules, use data from locally cloned submodules where possible
+# shellcheck disable=SC2016,SC1004
+git submodule foreach 'cd "${repo_root}/${WORKSPACE_NAME}" \
+ && git submodule update --init --reference ${repo_root}/${name} ${name}'
+
+echo "Running run_tests.py in workspace ${WORKSPACE_NAME}"
+python "${WORKSPACE_NAME}/tools/run_tests/run_tests.py" "$@"
diff --git a/tools/run_tests/interop/with_nvm.sh b/tools/run_tests/interop/with_nvm.sh
new file mode 100644
index 00000000..55f4b2b8
--- /dev/null
+++ b/tools/run_tests/interop/with_nvm.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Makes sure NVM is loaded before executing the command passed as an argument
+# shellcheck disable=SC1090
+source ~/.nvm/nvm.sh
+"$@"
diff --git a/tools/run_tests/interop/with_rvm.sh b/tools/run_tests/interop/with_rvm.sh
new file mode 100644
index 00000000..82bce9da
--- /dev/null
+++ b/tools/run_tests/interop/with_rvm.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Makes sure RVM is loaded before executing the command passed as an argument
+# shellcheck disable=SC1091
+source /usr/local/rvm/scripts/rvm
+"$@"
diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
new file mode 100644
index 00000000..4bf2186b
--- /dev/null
+++ b/tools/run_tests/performance/build_performance.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# shellcheck disable=SC1090
+source ~/.rvm/scripts/rvm
+set -ex
+
+cd "$(dirname "$0")/../../.."
+bazel=$(pwd)/tools/bazel
+
+CONFIG=${CONFIG:-opt}
+
+# build C++ qps worker & driver always - we need at least the driver to
+# run any of the scenarios.
+# TODO(jtattermusch): C++ worker and driver are not buildable on Windows yet
+if [ "$OSTYPE" != "msys" ]
+then
+ # build C++ with cmake as building with "make" disables boringssl assembly
+ # optimizations that can have huge impact on secure channel throughput.
+ mkdir -p cmake/build
+ cd cmake/build
+ cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ../..
+ make qps_worker qps_json_driver -j8
+ cd ../..
+ # unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake build)
+ # See https://github.com/grpc/grpc/issues/11581
+ (cd third_party/zlib; git checkout zconf.h)
+fi
+
+PHP_ALREADY_BUILT=""
+for language in "$@"
+do
+ case "$language" in
+ "c++")
+ ;; # C++ has already been built.
+ "java")
+ (cd ../grpc-java/ &&
+ ./gradlew -PskipCodegen=true -PskipAndroid=true :grpc-benchmarks:installDist)
+ ;;
+ "go")
+ tools/run_tests/performance/build_performance_go.sh
+ ;;
+ "php7"|"php7_protobuf_c")
+ if [ -n "$PHP_ALREADY_BUILT" ]; then
+ echo "Skipping PHP build as already built by $PHP_ALREADY_BUILT"
+ else
+ PHP_ALREADY_BUILT=$language
+ tools/run_tests/performance/build_performance_php7.sh
+ fi
+ ;;
+ "csharp")
+ python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8
+ # unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake portion of C#'s build)
+ # See https://github.com/grpc/grpc/issues/11581
+ (cd third_party/zlib; git checkout zconf.h)
+ ;;
+ "node"|"node_purejs")
+ tools/run_tests/performance/build_performance_node.sh
+ ;;
+ "python")
+ $bazel build -c opt //src/python/grpcio_tests/tests/qps:qps_worker
+ ;;
+ "python_asyncio")
+ $bazel build -c opt //src/python/grpcio_tests/tests_aio/benchmark:worker
+ ;;
+ *)
+ python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8
+ ;;
+ esac
+done
diff --git a/tools/run_tests/performance/build_performance_go.sh b/tools/run_tests/performance/build_performance_go.sh
new file mode 100644
index 00000000..3aa203a6
--- /dev/null
+++ b/tools/run_tests/performance/build_performance_go.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+GOPATH=$(pwd)/../gopath
+export GOPATH
+
+# Get grpc-go and the dependencies but get rid of the upstream/master version
+go get google.golang.org/grpc
+rm -rf "${GOPATH}/src/google.golang.org/grpc"
+
+# Get the revision of grpc-go we want to test
+git clone --recursive ../grpc-go "${GOPATH}/src/google.golang.org/grpc"
+
+(cd "${GOPATH}/src/google.golang.org/grpc/benchmark/worker" && go install)
diff --git a/tools/run_tests/performance/build_performance_node.sh b/tools/run_tests/performance/build_performance_node.sh
new file mode 100644
index 00000000..b5b5d9a1
--- /dev/null
+++ b/tools/run_tests/performance/build_performance_node.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set +ex
+
+# shellcheck disable=SC1090
+. "$HOME/.nvm/nvm.sh"
+
+nvm install 10
+
+set -ex
+
+cd "$(dirname "$0")/../../../../grpc-node"
+
+npm install
+
+./node_modules/.bin/gulp setup
diff --git a/tools/run_tests/performance/build_performance_php7.sh b/tools/run_tests/performance/build_performance_php7.sh
new file mode 100644
index 00000000..386c7862
--- /dev/null
+++ b/tools/run_tests/performance/build_performance_php7.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+CONFIG=${CONFIG:-opt}
+python tools/run_tests/run_tests.py -l php7 -c "$CONFIG" --build_only -j 8
+
+# Set up all dependences needed for PHP QPS test
+cd src/php/tests/qps
+composer install
+# Install protobuf C-extension for php
+cd ../../../../third_party/protobuf/php/ext/google/protobuf
+phpize
+./configure
+make
+
diff --git a/tools/run_tests/performance/kill_workers.sh b/tools/run_tests/performance/kill_workers.sh
new file mode 100644
index 00000000..95a5bf5d
--- /dev/null
+++ b/tools/run_tests/performance/kill_workers.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Make sure there are no pre-existing QPS workers around before starting
+# the performance test suite
+
+# C++
+killall -9 qps_worker || true
+
+# C#
+# shellcheck disable=SC2009
+ps -C mono -o pid=,cmd= | grep QpsWorker | awk '{print $1}' | xargs kill -9 || true
+# shellcheck disable=SC2009
+ps -C dotnet -o pid=,cmd= | grep QpsWorker | awk '{print $1}' | xargs kill -9 || true
+
+# Ruby
+# shellcheck disable=SC2009
+ps -C ruby -o pid=,cmd= | grep 'qps/worker.rb' | awk '{print $1}' | xargs kill -9 || true
+
+# Python
+# shellcheck disable=SC2009
+ps -C python -o pid=,cmd= | grep 'qps_worker.py' | awk '{print $1}' | xargs kill -9 || true
+
+# Java
+jps | grep LoadWorker | awk '{print $1}' | xargs kill -9 || true
+
+# Go
+killall -9 worker || true
diff --git a/tools/run_tests/performance/loadtest_examples.sh b/tools/run_tests/performance/loadtest_examples.sh
new file mode 100644
index 00000000..c7714b3e
--- /dev/null
+++ b/tools/run_tests/performance/loadtest_examples.sh
@@ -0,0 +1,129 @@
+#!/bin/bash
+# Copyright 2021 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script generates a set of load test examples from templates.
+
+LOADTEST_CONFIG=tools/run_tests/performance/loadtest_config.py
+
+if (( $# < 1 )); then
+ echo "Usage: ${0}