From f2ffbb89a2f7456b897e5556782e8639d161a6f6 Mon Sep 17 00:00:00 2001
From: Sreenithi Sridharan <19sreenithi98@gmail.com>
Date: Wed, 25 Sep 2024 20:11:10 -0700
Subject: [PATCH 01/74] Add templating and support for Python 3.13 (#37643)
This PR adds templating for Python versions and updates the maximum supported Python version to 3.13. The following major changes related to templating are added:
- Minimum supported Python version and list of supported versions in `setup.py` are fetched using new template generated files called `python_version.py`
- Dockerfiles for the different Python Linux builds are now template generated.
- The "Supported Python Versions" section from READMEs of ancillary and main packages have been removed
Note: All the `python_version.py` files and Linux build `Dockerfiles` except `tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile` in the PR are generated from the respective templates.
Further non-templated additions to add support for Python 3.13:
- install scripts and artifacts for windows, macos and linux are added manually. Later, these can be templated as well.
- updated cython bounds to 3.x
- updated twine version to solve [cgi module import error](https://github.com/pypa/twine/issues/1046)
- the twine update introduces a dependency on cryptography>=2.0. But the cryptography package doesn't support 32-bit Linux images and hence `twine check` has been disabled for x86 manylinux and x86 musllinux artifacts.
Closes #37643
PiperOrigin-RevId: 678954495
---
PYTHON-MANIFEST.in | 1 +
WORKSPACE | 2 +-
bazel/grpc_python_deps.bzl | 6 +-
black.toml | 1 +
build_handwritten.yaml | 7 +++
setup.py | 27 +++++----
src/python/grpcio/README.rst | 3 -
src/python/grpcio/python_version.py | 20 +++++++
src/python/grpcio_admin/MANIFEST.in | 1 +
src/python/grpcio_admin/python_version.py | 20 +++++++
src/python/grpcio_admin/setup.py | 5 +-
src/python/grpcio_channelz/MANIFEST.in | 1 +
src/python/grpcio_channelz/README.rst | 3 -
src/python/grpcio_channelz/grpc_version.py | 2 +-
src/python/grpcio_channelz/python_version.py | 20 +++++++
src/python/grpcio_channelz/setup.py | 29 ++++++----
src/python/grpcio_csds/MANIFEST.in | 1 +
src/python/grpcio_csds/python_version.py | 20 +++++++
src/python/grpcio_csds/setup.py | 4 +-
.../grpcio_csm_observability/MANIFEST.in | 1 +
.../grpcio_csm_observability/README.rst | 3 -
.../python_version.py | 20 +++++++
src/python/grpcio_csm_observability/setup.py | 4 +-
src/python/grpcio_health_checking/MANIFEST.in | 1 +
src/python/grpcio_health_checking/README.rst | 3 -
.../grpcio_health_checking/python_version.py | 20 +++++++
src/python/grpcio_health_checking/setup.py | 27 +++++----
src/python/grpcio_observability/MANIFEST.in | 1 +
src/python/grpcio_observability/README.rst | 3 -
.../grpcio_observability/python_version.py | 20 +++++++
src/python/grpcio_observability/setup.py | 3 +-
src/python/grpcio_reflection/MANIFEST.in | 1 +
src/python/grpcio_reflection/README.rst | 3 -
.../grpcio_reflection/python_version.py | 20 +++++++
src/python/grpcio_reflection/setup.py | 27 +++++----
src/python/grpcio_status/MANIFEST.in | 1 +
src/python/grpcio_status/README.rst | 3 -
src/python/grpcio_status/python_version.py | 20 +++++++
src/python/grpcio_status/setup.py | 27 +++++----
src/python/grpcio_testing/README.rst | 3 -
.../python/grpcio/python_version.py.template | 22 +++++++
.../grpcio_admin/python_version.py.template | 22 +++++++
.../grpcio_channelz/grpc_version.py.template | 2 +-
.../python_version.py.template | 22 +++++++
.../grpcio_csds/python_version.py.template | 22 +++++++
.../python_version.py.template | 22 +++++++
.../python_version.py.template | 22 +++++++
.../python_version.py.template | 22 +++++++
.../python_version.py.template | 22 +++++++
.../grpcio_status/python_version.py.template | 22 +++++++
.../distrib/python/grpc_version.py.template | 2 +-
.../grpc_tools/python_version.py.template | 22 +++++++
.../grpcio_tools/python_version.py.template | 22 +++++++
.../xds_protos/grpc_version.py.template | 2 +-
.../xds_protos/python_version.py.template | 22 +++++++
.../dockerfile/ccache_crosscompile.include | 14 +++++
.../dockerfile/compile_python_313.include | 21 +++++++
templates/tools/dockerfile/git_config.include | 22 +++++++
.../Dockerfile.template | 57 +++++++++++++++++++
.../Dockerfile.template | 28 +++++++++
.../Dockerfile.template | 33 +++++++++++
.../Dockerfile.template | 34 +++++++++++
.../Dockerfile.template | 27 +++++++++
.../Dockerfile.template | 25 ++++++++
.../dockerfile/python_pip_builds.include | 8 +++
.../Dockerfile.template | 1 +
test/distrib/bazel/python/WORKSPACE | 2 +-
.../dockerimage_current_versions.bzl | 14 ++---
tools/bazelify_tests/test/BUILD | 8 +--
... build_artifact_python_linux_x64_cp313.sh} | 4 +-
.../expand_supported_python_versions.py | 33 +++++++++++
tools/distrib/install_all_python_modules.sh | 1 -
tools/distrib/python/grpc_version.py | 2 +-
tools/distrib/python/grpcio_tools/MANIFEST.in | 2 +
.../grpcio_tools/grpc_tools/python_version.py | 20 +++++++
.../python/grpcio_tools/python_version.py | 20 +++++++
tools/distrib/python/grpcio_tools/setup.py | 3 +-
tools/distrib/python/xds_protos/MANIFEST.in | 1 +
.../distrib/python/xds_protos/grpc_version.py | 2 +-
.../python/xds_protos/python_version.py | 20 +++++++
tools/distrib/python/xds_protos/setup.py | 4 +-
tools/dockerfile/README.md | 4 ++
...rtifact_python_linux_armv7.current_version | 2 +-
.../Dockerfile | 40 ++++++++++---
...stall_python_for_wheel_crosscompilation.sh | 2 +-
...thon_manylinux2014_aarch64.current_version | 2 +-
.../Dockerfile | 50 +++++++++++-----
...t_python_manylinux2014_x64.current_version | 2 +-
.../Dockerfile | 48 +++++++++++-----
...t_python_manylinux2014_x86.current_version | 2 +-
.../Dockerfile | 48 +++++++++++-----
...t_python_musllinux_1_1_x64.current_version | 2 +-
.../Dockerfile | 52 ++++++++++++-----
...t_python_musllinux_1_1_x86.current_version | 2 +-
.../Dockerfile | 50 +++++++++++-----
...ython_debian11_default_x64.current_version | 2 +-
.../python_debian11_default_x64/Dockerfile | 22 +++++++
.../install_python_interpreters.ps1 | 17 ++++++
.../helper_scripts/prepare_build_macos_rc | 8 +++
.../helper_scripts/requirements.macos.txt | 2 +-
.../macos/grpc_distribtests_python.sh | 12 ++--
tools/run_tests/artifacts/artifact_targets.py | 32 ++++++++---
.../artifacts/build_artifact_python.bat | 2 +-
.../artifacts/build_artifact_python.sh | 5 +-
tools/run_tests/run_tests.py | 10 ++++
105 files changed, 1260 insertions(+), 218 deletions(-)
create mode 100644 src/python/grpcio/python_version.py
create mode 100644 src/python/grpcio_admin/python_version.py
create mode 100644 src/python/grpcio_channelz/python_version.py
create mode 100644 src/python/grpcio_csds/python_version.py
create mode 100644 src/python/grpcio_csm_observability/python_version.py
create mode 100644 src/python/grpcio_health_checking/python_version.py
create mode 100644 src/python/grpcio_observability/python_version.py
create mode 100644 src/python/grpcio_reflection/python_version.py
create mode 100644 src/python/grpcio_status/python_version.py
create mode 100644 templates/src/python/grpcio/python_version.py.template
create mode 100644 templates/src/python/grpcio_admin/python_version.py.template
create mode 100644 templates/src/python/grpcio_channelz/python_version.py.template
create mode 100644 templates/src/python/grpcio_csds/python_version.py.template
create mode 100644 templates/src/python/grpcio_csm_observability/python_version.py.template
create mode 100644 templates/src/python/grpcio_health_checking/python_version.py.template
create mode 100644 templates/src/python/grpcio_observability/python_version.py.template
create mode 100644 templates/src/python/grpcio_reflection/python_version.py.template
create mode 100644 templates/src/python/grpcio_status/python_version.py.template
create mode 100644 templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template
create mode 100644 templates/tools/distrib/python/grpcio_tools/python_version.py.template
create mode 100644 templates/tools/distrib/python/xds_protos/python_version.py.template
create mode 100644 templates/tools/dockerfile/ccache_crosscompile.include
create mode 100644 templates/tools/dockerfile/compile_python_313.include
create mode 100644 templates/tools/dockerfile/git_config.include
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template
create mode 100644 templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template
create mode 100644 templates/tools/dockerfile/python_pip_builds.include
rename tools/bazelify_tests/test/{build_artifact_python_linux_x64_cp312.sh => build_artifact_python_linux_x64_cp313.sh} (93%)
create mode 100644 tools/buildgen/plugins/expand_supported_python_versions.py
create mode 100644 tools/distrib/python/grpcio_tools/grpc_tools/python_version.py
create mode 100644 tools/distrib/python/grpcio_tools/python_version.py
create mode 100644 tools/distrib/python/xds_protos/python_version.py
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index dd76dbcf756..b8ab04726ed 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -17,6 +17,7 @@ include src/python/grpcio/_parallel_compile_patch.py
include src/python/grpcio/_spawn_patch.py
include src/python/grpcio/commands.py
include src/python/grpcio/grpc_version.py
+include src/python/grpcio/python_version.py
include src/python/grpcio/grpc_core_dependencies.py
include src/python/grpcio/precompiled.py
include src/python/grpcio/support.py
diff --git a/WORKSPACE b/WORKSPACE
index f88a7790594..675233b2eb1 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -89,7 +89,7 @@ load("@com_google_protobuf//bazel:system_python.bzl", "system_python")
system_python(
name = "system_python",
- minimum_python_version = "3.7",
+ minimum_python_version = "3.8",
)
load("@system_python//:pip.bzl", system_pip_parse = "pip_parse")
diff --git a/bazel/grpc_python_deps.bzl b/bazel/grpc_python_deps.bzl
index dbfff526a11..44eca11f671 100644
--- a/bazel/grpc_python_deps.bzl
+++ b/bazel/grpc_python_deps.bzl
@@ -38,9 +38,9 @@ def grpc_python_deps():
http_archive(
name = "cython",
build_file = "@com_github_grpc_grpc//third_party:cython.BUILD",
- sha256 = "a2da56cc22be823acf49741b9aa3aa116d4f07fa8e8b35a3cb08b8447b37c607",
- strip_prefix = "cython-0.29.35",
+ sha256 = "2ec7d66d23d6da2328fb24f5c1bec6c63a59ec2e91027766ab904f417e1078aa",
+ strip_prefix = "cython-3.0.11",
urls = [
- "https://github.com/cython/cython/archive/0.29.35.tar.gz",
+ "https://github.com/cython/cython/archive/3.0.11.tar.gz",
],
)
diff --git a/black.toml b/black.toml
index e655f7f8e7e..1a397fea579 100644
--- a/black.toml
+++ b/black.toml
@@ -15,6 +15,7 @@ extend-exclude = '''
| test/cpp/naming/resolver_component_tests_runner.py # AUTO-GENERATED
# AUTO-GENERATED from a template:
| grpc_version.py
+ | python_version.py
| src/python/grpcio/grpc_core_dependencies.py
| src/python/grpcio/grpc/_grpcio_metadata.py
# AUTO-GENERATED BY make_grpcio_tools.py
diff --git a/build_handwritten.yaml b/build_handwritten.yaml
index 61e73166122..3c0d694d77c 100644
--- a/build_handwritten.yaml
+++ b/build_handwritten.yaml
@@ -16,6 +16,13 @@ settings:
csharp_major_version: 2
g_stands_for: groovy
protobuf_version: 3.28.1
+ supported_python_versions:
+ - '3.8'
+ - '3.9'
+ - '3.10'
+ - '3.11'
+ - '3.12'
+ - '3.13'
version: 1.68.0-dev
configs:
asan:
diff --git a/setup.py b/setup.py
index b93637215ff..48bfefe4dba 100644
--- a/setup.py
+++ b/setup.py
@@ -88,6 +88,7 @@ sys.path.insert(0, os.path.abspath(PYTHON_STEM))
import _parallel_compile_patch
import _spawn_patch
import grpc_core_dependencies
+import python_version
import commands
import grpc_version
@@ -95,19 +96,21 @@ import grpc_version
_parallel_compile_patch.monkeypatch_compile_maybe()
_spawn_patch.monkeypatch_spawn()
+
LICENSE = "Apache License 2.0"
-CLASSIFIERS = [
- "Development Status :: 5 - Production/Stable",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "License :: OSI Approved :: Apache Software License",
-]
+CLASSIFIERS = (
+ [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ]
+ + [
+ f"Programming Language :: Python :: {x}"
+ for x in python_version.SUPPORTED_PYTHON_VERSIONS
+ ]
+ + ["License :: OSI Approved :: Apache Software License"]
+)
def _env_bool_value(env_name, default):
@@ -596,7 +599,7 @@ setuptools.setup(
packages=list(PACKAGES),
package_dir=PACKAGE_DIRECTORIES,
package_data=PACKAGE_DATA,
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
extras_require=EXTRAS_REQUIRES,
setup_requires=SETUP_REQUIRES,
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index eb2e8a9aa59..cd529ad54f7 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -8,9 +8,6 @@ Package for gRPC Python.
.. |compat_check_pypi| image:: https://python-compatibility-tools.appspot.com/one_badge_image?package=grpcio
:target: https://python-compatibility-tools.appspot.com/one_badge_target?package=grpcio
-Supported Python Versions
--------------------------
-Python >= 3.8
Installation
------------
diff --git a/src/python/grpcio/python_version.py b/src/python/grpcio/python_version.py
new file mode 100644
index 00000000000..4faab63465c
--- /dev/null
+++ b/src/python/grpcio/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_admin/MANIFEST.in b/src/python/grpcio_admin/MANIFEST.in
index eb7e029a4ba..3cb62658770 100644
--- a/src/python/grpcio_admin/MANIFEST.in
+++ b/src/python/grpcio_admin/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
recursive-include grpc_admin *.py
global-exclude *.pyc
include LICENSE
diff --git a/src/python/grpcio_admin/python_version.py b/src/python/grpcio_admin/python_version.py
new file mode 100644
index 00000000000..d47284cb06f
--- /dev/null
+++ b/src/python/grpcio_admin/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_admin/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_admin/setup.py b/src/python/grpcio_admin/setup.py
index 4e6bdbc8dd5..30d0ca62a14 100644
--- a/src/python/grpcio_admin/setup.py
+++ b/src/python/grpcio_admin/setup.py
@@ -25,6 +25,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
CLASSIFIERS = [
@@ -44,6 +46,7 @@ INSTALL_REQUIRES = (
)
SETUP_REQUIRES = INSTALL_REQUIRES
+
setuptools.setup(
name="grpcio-admin",
version=grpc_version.VERSION,
@@ -56,7 +59,7 @@ setuptools.setup(
url="https://grpc.io",
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
)
diff --git a/src/python/grpcio_channelz/MANIFEST.in b/src/python/grpcio_channelz/MANIFEST.in
index 7354bef4235..14089064dce 100644
--- a/src/python/grpcio_channelz/MANIFEST.in
+++ b/src/python/grpcio_channelz/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
recursive-include grpc_channelz *.py *.pyi
global-exclude *.pyc
include LICENSE
diff --git a/src/python/grpcio_channelz/README.rst b/src/python/grpcio_channelz/README.rst
index 027c0d9e10c..26056422143 100644
--- a/src/python/grpcio_channelz/README.rst
+++ b/src/python/grpcio_channelz/README.rst
@@ -3,9 +3,6 @@ gRPC Python Channelz package
Channelz is a live debug tool in gRPC Python.
-Supported Python Versions
--------------------------
-Python >= 3.8
Dependencies
------------
diff --git a/src/python/grpcio_channelz/grpc_version.py b/src/python/grpcio_channelz/grpc_version.py
index de5e63dddcf..fff1849540e 100644
--- a/src/python/grpcio_channelz/grpc_version.py
+++ b/src/python/grpcio_channelz/grpc_version.py
@@ -12,6 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/python_version.py.template`!!!
VERSION = '1.68.0.dev0'
diff --git a/src/python/grpcio_channelz/python_version.py b/src/python/grpcio_channelz/python_version.py
new file mode 100644
index 00000000000..74755fdb1a9
--- /dev/null
+++ b/src/python/grpcio_channelz/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_channelz/setup.py b/src/python/grpcio_channelz/setup.py
index 034ed814829..222a0d30ca3 100644
--- a/src/python/grpcio_channelz/setup.py
+++ b/src/python/grpcio_channelz/setup.py
@@ -25,6 +25,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
@@ -44,17 +46,19 @@ class _NoOpCommand(setuptools.Command):
pass
-CLASSIFIERS = [
- "Development Status :: 5 - Production/Stable",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "License :: OSI Approved :: Apache Software License",
-]
+CLASSIFIERS = (
+ [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ]
+ + [
+ f"Programming Language :: Python :: {x}"
+ for x in python_version.SUPPORTED_PYTHON_VERSIONS
+ ]
+ + ["License :: OSI Approved :: Apache Software License"]
+)
+
PACKAGE_DIRECTORIES = {
"": ".",
@@ -85,6 +89,7 @@ except ImportError:
"build_package_protos": _NoOpCommand,
}
+
setuptools.setup(
name="grpcio-channelz",
version=grpc_version.VERSION,
@@ -97,7 +102,7 @@ setuptools.setup(
url="https://grpc.io",
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
cmdclass=COMMAND_CLASS,
diff --git a/src/python/grpcio_csds/MANIFEST.in b/src/python/grpcio_csds/MANIFEST.in
index 4ecdf7428ed..3df9cc3cac2 100644
--- a/src/python/grpcio_csds/MANIFEST.in
+++ b/src/python/grpcio_csds/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
recursive-include grpc_csds *.py
global-exclude *.pyc
include LICENSE
diff --git a/src/python/grpcio_csds/python_version.py b/src/python/grpcio_csds/python_version.py
new file mode 100644
index 00000000000..5d9e6b076ea
--- /dev/null
+++ b/src/python/grpcio_csds/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csds/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_csds/setup.py b/src/python/grpcio_csds/setup.py
index 8fb4dab5341..1dc40333f03 100644
--- a/src/python/grpcio_csds/setup.py
+++ b/src/python/grpcio_csds/setup.py
@@ -25,6 +25,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
CLASSIFIERS = [
@@ -57,7 +59,7 @@ setuptools.setup(
url="https://grpc.io",
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
)
diff --git a/src/python/grpcio_csm_observability/MANIFEST.in b/src/python/grpcio_csm_observability/MANIFEST.in
index 754eb1d7e13..afaf3464883 100644
--- a/src/python/grpcio_csm_observability/MANIFEST.in
+++ b/src/python/grpcio_csm_observability/MANIFEST.in
@@ -1,4 +1,5 @@
graft src/python/grpcio_csm_observability/grpc_csm_observability.egg-info
graft grpc_csm_observability
include grpc_version.py
+include python_version.py
include README.rst
diff --git a/src/python/grpcio_csm_observability/README.rst b/src/python/grpcio_csm_observability/README.rst
index f2c549afdb1..4725f758140 100644
--- a/src/python/grpcio_csm_observability/README.rst
+++ b/src/python/grpcio_csm_observability/README.rst
@@ -3,9 +3,6 @@ gRPC Python CSM Observability
Package for gRPC Python CSM Observability.
-Supported Python Versions
--------------------------
-Python >= 3.8
Installation
------------
diff --git a/src/python/grpcio_csm_observability/python_version.py b/src/python/grpcio_csm_observability/python_version.py
new file mode 100644
index 00000000000..4309c6a3ce0
--- /dev/null
+++ b/src/python/grpcio_csm_observability/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csm_observability/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_csm_observability/setup.py b/src/python/grpcio_csm_observability/setup.py
index c9a26db1ed5..ce4ec398a1d 100644
--- a/src/python/grpcio_csm_observability/setup.py
+++ b/src/python/grpcio_csm_observability/setup.py
@@ -22,6 +22,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
# Ensure we're in the proper directory whether or not we're being used by pip.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
+import python_version
+
import grpc_version
CLASSIFIERS = [
@@ -58,6 +60,6 @@ setuptools.setup(
classifiers=CLASSIFIERS,
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
)
diff --git a/src/python/grpcio_health_checking/MANIFEST.in b/src/python/grpcio_health_checking/MANIFEST.in
index 6644074dc22..f68d10ad183 100644
--- a/src/python/grpcio_health_checking/MANIFEST.in
+++ b/src/python/grpcio_health_checking/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
recursive-include grpc_health *.py *.pyi
global-exclude *.pyc
include LICENSE
diff --git a/src/python/grpcio_health_checking/README.rst b/src/python/grpcio_health_checking/README.rst
index d13e671eae4..388fe3148fe 100644
--- a/src/python/grpcio_health_checking/README.rst
+++ b/src/python/grpcio_health_checking/README.rst
@@ -3,9 +3,6 @@ gRPC Python Health Checking
Reference package for GRPC Python health checking.
-Supported Python Versions
--------------------------
-Python >= 3.8
Dependencies
------------
diff --git a/src/python/grpcio_health_checking/python_version.py b/src/python/grpcio_health_checking/python_version.py
new file mode 100644
index 00000000000..96e4e2f0e06
--- /dev/null
+++ b/src/python/grpcio_health_checking/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 97a40723097..7d451e63ee6 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -24,6 +24,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
@@ -43,17 +45,18 @@ class _NoOpCommand(setuptools.Command):
pass
-CLASSIFIERS = [
- "Development Status :: 5 - Production/Stable",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "License :: OSI Approved :: Apache Software License",
-]
+CLASSIFIERS = (
+ [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ]
+ + [
+ f"Programming Language :: Python :: {x}"
+ for x in python_version.SUPPORTED_PYTHON_VERSIONS
+ ]
+ + ["License :: OSI Approved :: Apache Software License"]
+)
PACKAGE_DIRECTORIES = {
"": ".",
@@ -96,7 +99,7 @@ setuptools.setup(
classifiers=CLASSIFIERS,
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
cmdclass=COMMAND_CLASS,
diff --git a/src/python/grpcio_observability/MANIFEST.in b/src/python/grpcio_observability/MANIFEST.in
index 8efdc8f6f21..ffd7f861231 100644
--- a/src/python/grpcio_observability/MANIFEST.in
+++ b/src/python/grpcio_observability/MANIFEST.in
@@ -4,5 +4,6 @@ graft grpc_root
graft third_party
include _parallel_compile_patch.py
include grpc_version.py
+include python_version.py
include observability_lib_deps.py
include README.rst
diff --git a/src/python/grpcio_observability/README.rst b/src/python/grpcio_observability/README.rst
index 11ba92f90f5..513ebe02112 100644
--- a/src/python/grpcio_observability/README.rst
+++ b/src/python/grpcio_observability/README.rst
@@ -17,9 +17,6 @@ Note that while this approach enhances efficiency, it will introduce a slight de
time the data is collected and the time it becomes available through Python exporters.
-Supported Python Versions
--------------------------
-Python >= 3.8
Installation
------------
diff --git a/src/python/grpcio_observability/python_version.py b/src/python/grpcio_observability/python_version.py
new file mode 100644
index 00000000000..aca7367b65c
--- /dev/null
+++ b/src/python/grpcio_observability/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_observability/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_observability/setup.py b/src/python/grpcio_observability/setup.py
index 60be8deee92..1bf43a8170f 100644
--- a/src/python/grpcio_observability/setup.py
+++ b/src/python/grpcio_observability/setup.py
@@ -34,6 +34,7 @@ sys.path.insert(0, os.path.abspath("."))
import _parallel_compile_patch
import observability_lib_deps
+import python_version
import grpc_version
@@ -287,7 +288,7 @@ setuptools.setup(
classifiers=CLASSIFIERS,
ext_modules=extension_modules(),
packages=list(PACKAGES),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=[
"grpcio=={version}".format(version=grpc_version.VERSION),
"setuptools>=59.6.0",
diff --git a/src/python/grpcio_reflection/MANIFEST.in b/src/python/grpcio_reflection/MANIFEST.in
index eefb53d31f8..547bdd27597 100644
--- a/src/python/grpcio_reflection/MANIFEST.in
+++ b/src/python/grpcio_reflection/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
recursive-include grpc_reflection *.py *.pyi
global-exclude *.pyc
include LICENSE
diff --git a/src/python/grpcio_reflection/README.rst b/src/python/grpcio_reflection/README.rst
index b954108cc45..abb54a57f14 100644
--- a/src/python/grpcio_reflection/README.rst
+++ b/src/python/grpcio_reflection/README.rst
@@ -3,9 +3,6 @@ gRPC Python Reflection package
Reference package for reflection in GRPC Python.
-Supported Python Versions
--------------------------
-Python >= 3.8
Dependencies
------------
diff --git a/src/python/grpcio_reflection/python_version.py b/src/python/grpcio_reflection/python_version.py
new file mode 100644
index 00000000000..e94e725d14d
--- /dev/null
+++ b/src/python/grpcio_reflection/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py
index fd2cd7eb872..ca7e23219fd 100644
--- a/src/python/grpcio_reflection/setup.py
+++ b/src/python/grpcio_reflection/setup.py
@@ -25,6 +25,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
@@ -44,17 +46,18 @@ class _NoOpCommand(setuptools.Command):
pass
-CLASSIFIERS = [
- "Development Status :: 5 - Production/Stable",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "License :: OSI Approved :: Apache Software License",
-]
+CLASSIFIERS = (
+ [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ]
+ + [
+ f"Programming Language :: Python :: {x}"
+ for x in python_version.SUPPORTED_PYTHON_VERSIONS
+ ]
+ + ["License :: OSI Approved :: Apache Software License"]
+)
PACKAGE_DIRECTORIES = {
"": ".",
@@ -97,7 +100,7 @@ setuptools.setup(
url="https://grpc.io",
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
cmdclass=COMMAND_CLASS,
diff --git a/src/python/grpcio_status/MANIFEST.in b/src/python/grpcio_status/MANIFEST.in
index 3ecc88ec2dd..62439177f19 100644
--- a/src/python/grpcio_status/MANIFEST.in
+++ b/src/python/grpcio_status/MANIFEST.in
@@ -1,4 +1,5 @@
include grpc_version.py
+include python_version.py
include grpc_status/google/rpc/status.proto
recursive-include grpc_status *.py
global-exclude *.pyc
diff --git a/src/python/grpcio_status/README.rst b/src/python/grpcio_status/README.rst
index bfc753c799e..c2c8efcc0c7 100644
--- a/src/python/grpcio_status/README.rst
+++ b/src/python/grpcio_status/README.rst
@@ -3,9 +3,6 @@ gRPC Python Status Proto
Reference package for GRPC Python status proto mapping.
-Supported Python Versions
--------------------------
-Python >= 3.8
Dependencies
------------
diff --git a/src/python/grpcio_status/python_version.py b/src/python/grpcio_status/python_version.py
new file mode 100644
index 00000000000..02de6673e4b
--- /dev/null
+++ b/src/python/grpcio_status/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/src/python/grpcio_status/setup.py b/src/python/grpcio_status/setup.py
index f70013774c9..f98032d28b1 100644
--- a/src/python/grpcio_status/setup.py
+++ b/src/python/grpcio_status/setup.py
@@ -24,6 +24,8 @@ _README_PATH = os.path.join(_PACKAGE_PATH, "README.rst")
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our local modules.
+import python_version
+
import grpc_version
@@ -43,17 +45,18 @@ class _NoOpCommand(setuptools.Command):
pass
-CLASSIFIERS = [
- "Development Status :: 5 - Production/Stable",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "License :: OSI Approved :: Apache Software License",
-]
+CLASSIFIERS = (
+ [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ]
+ + [
+ f"Programming Language :: Python :: {x}"
+ for x in python_version.SUPPORTED_PYTHON_VERSIONS
+ ]
+ + ["License :: OSI Approved :: Apache Software License"]
+)
PACKAGE_DIRECTORIES = {
"": ".",
@@ -93,7 +96,7 @@ setuptools.setup(
classifiers=CLASSIFIERS,
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
cmdclass=COMMAND_CLASS,
)
diff --git a/src/python/grpcio_testing/README.rst b/src/python/grpcio_testing/README.rst
index 1b8de5dca19..34fe05be9dc 100644
--- a/src/python/grpcio_testing/README.rst
+++ b/src/python/grpcio_testing/README.rst
@@ -3,9 +3,6 @@ gRPC Python Testing Package
Testing utilities for gRPC Python
-Supported Python Versions
--------------------------
-Python >= 3.8
Dependencies
------------
diff --git a/templates/src/python/grpcio/python_version.py.template b/templates/src/python/grpcio/python_version.py.template
new file mode 100644
index 00000000000..8c8da439184
--- /dev/null
+++ b/templates/src/python/grpcio/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_admin/python_version.py.template b/templates/src/python/grpcio_admin/python_version.py.template
new file mode 100644
index 00000000000..d904c1d7228
--- /dev/null
+++ b/templates/src/python/grpcio_admin/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_admin/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_channelz/grpc_version.py.template b/templates/src/python/grpcio_channelz/grpc_version.py.template
index 75d510cd17b..999c1025257 100644
--- a/templates/src/python/grpcio_channelz/grpc_version.py.template
+++ b/templates/src/python/grpcio_channelz/grpc_version.py.template
@@ -14,6 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/python_version.py.template`!!!
VERSION = '${settings.python_version.pep440()}'
diff --git a/templates/src/python/grpcio_channelz/python_version.py.template b/templates/src/python/grpcio_channelz/python_version.py.template
new file mode 100644
index 00000000000..e0630bb7aa1
--- /dev/null
+++ b/templates/src/python/grpcio_channelz/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_csds/python_version.py.template b/templates/src/python/grpcio_csds/python_version.py.template
new file mode 100644
index 00000000000..a5cc8627ecb
--- /dev/null
+++ b/templates/src/python/grpcio_csds/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csds/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_csm_observability/python_version.py.template b/templates/src/python/grpcio_csm_observability/python_version.py.template
new file mode 100644
index 00000000000..2aa52d73111
--- /dev/null
+++ b/templates/src/python/grpcio_csm_observability/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csm_observability/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_health_checking/python_version.py.template b/templates/src/python/grpcio_health_checking/python_version.py.template
new file mode 100644
index 00000000000..6646f69979a
--- /dev/null
+++ b/templates/src/python/grpcio_health_checking/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_observability/python_version.py.template b/templates/src/python/grpcio_observability/python_version.py.template
new file mode 100644
index 00000000000..f82b1c2d7a5
--- /dev/null
+++ b/templates/src/python/grpcio_observability/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_observability/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_reflection/python_version.py.template b/templates/src/python/grpcio_reflection/python_version.py.template
new file mode 100644
index 00000000000..29d9d47cffc
--- /dev/null
+++ b/templates/src/python/grpcio_reflection/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/src/python/grpcio_status/python_version.py.template b/templates/src/python/grpcio_status/python_version.py.template
new file mode 100644
index 00000000000..cb6aeda5a05
--- /dev/null
+++ b/templates/src/python/grpcio_status/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/tools/distrib/python/grpc_version.py.template b/templates/tools/distrib/python/grpc_version.py.template
index 5031353b871..0d36735631d 100644
--- a/templates/tools/distrib/python/grpc_version.py.template
+++ b/templates/tools/distrib/python/grpc_version.py.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpc_version.py.template`!!!
VERSION = '${settings.python_version.pep440()}'
PROTOBUF_VERSION = '${settings.protobuf_version}'
diff --git a/templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template b/templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template
new file mode 100644
index 00000000000..6e06a5a4bb8
--- /dev/null
+++ b/templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/tools/distrib/python/grpcio_tools/python_version.py.template b/templates/tools/distrib/python/grpcio_tools/python_version.py.template
new file mode 100644
index 00000000000..a40390110d8
--- /dev/null
+++ b/templates/tools/distrib/python/grpcio_tools/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/tools/distrib/python/xds_protos/grpc_version.py.template b/templates/tools/distrib/python/xds_protos/grpc_version.py.template
index 7808e28e219..ba301d6b865 100644
--- a/templates/tools/distrib/python/xds_protos/grpc_version.py.template
+++ b/templates/tools/distrib/python/xds_protos/grpc_version.py.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/xds_protos/grpc_version.py.template`!!!
VERSION = '${settings.python_version.pep440()}'
PROTOBUF_VERSION = '${settings.protobuf_version}'
diff --git a/templates/tools/distrib/python/xds_protos/python_version.py.template b/templates/tools/distrib/python/xds_protos/python_version.py.template
new file mode 100644
index 00000000000..6f9d0562f32
--- /dev/null
+++ b/templates/tools/distrib/python/xds_protos/python_version.py.template
@@ -0,0 +1,22 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/xds_protos/python_version.py.template`!!!
+
+ SUPPORTED_PYTHON_VERSIONS = ${settings.supported_python_versions}
+
+ MIN_PYTHON_VERSION = ${settings.min_python_version}
+ MAX_PYTHON_VERSION = ${settings.max_python_version}
diff --git a/templates/tools/dockerfile/ccache_crosscompile.include b/templates/tools/dockerfile/ccache_crosscompile.include
new file mode 100644
index 00000000000..04136e01b53
--- /dev/null
+++ b/templates/tools/dockerfile/ccache_crosscompile.include
@@ -0,0 +1,14 @@
+#=================
+# Install ccache
+
+# Install ccache from source since ccache 3.x packaged with most linux distributions
+# does not support Redis backend for caching.
+RUN unset CMAKE_TOOLCHAIN_FILE && unset AS AR CC CPP CXX LD STRIP OBJCOPY ${'\\'}
+ && curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz ${'\\'}
+ && tar -zxf ccache.tar.gz ${'\\'}
+ && cd ccache-4.7.5 ${'\\'}
+ && mkdir build && cd build ${'\\'}
+ && cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. ${'\\'}
+ && make -j4 && make install ${'\\'}
+ && cd ../.. ${'\\'}
+ && rm -rf ccache-4.7.5 ccache.tar.gz
diff --git a/templates/tools/dockerfile/compile_python_313.include b/templates/tools/dockerfile/compile_python_313.include
new file mode 100644
index 00000000000..e7d4bd38a9b
--- /dev/null
+++ b/templates/tools/dockerfile/compile_python_313.include
@@ -0,0 +1,21 @@
+#=================
+# Compile CPython 3.13.0rc2 from source
+
+RUN apt-get update && apt-get install -y zlib1g-dev libssl-dev libsqlite3-dev && apt-get clean
+RUN apt-get update && apt-get install -y jq build-essential libffi-dev && apt-get clean
+
+RUN cd /tmp && ${'\\'}
+ wget -q https://www.python.org/ftp/python/3.13.0/Python-3.13.0rc2.tgz && ${'\\'}
+ tar xzvf Python-3.13.0rc2.tgz && ${'\\'}
+ cd Python-3.13.0rc2 && ${'\\'}
+ ./configure && ${'\\'}
+ make -j4 && ${'\\'}
+ make install
+
+
+RUN cd /tmp && ${'\\'}
+ echo "ad7f44153649e27ec385e7633e853e03 Python-3.13.0rc2.tgz" > checksum.md5 && ${'\\'}
+ md5sum -c checksum.md5
+
+RUN python3.13 -m ensurepip && ${'\\'}
+ python3.13 -m pip install coverage
diff --git a/templates/tools/dockerfile/git_config.include b/templates/tools/dockerfile/git_config.include
new file mode 100644
index 00000000000..ad2ed5f3614
--- /dev/null
+++ b/templates/tools/dockerfile/git_config.include
@@ -0,0 +1,22 @@
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
+RUN git config --global --add safe.directory /var/local/jenkins/grpc
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
+RUN git config --global protocol.file.allow always
\ No newline at end of file
diff --git a/templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template
new file mode 100644
index 00000000000..94671a0a585
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template
@@ -0,0 +1,57 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # The aarch64 wheels are being crosscompiled to allow running the build
+ # on x64 machine. The dockcross/linux-armv7 image is a x86_64
+ # image with crosscompilation toolchain installed
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template`!!!
+ FROM dockcross/linux-armv7
+
+ <%text>RUN apt update && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
+ libnss3-dev libssl-dev libreadline-dev libffi-dev && apt-get clean%text>
+
+ ADD install_python_for_wheel_crosscompilation.sh /scripts/install_python_for_wheel_crosscompilation.sh
+
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.8.8" "3.8.8" /opt/python/cp38-cp38
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.9.2" "3.9.2" /opt/python/cp39-cp39
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.10.0" "3.10.0rc1" /opt/python/cp310-cp310
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.11.0" "3.11.0rc1" /opt/python/cp311-cp311
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.12.0" "3.12.0rc2" /opt/python/cp312-cp312
+ RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.13.0" "3.13.0rc2" /opt/python/cp313-cp313
+
+ ENV AUDITWHEEL_ARCH armv7l
+ ENV AUDITWHEEL_PLAT linux_armv7l
+
+ <%include file="../ccache_crosscompile.include"/>
+
+ # The dockcross base of this image sets CC and CXX to absolute paths, which makes it impossible to redirect their invocations
+ # to ccache via a symlink. Use relative paths instead.
+ <%text>
+ ENV CC ${CROSS_TRIPLE}-gcc
+ ENV CXX ${CROSS_TRIPLE}-g++
+ %text>
+
+ # For historical reasons, task_runner.py the script under docker container using "bash -l"
+ # which loads /etc/profile on startup. dockcross/linux-armv7 is based on an image where
+ # /etc/profile overwrites contents of PATH (for security reasons) when run as root.
+ # That causes the crosscompiler binaries located under /usr/xcc/armv7-unknown-linux-gnueabi/bin
+ # to be removed from PATH. Since in our builds we don't need the /etc/profile for anything, we can just
+ # truncate it.
+ # TODO(jtattermusch): Remove this hack when possible.
+ RUN echo "# file contents removed to avoid resetting PATH set by the docker image" >/etc/profile
+
+ <%include file="../git_config.include"/>
diff --git a/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template
new file mode 100644
index 00000000000..31c1be4aed5
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template
@@ -0,0 +1,28 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template`!!!
+
+ FROM dockcross/manylinux2014-aarch64:20240812-60fa1b0
+
+ # manylinux_2_17 is the preferred alias of manylinux2014
+ ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
+
+ <%include file="../python_pip_builds.include"/>
+
+ <%include file="../ccache_crosscompile.include"/>
+
+ <%include file="../git_config.include"/>
diff --git a/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template
new file mode 100644
index 00000000000..cf68868594e
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template
@@ -0,0 +1,33 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # Docker file for building gRPC manylinux Python artifacts.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template`!!!
+
+ FROM quay.io/pypa/manylinux2014_x86_64:2024-09-09-f386546
+
+ # manylinux_2_17 is the preferred alias of manylinux2014
+ ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
+
+ # TODO(jtattermusch): revisit which of the deps are really required
+ RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
+
+ <%include file="../python_pip_builds.include"/>
+
+ <%include file="../ccache.include"/>
+
+ <%include file="../git_config.include"/>
\ No newline at end of file
diff --git a/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template
new file mode 100644
index 00000000000..d681fd47354
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template
@@ -0,0 +1,34 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # Docker file for building gRPC manylinux Python artifacts.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template`!!!
+
+ FROM quay.io/pypa/manylinux2014_i686:2024-09-09-f386546
+
+ # manylinux_2_17 is the preferred alias of manylinux2014
+ ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
+
+ # TODO(jtattermusch): revisit which of the deps are really required
+ RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
+
+ <%include file="../python_pip_builds.include"/>
+
+ <%include file="../ccache.include"/>
+
+
+ <%include file="../git_config.include"/>
\ No newline at end of file
diff --git a/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template
new file mode 100644
index 00000000000..dfb62902711
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template
@@ -0,0 +1,27 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template`!!!
+
+ FROM quay.io/pypa/musllinux_1_1_x86_64:2024-09-09-f386546
+
+ <%include file="../python_pip_builds.include"/>
+
+ <%include file="../ccache.include"/>
+
+ <%include file="../git_config.include"/>
+
+ RUN apk add openssl openssl-dev
\ No newline at end of file
diff --git a/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template b/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template
new file mode 100644
index 00000000000..6f7ca5a52a8
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template
@@ -0,0 +1,25 @@
+%YAML 1.2
+--- |
+ # Copyright 2024 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.
+
+ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template`!!!
+
+ FROM quay.io/pypa/musllinux_1_1_i686:2024-09-09-f386546
+
+ <%include file="../python_pip_builds.include"/>
+
+ <%include file="../ccache.include"/>
+
+ <%include file="../git_config.include"/>
diff --git a/templates/tools/dockerfile/python_pip_builds.include b/templates/tools/dockerfile/python_pip_builds.include
new file mode 100644
index 00000000000..e573a063338
--- /dev/null
+++ b/templates/tools/dockerfile/python_pip_builds.include
@@ -0,0 +1,8 @@
+#===================================
+# Install Python build requirements
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/python_debian11_default_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_debian11_default_x64/Dockerfile.template
index 0981763f21d..a385ec8d602 100644
--- a/templates/tools/dockerfile/test/python_debian11_default_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/python_debian11_default_x64/Dockerfile.template
@@ -24,6 +24,7 @@
<%include file="../../compile_python_310.include"/>
<%include file="../../compile_python_311.include"/>
<%include file="../../compile_python_312.include"/>
+ <%include file="../../compile_python_313.include"/>
# Python test coverage requires libsqlite3, and it have
# to be installed before Python.
diff --git a/test/distrib/bazel/python/WORKSPACE b/test/distrib/bazel/python/WORKSPACE
index 3567f8a2ac0..b56055fa741 100644
--- a/test/distrib/bazel/python/WORKSPACE
+++ b/test/distrib/bazel/python/WORKSPACE
@@ -29,7 +29,7 @@ load("@com_google_protobuf//bazel:system_python.bzl", "system_python")
system_python(
name = "system_python",
- minimum_python_version = "3.7",
+ minimum_python_version = "3.8",
)
load("@system_python//:pip.bzl", "pip_parse")
diff --git a/tools/bazelify_tests/dockerimage_current_versions.bzl b/tools/bazelify_tests/dockerimage_current_versions.bzl
index 5a349762058..973a649dfe5 100644
--- a/tools/bazelify_tests/dockerimage_current_versions.bzl
+++ b/tools/bazelify_tests/dockerimage_current_versions.bzl
@@ -63,12 +63,12 @@ DOCKERIMAGE_CURRENT_VERSIONS = {
"tools/dockerfile/grpc_artifact_centos6_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_centos6_x64@sha256:3285047265ea2b7c5d4df4c769b2d05f56288d947c75e16d27ae2dee693f791b",
"tools/dockerfile/grpc_artifact_centos6_x86.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_centos6_x86@sha256:19783239da92208f0f39cf563529cd02e889920497ef81c60d20391fa998af62",
"tools/dockerfile/grpc_artifact_protoc_aarch64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_protoc_aarch64@sha256:a0f6b544c1b2fa75f73b26cb28281917153304e9df2789e93de0732494e6b651",
- "tools/dockerfile/grpc_artifact_python_linux_armv7.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_linux_armv7@sha256:f109d6c22cadb053f6843a66ee827d74f34d6cbf75a32f455a9da099ed1bdc9c",
- "tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_aarch64@sha256:3f0407d4db904b35a7665c2222db039994cd0c9bdb1a073a653ff8e6940081c9",
- "tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x64@sha256:89329900ec7fedc57cd89690acd34d07d726f6b896f60df987867737d0a0f5a8",
- "tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x86@sha256:8fce8e094b00935dc1f2640b4c2b10216c5a8711c0f4444efbafcd8c355a75a8",
- "tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x64@sha256:c8e8eb24942a2910197cf5481d61e7cbce68b57bd6f35fae878b043b1f2c38bb",
- "tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x86@sha256:c288f83435186ee675d004ee52c93195a51201bf2b5fe92581584d977a2499a3",
+ "tools/dockerfile/grpc_artifact_python_linux_armv7.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_linux_armv7@sha256:137616275fe59bf89849f7503779f9a5d9668dbf395fcc79a8221a8c38fa5bac",
+ "tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_aarch64@sha256:ad3233be3c3ad9e0c4b60f0176a853713a35e5c84ec9d9703996c67fa3e811b6",
+ "tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x64@sha256:0e102df67f31aeb6afe68250603288c2f1c98ccf360d1c42d751b8451da94b48",
+ "tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x86@sha256:527e2e9ec4db0c52a53b50abfd59907a1b7e221168dc401686f6a48d33bddc5c",
+ "tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x64@sha256:94b57e5ea31ebc29af734474bcaff3074770778e5d27557cdc06d755ee8bc7ed",
+ "tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x86@sha256:edf4a0c8333c9309e52f323aa7315bbc0e5643216613cab4ecd2bce3d1ec26c0",
"tools/dockerfile/interoptest/grpc_interop_aspnetcore.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_interop_aspnetcore@sha256:8e2e732e78724a8382c340dca72e7653c5f82c251a3110fa2874cc00ba538878",
"tools/dockerfile/interoptest/grpc_interop_cxx.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_interop_cxx@sha256:e5a474d33773d52ec6a8abbe2d61ee0c2a9c2b5f48793a5ea3b82c4445becf3f",
"tools/dockerfile/interoptest/grpc_interop_dart.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_interop_dart@sha256:4915a280788126dad029858eb384dbbef2dc18cadccb434df6450dfd7a4929f2",
@@ -109,7 +109,7 @@ DOCKERIMAGE_CURRENT_VERSIONS = {
"tools/dockerfile/test/php7_debian11_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/php7_debian11_x64@sha256:34b02fd66832ebf49601bef95632753e6710a75755401c21332d50056ccd52d2",
"tools/dockerfile/test/python_alpine_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/python_alpine_x64@sha256:0a4e3c166fb676d85ea26d9fffec3858d59a2f243a3acc1c2f9bd293a590a98c",
"tools/dockerfile/test/python_debian11_default_arm64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/python_debian11_default_arm64@sha256:fccca33a655c7aa89dd7ebd9492cbcc1f636bd2a004cd939d1982cfce3d68326",
- "tools/dockerfile/test/python_debian11_default_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/python_debian11_default_x64@sha256:4c539fc93d343324309939c2964204c90f4054cd9eeed093af315cb0f0ef7c26",
+ "tools/dockerfile/test/python_debian11_default_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/python_debian11_default_x64@sha256:8beca964d6bbb80a8cb4c4628c25e9702b007c97113e74e589fa50c15000738d",
"tools/dockerfile/test/rbe_ubuntu2004.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/rbe_ubuntu2004@sha256:b3eb1a17b7b091e3c5648a803076b2c40601242ff91c04d55997af6641305f68",
"tools/dockerfile/test/ruby_debian11_arm64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/ruby_debian11_arm64@sha256:d2e79919b2e2d4cc36a29682ecb5170641df4fb506cfb453978ffdeb8a841bd9",
"tools/dockerfile/test/ruby_debian11_x64.current_version": "docker://us-docker.pkg.dev/grpc-testing/testing-images-public/ruby_debian11_x64@sha256:6e8b4696ba0661f11a31ed0992a94d2efcd889a018f57160f0e2fb62963f3593",
diff --git a/tools/bazelify_tests/test/BUILD b/tools/bazelify_tests/test/BUILD
index 4aefd22e325..dee1d5172aa 100644
--- a/tools/bazelify_tests/test/BUILD
+++ b/tools/bazelify_tests/test/BUILD
@@ -269,8 +269,8 @@ grpc_build_artifact_task(
# Python artifact build tasks
grpc_build_artifact_task(
- name = "artifact_python_linux_x64_manylinux2014_cp312",
- build_script = "build_artifact_python_linux_x64_cp312.sh",
+ name = "artifact_python_linux_x64_manylinux2014_cp313",
+ build_script = "build_artifact_python_linux_x64_cp313.sh",
docker_image_version = "tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version",
)
@@ -287,7 +287,7 @@ grpc_build_artifact_task(
name = "package_python_linux",
# TODO(jtattermusch): add more python artifacts once they are migrated from artifact_targets.py
artifact_deps = [
- "artifact_python_linux_x64_manylinux2014_cp312",
+ "artifact_python_linux_x64_manylinux2014_cp313",
"artifact_python_linux_x64_manylinux2014_cp39",
],
build_script = "build_package_python_linux.sh",
@@ -421,7 +421,7 @@ test_suite(
":artifact_protoc_linux_aarch64_build_test",
":artifact_protoc_linux_x64_build_test",
":artifact_protoc_linux_x86_build_test",
- ":artifact_python_linux_x64_manylinux2014_cp312_build_test",
+ ":artifact_python_linux_x64_manylinux2014_cp313_build_test",
":artifact_python_linux_x64_manylinux2014_cp39_build_test",
":package_csharp_linux_build_test",
":package_python_linux_build_test",
diff --git a/tools/bazelify_tests/test/build_artifact_python_linux_x64_cp312.sh b/tools/bazelify_tests/test/build_artifact_python_linux_x64_cp313.sh
similarity index 93%
rename from tools/bazelify_tests/test/build_artifact_python_linux_x64_cp312.sh
rename to tools/bazelify_tests/test/build_artifact_python_linux_x64_cp313.sh
index 8604176c82e..d8a0b6b2ec2 100755
--- a/tools/bazelify_tests/test/build_artifact_python_linux_x64_cp312.sh
+++ b/tools/bazelify_tests/test/build_artifact_python_linux_x64_cp313.sh
@@ -17,8 +17,8 @@ set -ex
# env variable values extracted from PythonArtifact in tools/run_tests/artifacts/artifact_targets.py
# TODO(jtattermusch): find a better way of configuring the python artifact build (the current approach mostly serves as a demonstration)
-export PYTHON=/opt/python/cp312-cp312/bin/python
-export PIP=/opt/python/cp312-cp312/bin/pip
+export PYTHON=/opt/python/cp313-cp313/bin/python
+export PIP=/opt/python/cp313-cp313/bin/pip
export GRPC_SKIP_PIP_CYTHON_UPGRADE=TRUE
export GRPC_RUN_AUDITWHEEL_REPAIR=TRUE
export GRPC_BUILD_GRPCIO_TOOLS_DEPENDENTS=TRUE
diff --git a/tools/buildgen/plugins/expand_supported_python_versions.py b/tools/buildgen/plugins/expand_supported_python_versions.py
new file mode 100644
index 00000000000..8cc4e814d74
--- /dev/null
+++ b/tools/buildgen/plugins/expand_supported_python_versions.py
@@ -0,0 +1,33 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Buildgen python version plugin
+
+This parses the list of supported python versions from the yaml build file, and
+creates custom strings for the minimum and maximum supported python versions.
+
+"""
+
+
+def mako_plugin(dictionary):
+ """Expand version numbers:
+ - for each language, ensure there's a language_version tag in
+ settings (defaulting to the master version tag)
+ - expand version strings to major, minor, patch, and tag
+ """
+
+ settings = dictionary["settings"]
+
+ supported_python_versions = settings["supported_python_versions"]
+ settings["min_python_version"] = supported_python_versions[0]
+ settings["max_python_version"] = supported_python_versions[-1]
diff --git a/tools/distrib/install_all_python_modules.sh b/tools/distrib/install_all_python_modules.sh
index b23b38cc624..ab5823b9553 100755
--- a/tools/distrib/install_all_python_modules.sh
+++ b/tools/distrib/install_all_python_modules.sh
@@ -59,4 +59,3 @@ pushd src/python;
popd;
done
popd;
-
diff --git a/tools/distrib/python/grpc_version.py b/tools/distrib/python/grpc_version.py
index 8cec1e10eca..28f793690ef 100644
--- a/tools/distrib/python/grpc_version.py
+++ b/tools/distrib/python/grpc_version.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpc_version.py.template`!!!
VERSION = '1.68.0.dev0'
PROTOBUF_VERSION = '3.28.1'
diff --git a/tools/distrib/python/grpcio_tools/MANIFEST.in b/tools/distrib/python/grpcio_tools/MANIFEST.in
index 1393de652a8..e74fde44b91 100644
--- a/tools/distrib/python/grpcio_tools/MANIFEST.in
+++ b/tools/distrib/python/grpcio_tools/MANIFEST.in
@@ -1,10 +1,12 @@
include _parallel_compile_patch.py
include _spawn_patch.py
include grpc_version.py
+include python_version.py
include protoc_deps.py
include protoc_lib_deps.py
include README.rst
include grpc_tools/grpc_version.py
+include grpc_tools/python_version.py
graft grpc_tools
graft grpc_root
graft third_party
diff --git a/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py b/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py
new file mode 100644
index 00000000000..0dcc71c1fda
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_tools/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/tools/distrib/python/grpcio_tools/python_version.py b/tools/distrib/python/grpcio_tools/python_version.py
new file mode 100644
index 00000000000..fc59f030fbb
--- /dev/null
+++ b/tools/distrib/python/grpcio_tools/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index d0173a61658..5e19b6314ed 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -39,6 +39,7 @@ sys.path.insert(0, os.path.abspath("."))
import _parallel_compile_patch
import _spawn_patch
import protoc_lib_deps
+import python_version
import grpc_version
@@ -329,7 +330,7 @@ setuptools.setup(
classifiers=CLASSIFIERS,
ext_modules=extension_modules(),
packages=setuptools.find_packages("."),
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=[
"protobuf>=5.26.1,<6.0dev",
"grpcio>={version}".format(version=grpc_version.VERSION),
diff --git a/tools/distrib/python/xds_protos/MANIFEST.in b/tools/distrib/python/xds_protos/MANIFEST.in
index d83c49b9186..3fea17ba661 100644
--- a/tools/distrib/python/xds_protos/MANIFEST.in
+++ b/tools/distrib/python/xds_protos/MANIFEST.in
@@ -1 +1,2 @@
include grpc_version.py
+include python_version.py
\ No newline at end of file
diff --git a/tools/distrib/python/xds_protos/grpc_version.py b/tools/distrib/python/xds_protos/grpc_version.py
index 7add68a0e24..170b505959b 100644
--- a/tools/distrib/python/xds_protos/grpc_version.py
+++ b/tools/distrib/python/xds_protos/grpc_version.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/xds_protos/grpc_version.py.template`!!!
VERSION = '1.68.0.dev0'
PROTOBUF_VERSION = '3.28.1'
diff --git a/tools/distrib/python/xds_protos/python_version.py b/tools/distrib/python/xds_protos/python_version.py
new file mode 100644
index 00000000000..80cce2eb4c5
--- /dev/null
+++ b/tools/distrib/python/xds_protos/python_version.py
@@ -0,0 +1,20 @@
+# Copyright 2024 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/xds_protos/python_version.py.template`!!!
+
+SUPPORTED_PYTHON_VERSIONS = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
+
+MIN_PYTHON_VERSION = 3.8
+MAX_PYTHON_VERSION = 3.13
diff --git a/tools/distrib/python/xds_protos/setup.py b/tools/distrib/python/xds_protos/setup.py
index f1c7247cc4b..53a6fbdfecb 100644
--- a/tools/distrib/python/xds_protos/setup.py
+++ b/tools/distrib/python/xds_protos/setup.py
@@ -19,6 +19,7 @@ import os
import setuptools
import grpc_version
+import python_version
WORK_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -44,6 +45,7 @@ INSTALL_REQUIRES = [
SETUP_REQUIRES = INSTALL_REQUIRES + ["grpcio-tools>=1.49.0"]
+
setuptools.setup(
name="xds-protos",
version=grpc_version.VERSION,
@@ -55,7 +57,7 @@ setuptools.setup(
author_email="grpc-io@googlegroups.com",
url="https://grpc.io",
license="Apache License 2.0",
- python_requires=">=3.8",
+ python_requires=f">={python_version.MIN_PYTHON_VERSION}",
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
classifiers=CLASSIFIERS,
diff --git a/tools/dockerfile/README.md b/tools/dockerfile/README.md
index 89c599d6079..fbdc872f70f 100644
--- a/tools/dockerfile/README.md
+++ b/tools/dockerfile/README.md
@@ -37,6 +37,7 @@ If you've made modifications to a dockerfile, you can upload the new version of
registry as follows:
If you haven't configured authentication in Docker for us-docker.pkg.dev previously, run:
+
```
gcloud auth configure-docker us-docker.pkg.dev
gcloud auth login
@@ -45,6 +46,7 @@ gcloud auth login
Rebuild the docker images that have been modified locally and upload the docker images to
artifact registry (note that this won't overwrite the "old" versions of the docker image
that are already in artifact registry)
+
```
# Install qemu, binformat, and configure binfmt interpreters
sudo apt-get install binfmt-support qemu-user-static
@@ -58,6 +60,7 @@ tools/dockerfile/push_testing_images.sh
Build modified docker images locally and don't push to artifact registry. This option is
very useful for quick local experiments. The script is much faster if it doesn't have to
interact with artifact registry:
+
```
# very useful for local experiments
LOCAL_ONLY_MODE=true tools/dockerfile/push_testing_images.sh
@@ -69,6 +72,7 @@ In the past, our testing docker images were [hosted on dockerhub](https://hub.do
but we are in the process of migrating them artifact registry now.
This temporary feature might simplify the migration:
+
```
# try pull existing images from dockerhub instead of building the from scratch locally.
TRANSFER_FROM_DOCKERHUB=true tools/dockerfile/push_testing_images.sh
diff --git a/tools/dockerfile/grpc_artifact_python_linux_armv7.current_version b/tools/dockerfile/grpc_artifact_python_linux_armv7.current_version
index 2ddbcc9ba32..0a992570421 100644
--- a/tools/dockerfile/grpc_artifact_python_linux_armv7.current_version
+++ b/tools/dockerfile/grpc_artifact_python_linux_armv7.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_linux_armv7:0b87638ab97b433c6818be5124dcd89d479b3a8b@sha256:f109d6c22cadb053f6843a66ee827d74f34d6cbf75a32f455a9da099ed1bdc9c
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_linux_armv7:3523bf4a67fa9100deb8f48ee4833cb5a5e97697@sha256:137616275fe59bf89849f7503779f9a5d9668dbf395fcc79a8221a8c38fa5bac
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile b/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile
index 40a22e6fe54..03aacb23b49 100644
--- a/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2020 The gRPC Authors
+# Copyright 2024 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.
@@ -15,6 +15,8 @@
# The aarch64 wheels are being crosscompiled to allow running the build
# on x64 machine. The dockcross/linux-armv7 image is a x86_64
# image with crosscompilation toolchain installed
+
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile.template`!!!
FROM dockcross/linux-armv7
RUN apt update && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
@@ -22,37 +24,39 @@ RUN apt update && apt install -y build-essential zlib1g-dev libncurses5-dev libg
ADD install_python_for_wheel_crosscompilation.sh /scripts/install_python_for_wheel_crosscompilation.sh
-RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.6.13" "3.6.13" /opt/python/cp36-cp36m
-RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.7.10" "3.7.10" /opt/python/cp37-cp37m
RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.8.8" "3.8.8" /opt/python/cp38-cp38
RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.9.2" "3.9.2" /opt/python/cp39-cp39
RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.10.0" "3.10.0rc1" /opt/python/cp310-cp310
RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.11.0" "3.11.0rc1" /opt/python/cp311-cp311
RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.12.0" "3.12.0rc2" /opt/python/cp312-cp312
+RUN /scripts/install_python_for_wheel_crosscompilation.sh "3.13.0" "3.13.0rc2" /opt/python/cp313-cp313
ENV AUDITWHEEL_ARCH armv7l
ENV AUDITWHEEL_PLAT linux_armv7l
#=================
-# Install ccache
+# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
-RUN unset CMAKE_TOOLCHAIN_FILE && unset AS AR CC CPP CXX LD \
- && curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+RUN unset CMAKE_TOOLCHAIN_FILE && unset AS AR CC CPP CXX LD STRIP OBJCOPY \
+ && curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
# The dockcross base of this image sets CC and CXX to absolute paths, which makes it impossible to redirect their invocations
# to ccache via a symlink. Use relative paths instead.
+
ENV CC ${CROSS_TRIPLE}-gcc
ENV CXX ${CROSS_TRIPLE}-g++
+
# For historical reasons, task_runner.py the script under docker container using "bash -l"
# which loads /etc/profile on startup. dockcross/linux-armv7 is based on an image where
# /etc/profile overwrites contents of PATH (for security reasons) when run as root.
@@ -62,5 +66,25 @@ ENV CXX ${CROSS_TRIPLE}-g++
# TODO(jtattermusch): Remove this hack when possible.
RUN echo "# file contents removed to avoid resetting PATH set by the docker image" >/etc/profile
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
RUN git config --global protocol.file.allow always
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
index 08c6439d36a..f1f1d39509e 100755
--- 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
@@ -44,4 +44,4 @@ popd
rm -rf "Python-${PYTHON_VERSION}"
# install cython and wheel
-"${PYTHON_PREFIX}/bin/python3" -m pip install --upgrade 'cython<3.0.0rc1' wheel
+"${PYTHON_PREFIX}/bin/python3" -m pip install --upgrade 'cython<4.0.0rc1' wheel
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version b/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version
index cdce8e543b4..cf67b251907 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_aarch64:cfc9fe0cb36bb4ec8425982fd7f07e4e14bf3941@sha256:3f0407d4db904b35a7665c2222db039994cd0c9bdb1a073a653ff8e6940081c9
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_aarch64:377f694f92dd1b56dff0b0a0f47d6e731200953c@sha256:ad3233be3c3ad9e0c4b60f0176a853713a35e5c84ec9d9703996c67fa3e811b6
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile
index 8e1c0751a8a..e4c3f8f306c 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2020 The gRPC Authors
+# Copyright 2024 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.
@@ -12,35 +12,57 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM dockcross/manylinux2014-aarch64:20230905-7b2d74f
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile.template`!!!
+
+FROM dockcross/manylinux2014-aarch64:20240812-60fa1b0
# manylinux_2_17 is the preferred alias of manylinux2014
ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
-###################################
+#===================================
# Install Python build requirements
-RUN /opt/python/cp36-cp36m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp37-cp37m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<3.0.0rc1'
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
#=================
-# Install ccache
+# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
RUN unset CMAKE_TOOLCHAIN_FILE && unset AS AR CC CPP CXX LD STRIP OBJCOPY \
- && curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+ && curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
RUN git config --global protocol.file.allow always
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version b/tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version
index c6f58ea8034..b99340a7285 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_x64.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x64:e81af0c6d454929785e8126fc993cbd93da5c014@sha256:89329900ec7fedc57cd89690acd34d07d726f6b896f60df987867737d0a0f5a8
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x64:379c3240e9fd68b7c13a3b6cb24307a272558494@sha256:0e102df67f31aeb6afe68250603288c2f1c98ccf360d1c42d751b8451da94b48
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
index ae959de2db4..ea75ed3af7c 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2020 The gRPC Authors
+# Copyright 2024 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.
@@ -14,7 +14,9 @@
# Docker file for building gRPC manylinux Python artifacts.
-FROM quay.io/pypa/manylinux2014_x86_64:2023-09-17-ae90a16
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile.template`!!!
+
+FROM quay.io/pypa/manylinux2014_x86_64:2024-09-09-f386546
# manylinux_2_17 is the preferred alias of manylinux2014
ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
@@ -22,29 +24,49 @@ ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
# TODO(jtattermusch): revisit which of the deps are really required
RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
-###################################
+#===================================
# Install Python build requirements
-RUN /opt/python/cp36-cp36m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp37-cp37m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<3.0.0rc1'
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
#=================
# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
-RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
RUN git config --global protocol.file.allow always
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version b/tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version
index efbb3c35dbe..67a5533afbd 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_x86.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x86:fda00560d600eed356f8d6bef2cc8416d0a6b790@sha256:8fce8e094b00935dc1f2640b4c2b10216c5a8711c0f4444efbafcd8c355a75a8
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_manylinux2014_x86:28eec3c9e027fd42f5852f696ed3e47aec91229b@sha256:527e2e9ec4db0c52a53b50abfd59907a1b7e221168dc401686f6a48d33bddc5c
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
index 7736403f098..3ffa2f46bbb 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2020 The gRPC Authors
+# Copyright 2024 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.
@@ -14,7 +14,9 @@
# Docker file for building gRPC manylinux Python artifacts.
-FROM quay.io/pypa/manylinux2014_i686:2023-09-17-ae90a16
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile.template`!!!
+
+FROM quay.io/pypa/manylinux2014_i686:2024-09-09-f386546
# manylinux_2_17 is the preferred alias of manylinux2014
ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
@@ -22,30 +24,50 @@ ENV AUDITWHEEL_PLAT manylinux_2_17_$AUDITWHEEL_ARCH
# TODO(jtattermusch): revisit which of the deps are really required
RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
-###################################
+#===================================
# Install Python build requirements
-RUN /opt/python/cp36-cp36m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp37-cp37m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<3.0.0rc1'
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
#=================
# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
-RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
RUN git config --global protocol.file.allow always
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version
index 5365ea4a4be..af23ed31a5c 100644
--- a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version
+++ b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x64:2f56fcee2e4964359dddcd57bb9b066ceb8331ec@sha256:c8e8eb24942a2910197cf5481d61e7cbce68b57bd6f35fae878b043b1f2c38bb
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x64:1bc8405880fdad2b22f8a6422cd6198b0b54838a@sha256:94b57e5ea31ebc29af734474bcaff3074770778e5d27557cdc06d755ee8bc7ed
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile
index a6eff9bbe71..dc16c9133b7 100644
--- a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2021 The gRPC Authors
+# Copyright 2024 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.
@@ -12,31 +12,55 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM quay.io/pypa/musllinux_1_1_x86_64:2023-09-17-ae90a16
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x64/Dockerfile.template`!!!
-###################################
+FROM quay.io/pypa/musllinux_1_1_x86_64:2024-09-09-f386546
+
+#===================================
# Install Python build requirements
-RUN /opt/python/cp36-cp36m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp37-cp37m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<3.0.0rc1'
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
#=================
# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
-RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
-RUN git config --global protocol.file.allow always
\ No newline at end of file
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
+RUN git config --global protocol.file.allow always
+
+RUN apk add openssl openssl-dev
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version
index c30b39b356a..ba2e0cac19a 100644
--- a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version
+++ b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x86:9308dccacd76fb1782a43d97e6f5062b5b58576d@sha256:c288f83435186ee675d004ee52c93195a51201bf2b5fe92581584d977a2499a3
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/grpc_artifact_python_musllinux_1_1_x86:358044420e0991fe284f49848145d5145cff42ac@sha256:edf4a0c8333c9309e52f323aa7315bbc0e5643216613cab4ecd2bce3d1ec26c0
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile
index c7ac549e98f..6509ab15003 100644
--- a/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2021 The gRPC Authors
+# Copyright 2024 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.
@@ -12,31 +12,53 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM quay.io/pypa/musllinux_1_1_i686:2023-09-17-ae90a16
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/dockerfile/grpc_artifact_python_musllinux_1_1_x86/Dockerfile.template`!!!
-###################################
+FROM quay.io/pypa/musllinux_1_1_i686:2024-09-09-f386546
+
+#===================================
# Install Python build requirements
-RUN /opt/python/cp36-cp36m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp37-cp37m/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<3.0.0rc1'
-RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<3.0.0rc1'
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp310-cp310/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp311-cp311/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp312-cp312/bin/pip install --upgrade 'cython<4.0.0rc1'
+RUN /opt/python/cp313-cp313/bin/pip install --upgrade 'cython<4.0.0rc1'
#=================
# Install ccache
# Install ccache from source since ccache 3.x packaged with most linux distributions
# does not support Redis backend for caching.
-RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \
+RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \
&& tar -zxf ccache.tar.gz \
- && cd ccache-4.5.1 \
+ && cd ccache-4.7.5 \
&& mkdir build && cd build \
&& cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \
&& make -j4 && make install \
&& cd ../.. \
- && rm -rf ccache-4.5.1 ccache.tar.gz
+ && rm -rf ccache-4.7.5 ccache.tar.gz
+
+# TODO: simplify the list of third_party modules list
+# NOTE: git>=2.46 allows leading paths like third_party/* to include all subdirectories
+# current docker base images use git versions lower than 2.46 and hence require separate configs for each submodule
RUN git config --global --add safe.directory /var/local/jenkins/grpc
-RUN git config --global protocol.file.allow always
\ No newline at end of file
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/bloaty
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/xds
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googleapis
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/googletest
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opencensus-proto
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/boringssl-with-bazel
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/envoy-api
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protobuf
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/zlib
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/benchmark
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/re2
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/abseil-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/opentelemetry-cpp
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/protoc-gen-validate
+RUN git config --global --add safe.directory /var/local/jenkins/grpc/.git/modules/third_party/cares/cares
+RUN git config --global protocol.file.allow always
diff --git a/tools/dockerfile/test/python_debian11_default_x64.current_version b/tools/dockerfile/test/python_debian11_default_x64.current_version
index 70b0383e90a..8b82524dba6 100644
--- a/tools/dockerfile/test/python_debian11_default_x64.current_version
+++ b/tools/dockerfile/test/python_debian11_default_x64.current_version
@@ -1 +1 @@
-us-docker.pkg.dev/grpc-testing/testing-images-public/python_debian11_default_x64:05951fbd0e77e8ba072d270ad08f0d4b6ac00841@sha256:4c539fc93d343324309939c2964204c90f4054cd9eeed093af315cb0f0ef7c26
\ No newline at end of file
+us-docker.pkg.dev/grpc-testing/testing-images-public/python_debian11_default_x64:224d8dc6c8287ee247378888ac93b9fe9e36ec8c@sha256:8beca964d6bbb80a8cb4c4628c25e9702b007c97113e74e589fa50c15000738d
\ No newline at end of file
diff --git a/tools/dockerfile/test/python_debian11_default_x64/Dockerfile b/tools/dockerfile/test/python_debian11_default_x64/Dockerfile
index 2ba17722bce..e7c2c9a658d 100644
--- a/tools/dockerfile/test/python_debian11_default_x64/Dockerfile
+++ b/tools/dockerfile/test/python_debian11_default_x64/Dockerfile
@@ -173,6 +173,28 @@ RUN cd /tmp && \
RUN python3.12 -m ensurepip && \
python3.12 -m pip install coverage
+#=================
+# Compile CPython 3.13.0rc2 from source
+
+RUN apt-get update && apt-get install -y zlib1g-dev libssl-dev libsqlite3-dev && apt-get clean
+RUN apt-get update && apt-get install -y jq build-essential libffi-dev && apt-get clean
+
+RUN cd /tmp && \
+ wget -q https://www.python.org/ftp/python/3.13.0/Python-3.13.0rc2.tgz && \
+ tar xzvf Python-3.13.0rc2.tgz && \
+ cd Python-3.13.0rc2 && \
+ ./configure && \
+ make -j4 && \
+ make install
+
+
+RUN cd /tmp && \
+ echo "ad7f44153649e27ec385e7633e853e03 Python-3.13.0rc2.tgz" > checksum.md5 && \
+ md5sum -c checksum.md5
+
+RUN python3.13 -m ensurepip && \
+ python3.13 -m pip install coverage
+
# Python test coverage requires libsqlite3, and it have
# to be installed before Python.
diff --git a/tools/internal_ci/helper_scripts/install_python_interpreters.ps1 b/tools/internal_ci/helper_scripts/install_python_interpreters.ps1
index 902fa3b0965..ddeaad711f8 100644
--- a/tools/internal_ci/helper_scripts/install_python_interpreters.ps1
+++ b/tools/internal_ci/helper_scripts/install_python_interpreters.ps1
@@ -149,3 +149,20 @@ $Python312x64Config = @{
PythonInstallerHash = "ea1993b5227fa4c8f45a06f5fbdd23b3"
}
Install-Python @Python312x64Config
+
+# Python 3.13
+$Python313x86Config = @{
+ PythonVersion = "3.13.0"
+ PythonInstaller = "python-3.13.0rc2"
+ PythonInstallPath = "C:\Python313_32bit"
+ PythonInstallerHash = "647f429b5584d9ee2dd02fdc9c61a38e"
+}
+Install-Python @Python313x86Config
+
+$Python313x64Config = @{
+ PythonVersion = "3.13.0"
+ PythonInstaller = "python-3.13.0rc2-amd64"
+ PythonInstallPath = "C:\Python313"
+ PythonInstallerHash = "0af5ad8734962267323ef45f384de3aa"
+}
+Install-Python @Python313x64Config
\ No newline at end of file
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index 8b3de1ab8ff..1cfd4cba7ce 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -176,6 +176,14 @@ then
shasum -c /tmp/python_installer_checksum.sha256
time sudo installer -pkg ./python-3.12.0rc2-macos11.pkg -target /
fi
+
+ # Install Python 3.13 if it doesn't exist
+ if [ ! -f "/usr/local/bin/python3.13" ]; then
+ time curl -O https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg
+ echo "75579065f9ee5c25207353fbe0f79275123ff556 python-3.13.0rc2-macos11.pkg" > /tmp/python_installer_checksum.sha256
+ shasum -c /tmp/python_installer_checksum.sha256
+ time sudo installer -pkg ./python-3.13.0rc2-macos11.pkg -target /
+ fi
fi
if [ "${PREPARE_BUILD_INSTALL_DEPS_CSHARP}" == "true" ]
diff --git a/tools/internal_ci/helper_scripts/requirements.macos.txt b/tools/internal_ci/helper_scripts/requirements.macos.txt
index 59a759b0ce2..57c4fb7abf5 100644
--- a/tools/internal_ci/helper_scripts/requirements.macos.txt
+++ b/tools/internal_ci/helper_scripts/requirements.macos.txt
@@ -1,4 +1,4 @@
-cython<3.0.0rc1
+cython<4.0.0rc1
cryptography==3.4.6
PyJWT==2.0.1
pyOpenSSL==20.0.1
diff --git a/tools/internal_ci/macos/grpc_distribtests_python.sh b/tools/internal_ci/macos/grpc_distribtests_python.sh
index 8bd18de2e1d..fa651af4e8a 100644
--- a/tools/internal_ci/macos/grpc_distribtests_python.sh
+++ b/tools/internal_ci/macos/grpc_distribtests_python.sh
@@ -26,12 +26,12 @@ source tools/internal_ci/helper_scripts/prepare_build_macos_rc
# TODO(jtattermusch): cleanup this prepare build step (needed for python artifact build)
# install cython for all python versions
-python3.7 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
-python3.8 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
-python3.9 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
-python3.10 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
-python3.11 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
-python3.12 -m pip install -U 'cython<3.0.0rc1' setuptools==65.4.1 wheel --user
+python3.8 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
+python3.9 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
+python3.10 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
+python3.11 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
+python3.12 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
+python3.13 -m pip install -U 'cython<4.0.0rc1' setuptools==65.4.1 wheel --user
# Build all python macos artifacts (this step actually builds all the binary wheels and source archives)
tools/run_tests/task_runner.py -f artifact macos python ${TASK_RUNNER_EXTRA_FILTERS} -j 2 -x build_artifacts/sponge_log.xml || FAILED="true"
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index 3146af9266a..6f00c17fa03 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -165,6 +165,7 @@ class PythonArtifact:
elif "manylinux" in self.platform:
if self.arch == "x86":
environ["SETARCH_CMD"] = "linux32"
+ environ["GRPC_SKIP_TWINE_CHECK"] = "TRUE"
# Inside the manylinux container, the python installations are located in
# special places...
environ["PYTHON"] = "/opt/python/{}/bin/python".format(
@@ -201,6 +202,10 @@ class PythonArtifact:
environ["GRPC_SKIP_PIP_CYTHON_UPGRADE"] = "TRUE"
environ["GRPC_RUN_AUDITWHEEL_REPAIR"] = "TRUE"
environ["GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX"] = "TRUE"
+
+ if self.arch == "x86":
+ environ["GRPC_SKIP_TWINE_CHECK"] = "TRUE"
+
return create_docker_jobspec(
self.name,
"tools/dockerfile/grpc_artifact_python_%s_%s"
@@ -401,15 +406,17 @@ def targets():
PythonArtifact("manylinux2014", "x64", "cp39-cp39", presubmit=True),
PythonArtifact("manylinux2014", "x64", "cp310-cp310"),
PythonArtifact("manylinux2014", "x64", "cp311-cp311"),
+ PythonArtifact("manylinux2014", "x64", "cp312-cp312"),
PythonArtifact(
- "manylinux2014", "x64", "cp312-cp312", presubmit=True
+ "manylinux2014", "x64", "cp313-cp313", presubmit=True
),
PythonArtifact("manylinux2014", "x86", "cp38-cp38", presubmit=True),
PythonArtifact("manylinux2014", "x86", "cp39-cp39", presubmit=True),
PythonArtifact("manylinux2014", "x86", "cp310-cp310"),
PythonArtifact("manylinux2014", "x86", "cp311-cp311"),
+ PythonArtifact("manylinux2014", "x86", "cp312-cp312"),
PythonArtifact(
- "manylinux2014", "x86", "cp312-cp312", presubmit=True
+ "manylinux2014", "x86", "cp313-cp313", presubmit=True
),
PythonArtifact(
"manylinux2014", "aarch64", "cp38-cp38", presubmit=True
@@ -417,45 +424,52 @@ def targets():
PythonArtifact("manylinux2014", "aarch64", "cp39-cp39"),
PythonArtifact("manylinux2014", "aarch64", "cp310-cp310"),
PythonArtifact("manylinux2014", "aarch64", "cp311-cp311"),
+ PythonArtifact("manylinux2014", "aarch64", "cp312-cp312"),
PythonArtifact(
- "manylinux2014", "aarch64", "cp312-cp312", presubmit=True
+ "manylinux2014", "aarch64", "cp313-cp313", presubmit=True
),
PythonArtifact("linux_extra", "armv7", "cp38-cp38", presubmit=True),
PythonArtifact("linux_extra", "armv7", "cp39-cp39"),
PythonArtifact("linux_extra", "armv7", "cp310-cp310"),
PythonArtifact("linux_extra", "armv7", "cp311-cp311"),
+ PythonArtifact("linux_extra", "armv7", "cp312-cp312"),
PythonArtifact(
- "linux_extra", "armv7", "cp312-cp312", presubmit=True
+ "linux_extra", "armv7", "cp313-cp313", presubmit=True
),
PythonArtifact("musllinux_1_1", "x64", "cp38-cp38", presubmit=True),
PythonArtifact("musllinux_1_1", "x64", "cp39-cp39"),
PythonArtifact("musllinux_1_1", "x64", "cp310-cp310"),
PythonArtifact("musllinux_1_1", "x64", "cp311-cp311"),
+ PythonArtifact("musllinux_1_1", "x64", "cp312-cp312"),
PythonArtifact(
- "musllinux_1_1", "x64", "cp312-cp312", presubmit=True
+ "musllinux_1_1", "x64", "cp313-cp313", presubmit=True
),
PythonArtifact("musllinux_1_1", "x86", "cp38-cp38", presubmit=True),
PythonArtifact("musllinux_1_1", "x86", "cp39-cp39"),
PythonArtifact("musllinux_1_1", "x86", "cp310-cp310"),
PythonArtifact("musllinux_1_1", "x86", "cp311-cp311"),
+ PythonArtifact("musllinux_1_1", "x86", "cp312-cp312"),
PythonArtifact(
- "musllinux_1_1", "x86", "cp312-cp312", presubmit=True
+ "musllinux_1_1", "x86", "cp313-cp313", presubmit=True
),
PythonArtifact("macos", "x64", "python3.8", presubmit=True),
PythonArtifact("macos", "x64", "python3.9"),
PythonArtifact("macos", "x64", "python3.10"),
PythonArtifact("macos", "x64", "python3.11"),
- PythonArtifact("macos", "x64", "python3.12", presubmit=True),
+ PythonArtifact("macos", "x64", "python3.12"),
+ PythonArtifact("macos", "x64", "python3.13", presubmit=True),
PythonArtifact("windows", "x86", "Python38_32bit", presubmit=True),
PythonArtifact("windows", "x86", "Python39_32bit"),
PythonArtifact("windows", "x86", "Python310_32bit"),
PythonArtifact("windows", "x86", "Python311_32bit"),
- PythonArtifact("windows", "x86", "Python312_32bit", presubmit=True),
+ PythonArtifact("windows", "x86", "Python312_32bit"),
+ PythonArtifact("windows", "x86", "Python313_32bit", presubmit=True),
PythonArtifact("windows", "x64", "Python38", presubmit=True),
PythonArtifact("windows", "x64", "Python39"),
PythonArtifact("windows", "x64", "Python310"),
PythonArtifact("windows", "x64", "Python311"),
- PythonArtifact("windows", "x64", "Python312", presubmit=True),
+ PythonArtifact("windows", "x64", "Python312"),
+ PythonArtifact("windows", "x64", "Python313", presubmit=True),
RubyArtifact("linux", "x86-mingw32", presubmit=True),
RubyArtifact("linux", "x64-mingw32", presubmit=True),
RubyArtifact("linux", "x64-mingw-ucrt", presubmit=True),
diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
index ee17381bc1b..4ac49183af4 100644
--- a/tools/run_tests/artifacts/build_artifact_python.bat
+++ b/tools/run_tests/artifacts/build_artifact_python.bat
@@ -56,7 +56,7 @@ python setup.py bdist_wheel || goto :error
popd
@rem Ensure the generate artifacts are valid.
-python -m pip install packaging==21.3 twine==3.8.0
+python -m pip install packaging==21.3 twine==5.0.0
python -m twine check dist\* tools\distrib\python\grpcio_tools\dist\* || goto :error
xcopy /Y /I /S dist\* %ARTIFACT_DIR% || goto :error
diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
index 1598d2edc18..b00ae1e372c 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -39,7 +39,7 @@ then
# Any installation step is a potential source of breakages,
# so we are trying to perform as few download-and-install operations
# as possible.
- "${PYTHON}" -m pip install --upgrade 'cython<3.0.0rc1'
+ "${PYTHON}" -m pip install --upgrade 'cython<4.0.0rc1'
fi
# Allow build_ext to build C/C++ files in parallel
@@ -167,7 +167,8 @@ then
"${PYTHON}" -m pip install virtualenv
"${PYTHON}" -m virtualenv venv || { "${PYTHON}" -m pip install virtualenv==20.0.23 && "${PYTHON}" -m virtualenv venv; }
# Ensure the generated artifacts are valid using "twine check"
- venv/bin/python -m pip install "twine<=2.0" "readme_renderer<40.0"
+ # pinning twine's dependency package `cryptography` version to 3.3.2 (last version without Rust dependency)
+ venv/bin/python -m pip install "cryptography==3.3.2" "twine==5.0.0" "readme_renderer<40.0"
venv/bin/python -m twine check dist/* tools/distrib/python/grpcio_tools/dist/*
if [ "$GRPC_BUILD_MAC" == "" ]; then
venv/bin/python -m twine check src/python/grpcio_observability/dist/*
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 16f05533882..90073bb8e2c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -844,6 +844,13 @@ class PythonLanguage(object):
bits=bits,
config_vars=config_vars,
)
+ python313_config = _python_config_generator(
+ name="py313",
+ major="3",
+ minor="13",
+ bits=bits,
+ config_vars=config_vars,
+ )
pypy27_config = _pypy_config_generator(
name="pypy", major="2", config_vars=config_vars
)
@@ -880,6 +887,8 @@ class PythonLanguage(object):
return (python311_config,)
elif args.compiler == "python3.12":
return (python312_config,)
+ elif args.compiler == "python3.13":
+ return (python313_config,)
elif args.compiler == "pypy":
return (pypy27_config,)
elif args.compiler == "pypy3":
@@ -893,6 +902,7 @@ class PythonLanguage(object):
python310_config,
python311_config,
python312_config,
+ python313_config,
)
else:
raise Exception("Compiler %s not supported." % args.compiler)
From f6f13ccaec188339a69d96b91186c15b217d3e0c Mon Sep 17 00:00:00 2001
From: Tanvi Jagtap <139093547+tanvi-jagtap@users.noreply.github.com>
Date: Thu, 26 Sep 2024 10:37:01 -0700
Subject: [PATCH 02/74] [PH2][Refactor][internal.h] Split file. Add
stream_lists.h (#37775)
Moving out related code into a separate file.
`internal.h -> stream_lists.h`
Closes #37775
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37775 from tanvi-jagtap:ph2_stream_lists_h 13b6030cebcf00abecf1f010e21773490c6d08d2
PiperOrigin-RevId: 679205824
---
BUILD | 1 +
Package.swift | 1 +
build_autogenerated.yaml | 2 +
gRPC-C++.podspec | 2 +
gRPC-Core.podspec | 2 +
grpc.gemspec | 1 +
package.xml | 1 +
.../chttp2/transport/chttp2_transport.cc | 1 +
.../chttp2/transport/frame_window_update.cc | 1 +
.../ext/transport/chttp2/transport/internal.h | 41 ------------
.../chttp2/transport/stream_lists.cc | 2 +
.../transport/chttp2/transport/stream_lists.h | 65 +++++++++++++++++++
.../ext/transport/chttp2/transport/writing.cc | 1 +
tools/doxygen/Doxyfile.c++.internal | 1 +
tools/doxygen/Doxyfile.core.internal | 1 +
15 files changed, 82 insertions(+), 41 deletions(-)
create mode 100644 src/core/ext/transport/chttp2/transport/stream_lists.h
diff --git a/BUILD b/BUILD
index 093cddb95af..36c3c47497f 100644
--- a/BUILD
+++ b/BUILD
@@ -4779,6 +4779,7 @@ grpc_cc_library(
"//src/core:ext/transport/chttp2/transport/frame_settings.h",
"//src/core:ext/transport/chttp2/transport/frame_window_update.h",
"//src/core:ext/transport/chttp2/transport/internal.h",
+ "//src/core:ext/transport/chttp2/transport/stream_lists.h",
],
external_deps = [
"absl/base:core_headers",
diff --git a/Package.swift b/Package.swift
index d9411aed0ec..988f1e7abe7 100644
--- a/Package.swift
+++ b/Package.swift
@@ -256,6 +256,7 @@ let package = Package(
"src/core/ext/transport/chttp2/transport/ping_rate_policy.cc",
"src/core/ext/transport/chttp2/transport/ping_rate_policy.h",
"src/core/ext/transport/chttp2/transport/stream_lists.cc",
+ "src/core/ext/transport/chttp2/transport/stream_lists.h",
"src/core/ext/transport/chttp2/transport/varint.cc",
"src/core/ext/transport/chttp2/transport/varint.h",
"src/core/ext/transport/chttp2/transport/write_size_policy.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index bc395b7e0e4..e7c5b7684c3 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -291,6 +291,7 @@ libs:
- src/core/ext/transport/chttp2/transport/ping_abuse_policy.h
- src/core/ext/transport/chttp2/transport/ping_callbacks.h
- src/core/ext/transport/chttp2/transport/ping_rate_policy.h
+ - src/core/ext/transport/chttp2/transport/stream_lists.h
- src/core/ext/transport/chttp2/transport/varint.h
- src/core/ext/transport/chttp2/transport/write_size_policy.h
- src/core/ext/transport/inproc/inproc_transport.h
@@ -2313,6 +2314,7 @@ libs:
- src/core/ext/transport/chttp2/transport/ping_abuse_policy.h
- src/core/ext/transport/chttp2/transport/ping_callbacks.h
- src/core/ext/transport/chttp2/transport/ping_rate_policy.h
+ - src/core/ext/transport/chttp2/transport/stream_lists.h
- src/core/ext/transport/chttp2/transport/varint.h
- src/core/ext/transport/chttp2/transport/write_size_policy.h
- src/core/ext/transport/inproc/inproc_transport.h
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 4862b8ee10e..9d37c6cbe39 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -380,6 +380,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
'src/core/ext/transport/chttp2/transport/ping_rate_policy.h',
+ 'src/core/ext/transport/chttp2/transport/stream_lists.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/transport/write_size_policy.h',
'src/core/ext/transport/inproc/inproc_transport.h',
@@ -1681,6 +1682,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
'src/core/ext/transport/chttp2/transport/ping_rate_policy.h',
+ 'src/core/ext/transport/chttp2/transport/stream_lists.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/transport/write_size_policy.h',
'src/core/ext/transport/inproc/inproc_transport.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index f953ca34e73..15080faf737 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -376,6 +376,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/ping_rate_policy.cc',
'src/core/ext/transport/chttp2/transport/ping_rate_policy.h',
'src/core/ext/transport/chttp2/transport/stream_lists.cc',
+ 'src/core/ext/transport/chttp2/transport/stream_lists.h',
'src/core/ext/transport/chttp2/transport/varint.cc',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/transport/write_size_policy.cc',
@@ -2467,6 +2468,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
'src/core/ext/transport/chttp2/transport/ping_rate_policy.h',
+ 'src/core/ext/transport/chttp2/transport/stream_lists.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/transport/write_size_policy.h',
'src/core/ext/transport/inproc/inproc_transport.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 83b134b50fe..f7829369b0e 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -262,6 +262,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/ping_rate_policy.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/ping_rate_policy.h )
s.files += %w( src/core/ext/transport/chttp2/transport/stream_lists.cc )
+ s.files += %w( src/core/ext/transport/chttp2/transport/stream_lists.h )
s.files += %w( src/core/ext/transport/chttp2/transport/varint.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
s.files += %w( src/core/ext/transport/chttp2/transport/write_size_policy.cc )
diff --git a/package.xml b/package.xml
index 67c1e56e75a..4bd5a7a2f8c 100644
--- a/package.xml
+++ b/package.xml
@@ -244,6 +244,7 @@
+
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 02fffbf41ca..fef7fb92d0b 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -68,6 +68,7 @@
#include "src/core/ext/transport/chttp2/transport/ping_abuse_policy.h"
#include "src/core/ext/transport/chttp2/transport/ping_callbacks.h"
#include "src/core/ext/transport/chttp2/transport/ping_rate_policy.h"
+#include "src/core/ext/transport/chttp2/transport/stream_lists.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
#include "src/core/ext/transport/chttp2/transport/write_size_policy.h"
#include "src/core/lib/channel/channel_args.h"
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.cc b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
index 6dafd5318b2..20cddebd5ca 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
@@ -29,6 +29,7 @@
#include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/ext/transport/chttp2/transport/stream_lists.h"
grpc_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_delta,
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 80e214ca1f2..bdbbd6890c7 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -769,47 +769,6 @@ absl::variant grpc_chttp2_perform_read(
grpc_chttp2_transport* t, const grpc_slice& slice,
size_t& requests_started);
-bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-/// Get a writable stream
-/// returns non-zero if there was a stream available
-bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-bool grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-
-bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport* t);
-bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-
-void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-bool grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-
-void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-
-void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-
-void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream** s);
-bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s);
-
//******** Flow Control **************
// Takes in a flow control action and performs all the needed operations.
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.cc b/src/core/ext/transport/chttp2/transport/stream_lists.cc
index f4ee3e58eb8..14039a614b7 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.cc
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.cc
@@ -16,6 +16,8 @@
//
//
+#include "src/core/ext/transport/chttp2/transport/stream_lists.h"
+
#include "absl/log/check.h"
#include "absl/log/log.h"
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.h b/src/core/ext/transport/chttp2/transport/stream_lists.h
new file mode 100644
index 00000000000..f415fe73704
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.h
@@ -0,0 +1,65 @@
+//
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_LISTS_H
+#define GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_LISTS_H
+
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+/// Get a writable stream
+/// returns non-zero if there was a stream available
+bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+bool grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+
+bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport* t);
+bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+
+void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+bool grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+
+void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+
+void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+
+void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream** s);
+bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport* t,
+ grpc_chttp2_stream* s);
+
+#endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_LISTS_H
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 13797c1f1b5..d5678956f51 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -51,6 +51,7 @@
#include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
#include "src/core/ext/transport/chttp2/transport/ping_callbacks.h"
#include "src/core/ext/transport/chttp2/transport/ping_rate_policy.h"
+#include "src/core/ext/transport/chttp2/transport/stream_lists.h"
#include "src/core/ext/transport/chttp2/transport/write_size_policy.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/experiments/experiments.h"
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 3688a568841..994e038c983 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1267,6 +1267,7 @@ src/core/ext/transport/chttp2/transport/ping_callbacks.h \
src/core/ext/transport/chttp2/transport/ping_rate_policy.cc \
src/core/ext/transport/chttp2/transport/ping_rate_policy.h \
src/core/ext/transport/chttp2/transport/stream_lists.cc \
+src/core/ext/transport/chttp2/transport/stream_lists.h \
src/core/ext/transport/chttp2/transport/varint.cc \
src/core/ext/transport/chttp2/transport/varint.h \
src/core/ext/transport/chttp2/transport/write_size_policy.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 9b118d61fd8..3725bd86978 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1034,6 +1034,7 @@ src/core/ext/transport/chttp2/transport/ping_callbacks.h \
src/core/ext/transport/chttp2/transport/ping_rate_policy.cc \
src/core/ext/transport/chttp2/transport/ping_rate_policy.h \
src/core/ext/transport/chttp2/transport/stream_lists.cc \
+src/core/ext/transport/chttp2/transport/stream_lists.h \
src/core/ext/transport/chttp2/transport/varint.cc \
src/core/ext/transport/chttp2/transport/varint.h \
src/core/ext/transport/chttp2/transport/write_size_policy.cc \
From 2030231e3227c1c5b6b11ae1013a2374e6be6b7d Mon Sep 17 00:00:00 2001
From: Craig Tiller
Date: Thu, 26 Sep 2024 12:06:32 -0700
Subject: [PATCH 03/74] [gcc7] Build fix (#37796)
Closes #37796
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37796 from ctiller:buildy 363eca118abf339899a8114019027d579747385e
PiperOrigin-RevId: 679243010
---
src/core/call/request_buffer.cc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/core/call/request_buffer.cc b/src/core/call/request_buffer.cc
index 257743cbb90..ee0878603c0 100644
--- a/src/core/call/request_buffer.cc
+++ b/src/core/call/request_buffer.cc
@@ -117,7 +117,7 @@ RequestBuffer::Reader::PollPullClientInitialMetadata() {
pulled_client_initial_metadata_ = true;
auto result = ClaimObject(buffering->initial_metadata);
buffer_->MaybeSwitchToStreaming();
- return result;
+ return std::move(result);
}
if (auto* buffered = absl::get_if(&buffer_->state_)) {
pulled_client_initial_metadata_ = true;
@@ -142,7 +142,7 @@ RequestBuffer::Reader::PollPullMessage() {
auto result = ClaimObject(buffering->messages[idx]);
++message_index_;
buffer_->MaybeSwitchToStreaming();
- return result;
+ return std::move(result);
}
if (auto* buffered = absl::get_if(&buffer_->state_)) {
if (message_index_ == buffered->messages.size()) return absl::nullopt;
@@ -159,7 +159,7 @@ RequestBuffer::Reader::PollPullMessage() {
auto waker = std::move(buffer_->push_waker_);
lock.Release();
waker.Wakeup();
- return msg;
+ return std::move(msg);
}
error_ = absl::get(buffer_->state_).error;
return Failure{};
From 992b3aea8aaaa1285ed74f0ff3e3843765d1e197 Mon Sep 17 00:00:00 2001
From: Sourabh Singh
Date: Fri, 27 Sep 2024 08:41:13 -0700
Subject: [PATCH 04/74] remove logging_threshold tests (#37806)
Closes #37806
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37806 from sourabhsinghs:unittest/logging-threshold d501d38dc0c487fe2019fd4b0db6b61d831df45f
PiperOrigin-RevId: 679604228
---
bazel/internal_python_rules.bzl | 3 ---
1 file changed, 3 deletions(-)
diff --git a/bazel/internal_python_rules.bzl b/bazel/internal_python_rules.bzl
index a6c4e18ef81..b2a506c6ae4 100644
--- a/bazel/internal_python_rules.bzl
+++ b/bazel/internal_python_rules.bzl
@@ -14,7 +14,6 @@
"""Python-related rules intended only for use internal to the repo."""
load("//bazel:gevent_test.bzl", "py_grpc_gevent_test")
-load("//bazel:logging_threshold_test.bzl", "py_grpc_logging_threshold_test")
def internal_py_grpc_test(name, **kwargs):
"""Runs a test under all supported environments.
@@ -29,7 +28,6 @@ def internal_py_grpc_test(name, **kwargs):
**kwargs
)
py_grpc_gevent_test(name, **kwargs)
- py_grpc_logging_threshold_test(name, **kwargs)
suite_kwargs = {}
if "visibility" in kwargs:
@@ -40,7 +38,6 @@ def internal_py_grpc_test(name, **kwargs):
tests = [
name + ".native",
name + ".gevent",
- name + ".logging_threshold",
],
**suite_kwargs
)
From f2e3636303a66408cc67b61e8660cc51e9c1fbb3 Mon Sep 17 00:00:00 2001
From: Sreenithi Sridharan <19sreenithi98@gmail.com>
Date: Fri, 27 Sep 2024 08:53:41 -0700
Subject: [PATCH 05/74] increased timeout for armv7 artifact build to 2 hours
(#37807)
Building armv7 artifacts after adding Python 3.13 is failing with a timeout. Hence increasing timeout to 2 hours.
Closes #37807
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37807 from sreenithi:increase_armv7_artifact_build_timeout 60034378f585e7a7af5de8879fe32a04c9a3ccaa
PiperOrigin-RevId: 679608393
---
tools/run_tests/artifacts/artifact_targets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index 6f00c17fa03..2695500eae8 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -160,7 +160,7 @@ class PythonArtifact:
),
"tools/run_tests/artifacts/build_artifact_python.sh",
environ=environ,
- timeout_seconds=60 * 60,
+ timeout_seconds=60 * 60 * 2,
)
elif "manylinux" in self.platform:
if self.arch == "x86":
From 6ba3b4a71764c4a837cbfff3072b60d5e8d32f76 Mon Sep 17 00:00:00 2001
From: "Mark D. Roth"
Date: Fri, 27 Sep 2024 10:39:05 -0700
Subject: [PATCH 06/74] [xDS] ORCA to LRS propagation changes (#37467)
Implements gRFC A85 (https://github.com/grpc/proposal/pull/454).
Closes #37467
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37467 from markdroth:orca_lrs_propagation_changes 0c1e889bb70b422899bda04166524c678d628c70
PiperOrigin-RevId: 679646192
---
BUILD | 2 +
CMakeLists.txt | 1 +
Makefile | 1 +
Package.swift | 2 +
build_autogenerated.yaml | 2 +
config.m4 | 1 +
config.w32 | 1 +
gRPC-C++.podspec | 2 +
gRPC-Core.podspec | 3 +
grpc.gemspec | 2 +
package.xml | 2 +
src/core/BUILD | 24 ++
.../load_balancing/xds/xds_cluster_impl.cc | 13 +-
src/core/xds/grpc/xds_cluster.cc | 5 +
src/core/xds/grpc/xds_cluster.h | 15 +
src/core/xds/grpc/xds_cluster_parser.cc | 27 ++
src/core/xds/xds_client/lrs_client.cc | 145 ++++++--
src/core/xds/xds_client/lrs_client.h | 63 +++-
.../xds_backend_metric_propagation.cc | 64 ++++
.../xds_backend_metric_propagation.h | 60 ++++
src/proto/grpc/testing/xds/v3/cluster.proto | 15 +
.../grpc/testing/xds/v3/load_report.proto | 25 +-
src/python/grpcio/grpc_core_dependencies.py | 1 +
.../xds/xds_cluster_resource_type_test.cc | 88 ++++-
.../end2end/xds/xds_cluster_end2end_test.cc | 319 ++++++++++++++++++
test/cpp/end2end/xds/xds_end2end_test_lib.h | 12 +
test/cpp/end2end/xds/xds_server.h | 30 +-
tools/doxygen/Doxyfile.c++.internal | 2 +
tools/doxygen/Doxyfile.core.internal | 2 +
29 files changed, 872 insertions(+), 57 deletions(-)
create mode 100644 src/core/xds/xds_client/xds_backend_metric_propagation.cc
create mode 100644 src/core/xds/xds_client/xds_backend_metric_propagation.h
diff --git a/BUILD b/BUILD
index 36c3c47497f..17b278b61e6 100644
--- a/BUILD
+++ b/BUILD
@@ -4462,6 +4462,7 @@ grpc_cc_library(
"//src/core:default_event_engine",
"//src/core:dual_ref_counted",
"//src/core:env",
+ "//src/core:grpc_backend_metric_data",
"//src/core:json",
"//src/core:per_cpu",
"//src/core:ref_counted",
@@ -4469,6 +4470,7 @@ grpc_cc_library(
"//src/core:time",
"//src/core:upb_utils",
"//src/core:useful",
+ "//src/core:xds_backend_metric_propagation",
],
)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 14bceea8d0b..3836f7beac9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2665,6 +2665,7 @@ add_library(grpc
src/core/xds/grpc/xds_transport_grpc.cc
src/core/xds/xds_client/lrs_client.cc
src/core/xds/xds_client/xds_api.cc
+ src/core/xds/xds_client/xds_backend_metric_propagation.cc
src/core/xds/xds_client/xds_bootstrap.cc
src/core/xds/xds_client/xds_client.cc
)
diff --git a/Makefile b/Makefile
index 08ae5d181c1..70828125ba2 100644
--- a/Makefile
+++ b/Makefile
@@ -1517,6 +1517,7 @@ LIBGRPC_SRC = \
src/core/xds/grpc/xds_transport_grpc.cc \
src/core/xds/xds_client/lrs_client.cc \
src/core/xds/xds_client/xds_api.cc \
+ src/core/xds/xds_client/xds_backend_metric_propagation.cc \
src/core/xds/xds_client/xds_bootstrap.cc \
src/core/xds/xds_client/xds_client.cc \
third_party/abseil-cpp/absl/base/internal/cycleclock.cc \
diff --git a/Package.swift b/Package.swift
index 988f1e7abe7..8b1ae1392cc 100644
--- a/Package.swift
+++ b/Package.swift
@@ -2036,6 +2036,8 @@ let package = Package(
"src/core/xds/xds_client/lrs_client.h",
"src/core/xds/xds_client/xds_api.cc",
"src/core/xds/xds_client/xds_api.h",
+ "src/core/xds/xds_client/xds_backend_metric_propagation.cc",
+ "src/core/xds/xds_client/xds_backend_metric_propagation.h",
"src/core/xds/xds_client/xds_bootstrap.cc",
"src/core/xds/xds_client/xds_bootstrap.h",
"src/core/xds/xds_client/xds_channel_args.h",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index e7c5b7684c3..33b9da00c33 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1259,6 +1259,7 @@ libs:
- src/core/xds/grpc/xds_transport_grpc.h
- src/core/xds/xds_client/lrs_client.h
- src/core/xds/xds_client/xds_api.h
+ - src/core/xds/xds_client/xds_backend_metric_propagation.h
- src/core/xds/xds_client/xds_bootstrap.h
- src/core/xds/xds_client/xds_channel_args.h
- src/core/xds/xds_client/xds_client.h
@@ -2080,6 +2081,7 @@ libs:
- src/core/xds/grpc/xds_transport_grpc.cc
- src/core/xds/xds_client/lrs_client.cc
- src/core/xds/xds_client/xds_api.cc
+ - src/core/xds/xds_client/xds_backend_metric_propagation.cc
- src/core/xds/xds_client/xds_bootstrap.cc
- src/core/xds/xds_client/xds_client.cc
deps:
diff --git a/config.m4 b/config.m4
index 6a870a7d474..a5d57181f70 100644
--- a/config.m4
+++ b/config.m4
@@ -892,6 +892,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/xds/grpc/xds_transport_grpc.cc \
src/core/xds/xds_client/lrs_client.cc \
src/core/xds/xds_client/xds_api.cc \
+ src/core/xds/xds_client/xds_backend_metric_propagation.cc \
src/core/xds/xds_client/xds_bootstrap.cc \
src/core/xds/xds_client/xds_client.cc \
src/php/ext/grpc/byte_buffer.c \
diff --git a/config.w32 b/config.w32
index 05a181a2cb1..c0acf9bfb23 100644
--- a/config.w32
+++ b/config.w32
@@ -857,6 +857,7 @@ if (PHP_GRPC != "no") {
"src\\core\\xds\\grpc\\xds_transport_grpc.cc " +
"src\\core\\xds\\xds_client\\lrs_client.cc " +
"src\\core\\xds\\xds_client\\xds_api.cc " +
+ "src\\core\\xds\\xds_client\\xds_backend_metric_propagation.cc " +
"src\\core\\xds\\xds_client\\xds_bootstrap.cc " +
"src\\core\\xds\\xds_client\\xds_client.cc " +
"src\\php\\ext\\grpc\\byte_buffer.c " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 9d37c6cbe39..481f51c2ea4 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -1373,6 +1373,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/lrs_client.h',
'src/core/xds/xds_client/xds_api.h',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.h',
'src/core/xds/xds_client/xds_bootstrap.h',
'src/core/xds/xds_client/xds_channel_args.h',
'src/core/xds/xds_client/xds_client.h',
@@ -2675,6 +2676,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/lrs_client.h',
'src/core/xds/xds_client/xds_api.h',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.h',
'src/core/xds/xds_client/xds_bootstrap.h',
'src/core/xds/xds_client/xds_channel_args.h',
'src/core/xds/xds_client/xds_client.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 15080faf737..2867cb57323 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -2152,6 +2152,8 @@ Pod::Spec.new do |s|
'src/core/xds/xds_client/lrs_client.h',
'src/core/xds/xds_client/xds_api.cc',
'src/core/xds/xds_client/xds_api.h',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.cc',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.h',
'src/core/xds/xds_client/xds_bootstrap.cc',
'src/core/xds/xds_client/xds_bootstrap.h',
'src/core/xds/xds_client/xds_channel_args.h',
@@ -3460,6 +3462,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_transport_grpc.h',
'src/core/xds/xds_client/lrs_client.h',
'src/core/xds/xds_client/xds_api.h',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.h',
'src/core/xds/xds_client/xds_bootstrap.h',
'src/core/xds/xds_client/xds_channel_args.h',
'src/core/xds/xds_client/xds_client.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index f7829369b0e..bd39eda2bda 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -2038,6 +2038,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/xds/xds_client/lrs_client.h )
s.files += %w( src/core/xds/xds_client/xds_api.cc )
s.files += %w( src/core/xds/xds_client/xds_api.h )
+ s.files += %w( src/core/xds/xds_client/xds_backend_metric_propagation.cc )
+ s.files += %w( src/core/xds/xds_client/xds_backend_metric_propagation.h )
s.files += %w( src/core/xds/xds_client/xds_bootstrap.cc )
s.files += %w( src/core/xds/xds_client/xds_bootstrap.h )
s.files += %w( src/core/xds/xds_client/xds_channel_args.h )
diff --git a/package.xml b/package.xml
index 4bd5a7a2f8c..befa4e97aa3 100644
--- a/package.xml
+++ b/package.xml
@@ -2020,6 +2020,8 @@
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index dccdf45962d..13091d6bd38 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -5619,6 +5619,7 @@ grpc_cc_library(
"json_writer",
"match",
"time",
+ "xds_backend_metric_propagation",
"xds_common_types",
"xds_health_status",
"xds_metadata",
@@ -5651,6 +5652,28 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "xds_backend_metric_propagation",
+ srcs = [
+ "xds/xds_client/xds_backend_metric_propagation.cc",
+ ],
+ hdrs = [
+ "xds/xds_client/xds_backend_metric_propagation.h",
+ ],
+ external_deps = [
+ "absl/container:flat_hash_set",
+ "absl/strings",
+ ],
+ language = "c++",
+ tags = ["nofixdeps"],
+ visibility = ["@grpc:xds_client_core"],
+ deps = [
+ "ref_counted",
+ "useful",
+ "//:ref_counted_ptr",
+ ],
+)
+
# TODO(roth): Split this up into individual targets.
grpc_cc_library(
name = "grpc_xds_client",
@@ -5827,6 +5850,7 @@ grpc_cc_library(
"upb_utils",
"useful",
"validation_errors",
+ "xds_backend_metric_propagation",
"xds_certificate_provider",
"xds_certificate_provider_store",
"xds_cluster",
diff --git a/src/core/load_balancing/xds/xds_cluster_impl.cc b/src/core/load_balancing/xds/xds_cluster_impl.cc
index eb1a4b3259a..380ed7b108a 100644
--- a/src/core/load_balancing/xds/xds_cluster_impl.cc
+++ b/src/core/load_balancing/xds/xds_cluster_impl.cc
@@ -362,13 +362,9 @@ class XdsClusterImplLb::Picker::SubchannelCallTracker final
}
// Record call completion for load reporting.
if (locality_stats_ != nullptr) {
- auto* backend_metric_data =
- args.backend_metric_accessor->GetBackendMetricData();
- const std::map* named_metrics = nullptr;
- if (backend_metric_data != nullptr) {
- named_metrics = &backend_metric_data->named_metrics;
- }
- locality_stats_->AddCallFinished(named_metrics, !args.status.ok());
+ locality_stats_->AddCallFinished(
+ args.backend_metric_accessor->GetBackendMetricData(),
+ !args.status.ok());
}
// Decrement number of calls in flight.
call_counter_->Decrement();
@@ -826,7 +822,8 @@ RefCountedPtr XdsClusterImplLb::Helper::CreateSubchannel(
parent()->xds_client_->lrs_client().AddClusterLocalityStats(
parent()->cluster_resource_->lrs_load_reporting_server,
parent()->config_->cluster_name(),
- GetEdsResourceName(*parent()->cluster_resource_), locality_name);
+ GetEdsResourceName(*parent()->cluster_resource_), locality_name,
+ parent()->cluster_resource_->lrs_backend_metric_propagation);
if (locality_stats == nullptr) {
LOG(ERROR)
<< "[xds_cluster_impl_lb " << parent()
diff --git a/src/core/xds/grpc/xds_cluster.cc b/src/core/xds/grpc/xds_cluster.cc
index 2d4c2834ff0..09a7454d80f 100644
--- a/src/core/xds/grpc/xds_cluster.cc
+++ b/src/core/xds/grpc/xds_cluster.cc
@@ -53,6 +53,11 @@ std::string XdsClusterResource::ToString() const {
contents.push_back(absl::StrCat("lrs_load_reporting_server_name=",
lrs_load_reporting_server->server_uri()));
}
+ if (lrs_backend_metric_propagation != nullptr) {
+ contents.push_back(
+ absl::StrCat("lrs_backend_metric_propagation=",
+ lrs_backend_metric_propagation->AsString()));
+ }
if (!common_tls_context.Empty()) {
contents.push_back(
absl::StrCat("common_tls_context=", common_tls_context.ToString()));
diff --git a/src/core/xds/grpc/xds_cluster.h b/src/core/xds/grpc/xds_cluster.h
index f733a9328f8..7eea5d0b0fd 100644
--- a/src/core/xds/grpc/xds_cluster.h
+++ b/src/core/xds/grpc/xds_cluster.h
@@ -30,6 +30,7 @@
#include "src/core/xds/grpc/xds_health_status.h"
#include "src/core/xds/grpc/xds_metadata.h"
#include "src/core/xds/grpc/xds_server_grpc.h"
+#include "src/core/xds/xds_client/xds_backend_metric_propagation.h"
#include "src/core/xds/xds_client/xds_resource_type.h"
#include "src/core/xds/xds_client/xds_resource_type_impl.h"
@@ -44,6 +45,15 @@ inline bool LrsServersEqual(
return *lrs_server1 == *lrs_server2;
}
+inline bool LrsBackendMetricPropagationEqual(
+ const RefCountedPtr& p1,
+ const RefCountedPtr& p2) {
+ if (p1 == nullptr) return p2 == nullptr;
+ if (p2 == nullptr) return false;
+ // Neither one is null, so compare them.
+ return *p1 == *p2;
+}
+
struct XdsClusterResource : public XdsResourceType::ResourceData {
struct Eds {
// If empty, defaults to the cluster name.
@@ -82,6 +92,8 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
// The LRS server to use for load reporting.
// If null, load reporting will be disabled.
std::shared_ptr lrs_load_reporting_server;
+ // The set of metrics to propagate from ORCA to LRS.
+ RefCountedPtr lrs_backend_metric_propagation;
// Tls Context used by clients
CommonTlsContext common_tls_context;
@@ -103,6 +115,9 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
return type == other.type && lb_policy_config == other.lb_policy_config &&
LrsServersEqual(lrs_load_reporting_server,
other.lrs_load_reporting_server) &&
+ LrsBackendMetricPropagationEqual(
+ lrs_backend_metric_propagation,
+ other.lrs_backend_metric_propagation) &&
common_tls_context == other.common_tls_context &&
connection_idle_timeout == other.connection_idle_timeout &&
max_concurrent_requests == other.max_concurrent_requests &&
diff --git a/src/core/xds/grpc/xds_cluster_parser.cc b/src/core/xds/grpc/xds_cluster_parser.cc
index 4b0f2683f10..1a6bbc2e2b6 100644
--- a/src/core/xds/grpc/xds_cluster_parser.cc
+++ b/src/core/xds/grpc/xds_cluster_parser.cc
@@ -59,6 +59,8 @@
#include "src/core/xds/grpc/xds_common_types_parser.h"
#include "src/core/xds/grpc/xds_lb_policy_registry.h"
#include "src/core/xds/grpc/xds_metadata_parser.h"
+#include "src/core/xds/xds_client/lrs_client.h"
+#include "src/core/xds/xds_client/xds_backend_metric_propagation.h"
namespace grpc_core {
@@ -457,6 +459,31 @@ absl::StatusOr> CdsResourceParse(
cds_update->lrs_load_reporting_server = std::make_shared(
static_cast(context.server));
}
+ // Record LRS metric propagation.
+ auto propagation = MakeRefCounted();
+ if (XdsOrcaLrsPropagationChangesEnabled()) {
+ size_t size;
+ upb_StringView const* metrics =
+ envoy_config_cluster_v3_Cluster_lrs_report_endpoint_metrics(cluster,
+ &size);
+ for (size_t i = 0; i < size; ++i) {
+ absl::string_view metric_name = UpbStringToAbsl(metrics[i]);
+ if (metric_name == "cpu_utilization") {
+ propagation->propagation_bits |= propagation->kCpuUtilization;
+ } else if (metric_name == "mem_utilization") {
+ propagation->propagation_bits |= propagation->kMemUtilization;
+ } else if (metric_name == "application_utilization") {
+ propagation->propagation_bits |= propagation->kApplicationUtilization;
+ } else if (absl::ConsumePrefix(&metric_name, "named_metrics.")) {
+ if (metric_name == "*") {
+ propagation->propagation_bits |= propagation->kNamedMetricsAll;
+ } else {
+ propagation->named_metric_keys.emplace(metric_name);
+ }
+ }
+ }
+ }
+ cds_update->lrs_backend_metric_propagation = std::move(propagation);
// Protocol options.
auto* upstream_config =
envoy_config_cluster_v3_Cluster_upstream_config(cluster);
diff --git a/src/core/xds/xds_client/lrs_client.cc b/src/core/xds/xds_client/lrs_client.cc
index b1767a0e037..d8059321d9e 100644
--- a/src/core/xds/xds_client/lrs_client.cc
+++ b/src/core/xds/xds_client/lrs_client.cc
@@ -42,8 +42,10 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/util/backoff.h"
#include "src/core/util/debug_location.h"
+#include "src/core/util/env.h"
#include "src/core/util/orphanable.h"
#include "src/core/util/ref_counted_ptr.h"
+#include "src/core/util/string.h"
#include "src/core/util/sync.h"
#include "src/core/util/upb_utils.h"
#include "src/core/util/uri.h"
@@ -61,6 +63,15 @@ namespace grpc_core {
using ::grpc_event_engine::experimental::EventEngine;
+// TODO(roth): Remove this once the feature passes interop tests.
+bool XdsOrcaLrsPropagationChangesEnabled() {
+ auto value = GetEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ if (!value.has_value()) return false;
+ bool parsed_value;
+ bool parse_succeeded = gpr_parse_bool_value(value->c_str(), &parsed_value);
+ return parse_succeeded && parsed_value;
+}
+
namespace {
uint64_t GetAndResetCounter(std::atomic* from) {
@@ -124,7 +135,8 @@ void LrsClient::ClusterDropStats::AddCallDropped(const std::string& category) {
LrsClient::ClusterLocalityStats::ClusterLocalityStats(
RefCountedPtr lrs_client, absl::string_view lrs_server,
absl::string_view cluster_name, absl::string_view eds_service_name,
- RefCountedPtr name)
+ RefCountedPtr name,
+ RefCountedPtr backend_metric_propagation)
: RefCounted(GRPC_TRACE_FLAG_ENABLED(xds_client_refcount)
? "ClusterLocalityStats"
: nullptr),
@@ -132,13 +144,14 @@ LrsClient::ClusterLocalityStats::ClusterLocalityStats(
lrs_server_(lrs_server),
cluster_name_(cluster_name),
eds_service_name_(eds_service_name),
- name_(std::move(name)) {
+ name_(std::move(name)),
+ backend_metric_propagation_(std::move(backend_metric_propagation)) {
GRPC_TRACE_LOG(xds_client, INFO)
<< "[lrs_client " << lrs_client_.get() << "] created locality stats "
<< this << " for {" << lrs_server_ << ", " << cluster_name_ << ", "
<< eds_service_name_ << ", "
<< (name_ == nullptr ? "" : name_->human_readable_string().c_str())
- << "}";
+ << ", propagation=" << backend_metric_propagation_->AsString() << "}";
}
LrsClient::ClusterLocalityStats::~ClusterLocalityStats() {
@@ -147,9 +160,10 @@ LrsClient::ClusterLocalityStats::~ClusterLocalityStats() {
<< this << " for {" << lrs_server_ << ", " << cluster_name_ << ", "
<< eds_service_name_ << ", "
<< (name_ == nullptr ? "" : name_->human_readable_string().c_str())
- << "}";
+ << ", propagation=" << backend_metric_propagation_->AsString() << "}";
lrs_client_->RemoveClusterLocalityStats(lrs_server_, cluster_name_,
- eds_service_name_, name_, this);
+ eds_service_name_, name_,
+ backend_metric_propagation_, this);
lrs_client_.reset(DEBUG_LOCATION, "ClusterLocalityStats");
}
@@ -164,9 +178,16 @@ LrsClient::ClusterLocalityStats::GetSnapshotAndReset() {
percpu_stats.total_requests_in_progress.load(std::memory_order_relaxed),
GetAndResetCounter(&percpu_stats.total_error_requests),
GetAndResetCounter(&percpu_stats.total_issued_requests),
+ {},
+ {},
+ {},
{}};
{
MutexLock lock(&percpu_stats.backend_metrics_mu);
+ percpu_snapshot.cpu_utilization = std::move(percpu_stats.cpu_utilization);
+ percpu_snapshot.mem_utilization = std::move(percpu_stats.mem_utilization);
+ percpu_snapshot.application_utilization =
+ std::move(percpu_stats.application_utilization);
percpu_snapshot.backend_metrics = std::move(percpu_stats.backend_metrics);
}
snapshot += percpu_snapshot;
@@ -181,16 +202,44 @@ void LrsClient::ClusterLocalityStats::AddCallStarted() {
}
void LrsClient::ClusterLocalityStats::AddCallFinished(
- const std::map* named_metrics, bool fail) {
+ const BackendMetricData* backend_metrics, bool fail) {
Stats& stats = stats_.this_cpu();
std::atomic& to_increment =
fail ? stats.total_error_requests : stats.total_successful_requests;
to_increment.fetch_add(1, std::memory_order_relaxed);
stats.total_requests_in_progress.fetch_add(-1, std::memory_order_acq_rel);
- if (named_metrics == nullptr) return;
+ if (backend_metrics == nullptr) return;
MutexLock lock(&stats.backend_metrics_mu);
- for (const auto& m : *named_metrics) {
- stats.backend_metrics[std::string(m.first)] += BackendMetric{1, m.second};
+ if (!XdsOrcaLrsPropagationChangesEnabled()) {
+ for (const auto& m : backend_metrics->named_metrics) {
+ stats.backend_metrics[std::string(m.first)] += BackendMetric(1, m.second);
+ }
+ return;
+ }
+ if (backend_metric_propagation_->propagation_bits &
+ BackendMetricPropagation::kCpuUtilization) {
+ stats.cpu_utilization += BackendMetric(1, backend_metrics->cpu_utilization);
+ }
+ if (backend_metric_propagation_->propagation_bits &
+ BackendMetricPropagation::kMemUtilization) {
+ stats.mem_utilization += BackendMetric(1, backend_metrics->mem_utilization);
+ }
+ if (backend_metric_propagation_->propagation_bits &
+ BackendMetricPropagation::kApplicationUtilization) {
+ stats.application_utilization +=
+ BackendMetric(1, backend_metrics->application_utilization);
+ }
+ if (backend_metric_propagation_->propagation_bits &
+ BackendMetricPropagation::kNamedMetricsAll ||
+ !backend_metric_propagation_->named_metric_keys.empty()) {
+ for (const auto& m : backend_metrics->named_metrics) {
+ if (backend_metric_propagation_->propagation_bits &
+ BackendMetricPropagation::kNamedMetricsAll ||
+ backend_metric_propagation_->named_metric_keys.contains(m.first)) {
+ stats.backend_metrics[absl::StrCat("named_metrics.", m.first)] +=
+ BackendMetric(1, m.second);
+ }
+ }
}
}
@@ -825,7 +874,8 @@ RefCountedPtr
LrsClient::AddClusterLocalityStats(
std::shared_ptr lrs_server,
absl::string_view cluster_name, absl::string_view eds_service_name,
- RefCountedPtr locality) {
+ RefCountedPtr locality,
+ RefCountedPtr backend_metric_propagation) {
auto key =
std::make_pair(std::string(cluster_name), std::string(eds_service_name));
RefCountedPtr cluster_locality_stats;
@@ -847,20 +897,22 @@ LrsClient::AddClusterLocalityStats(
LoadReportState& load_report_state = load_report_it->second;
LoadReportState::LocalityState& locality_state =
load_report_state.locality_stats[locality];
- if (locality_state.locality_stats != nullptr) {
- cluster_locality_stats = locality_state.locality_stats->RefIfNonZero();
+ ClusterLocalityStats*& locality_stats =
+ locality_state.propagation_stats[backend_metric_propagation];
+ if (locality_stats != nullptr) {
+ cluster_locality_stats = locality_stats->RefIfNonZero();
}
if (cluster_locality_stats == nullptr) {
- if (locality_state.locality_stats != nullptr) {
+ if (locality_stats != nullptr) {
locality_state.deleted_locality_stats +=
- locality_state.locality_stats->GetSnapshotAndReset();
+ locality_stats->GetSnapshotAndReset();
}
cluster_locality_stats = MakeRefCounted(
Ref(DEBUG_LOCATION, "LocalityStats"), server_it->first /*lrs_server*/,
load_report_it->first.first /*cluster_name*/,
load_report_it->first.second /*eds_service_name*/,
- std::move(locality));
- locality_state.locality_stats = cluster_locality_stats.get();
+ std::move(locality), std::move(backend_metric_propagation));
+ locality_stats = cluster_locality_stats.get();
}
server_it->second.lrs_channel->MaybeStartLrsCall();
}
@@ -871,6 +923,8 @@ void LrsClient::RemoveClusterLocalityStats(
absl::string_view lrs_server_key, absl::string_view cluster_name,
absl::string_view eds_service_name,
const RefCountedPtr& locality,
+ const RefCountedPtr&
+ backend_metric_propagation,
ClusterLocalityStats* cluster_locality_stats) {
MutexLock lock(&mu_);
auto server_it = load_report_map_.find(lrs_server_key);
@@ -882,12 +936,16 @@ void LrsClient::RemoveClusterLocalityStats(
auto locality_it = load_report_state.locality_stats.find(locality);
if (locality_it == load_report_state.locality_stats.end()) return;
LoadReportState::LocalityState& locality_state = locality_it->second;
- if (locality_state.locality_stats == cluster_locality_stats) {
+ auto propagation_it =
+ locality_state.propagation_stats.find(backend_metric_propagation);
+ if (propagation_it == locality_state.propagation_stats.end()) return;
+ ClusterLocalityStats* locality_stats = propagation_it->second;
+ if (locality_stats == cluster_locality_stats) {
// Record final snapshot in deleted_locality_stats, which will be
// added to the next load report.
locality_state.deleted_locality_stats +=
- locality_state.locality_stats->GetSnapshotAndReset();
- locality_state.locality_stats = nullptr;
+ locality_stats->GetSnapshotAndReset();
+ locality_state.propagation_stats.erase(propagation_it);
}
}
@@ -940,19 +998,22 @@ LrsClient::ClusterLoadReportMap LrsClient::BuildLoadReportSnapshotLocked(
ClusterLocalityStats::Snapshot& locality_snapshot =
snapshot.locality_stats[locality_name];
locality_snapshot = std::move(locality_state.deleted_locality_stats);
- if (locality_state.locality_stats != nullptr) {
- locality_snapshot +=
- locality_state.locality_stats->GetSnapshotAndReset();
- GRPC_TRACE_LOG(xds_client, INFO)
- << "[lrs_client " << this
- << "] cluster=" << cluster_key.first.c_str()
- << " eds_service_name=" << cluster_key.second.c_str()
- << " locality=" << locality_name->human_readable_string().c_str()
- << " locality_stats=" << locality_state.locality_stats;
+ for (const auto& p : locality_state.propagation_stats) {
+ ClusterLocalityStats* locality_stats = p.second;
+ if (locality_stats != nullptr) {
+ locality_snapshot += locality_stats->GetSnapshotAndReset();
+ GRPC_TRACE_LOG(xds_client, INFO)
+ << "[lrs_client " << this
+ << "] cluster=" << cluster_key.first.c_str()
+ << " eds_service_name=" << cluster_key.second.c_str()
+ << " locality=" << locality_name->human_readable_string().c_str()
+ << " propagation=" << p.first->AsString()
+ << " locality_stats=" << locality_stats;
+ }
}
// If the only thing left in this entry was final snapshots from
// deleted locality stats objects, remove the entry.
- if (locality_state.locality_stats == nullptr) {
+ if (locality_state.propagation_stats.empty()) {
it = load_report.locality_stats.erase(it);
} else {
++it;
@@ -1034,6 +1095,20 @@ std::string LrsClient::CreateLrsInitialRequest() {
namespace {
+void MaybeAddUnnamedMetric(
+ const LrsApiContext& context,
+ const LrsClient::ClusterLocalityStats::BackendMetric& backend_metric,
+ envoy_config_endpoint_v3_UnnamedEndpointLoadMetricStats* (*add_field)(
+ envoy_config_endpoint_v3_UpstreamLocalityStats*, upb_Arena*),
+ envoy_config_endpoint_v3_UpstreamLocalityStats* output) {
+ if (backend_metric.IsZero()) return;
+ auto* metric_proto = add_field(output, context.arena);
+ envoy_config_endpoint_v3_UnnamedEndpointLoadMetricStats_set_num_requests_finished_with_metric(
+ metric_proto, backend_metric.num_requests_finished_with_metric);
+ envoy_config_endpoint_v3_UnnamedEndpointLoadMetricStats_set_total_metric_value(
+ metric_proto, backend_metric.total_metric_value);
+}
+
void LocalityStatsPopulate(
const LrsApiContext& context,
envoy_config_endpoint_v3_UpstreamLocalityStats* output,
@@ -1065,6 +1140,18 @@ void LocalityStatsPopulate(
envoy_config_endpoint_v3_UpstreamLocalityStats_set_total_issued_requests(
output, snapshot.total_issued_requests);
// Add backend metrics.
+ MaybeAddUnnamedMetric(
+ context, snapshot.cpu_utilization,
+ envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_cpu_utilization,
+ output);
+ MaybeAddUnnamedMetric(
+ context, snapshot.mem_utilization,
+ envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_mem_utilization,
+ output);
+ MaybeAddUnnamedMetric(
+ context, snapshot.application_utilization,
+ envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_application_utilization,
+ output);
for (const auto& p : snapshot.backend_metrics) {
const std::string& metric_name = p.first;
const LrsClient::ClusterLocalityStats::BackendMetric& metric_value =
diff --git a/src/core/xds/xds_client/lrs_client.h b/src/core/xds/xds_client/lrs_client.h
index 7bda6f68799..36fabc56fe3 100644
--- a/src/core/xds/xds_client/lrs_client.h
+++ b/src/core/xds/xds_client/lrs_client.h
@@ -33,6 +33,7 @@
#include
#include "src/core/lib/debug/trace.h"
+#include "src/core/load_balancing/backend_metric_data.h"
#include "src/core/util/dual_ref_counted.h"
#include "src/core/util/orphanable.h"
#include "src/core/util/per_cpu.h"
@@ -43,6 +44,7 @@
#include "src/core/util/uri.h"
#include "src/core/util/work_serializer.h"
#include "src/core/xds/xds_client/xds_api.h"
+#include "src/core/xds/xds_client/xds_backend_metric_propagation.h"
#include "src/core/xds/xds_client/xds_bootstrap.h"
#include "src/core/xds/xds_client/xds_locality.h"
#include "src/core/xds/xds_client/xds_metrics.h"
@@ -51,6 +53,8 @@
namespace grpc_core {
+bool XdsOrcaLrsPropagationChangesEnabled();
+
class LrsClient : public DualRefCounted {
public:
// Drop stats for an xds cluster.
@@ -114,6 +118,24 @@ class LrsClient : public DualRefCounted {
uint64_t num_requests_finished_with_metric = 0;
double total_metric_value = 0;
+ BackendMetric() = default;
+
+ BackendMetric(uint64_t num_requests_finished, double value)
+ : num_requests_finished_with_metric(num_requests_finished),
+ total_metric_value(value) {}
+
+ BackendMetric(BackendMetric&& other) noexcept
+ : num_requests_finished_with_metric(
+ std::exchange(other.num_requests_finished_with_metric, 0)),
+ total_metric_value(std::exchange(other.total_metric_value, 0)) {}
+
+ BackendMetric& operator=(BackendMetric&& other) noexcept {
+ num_requests_finished_with_metric =
+ std::exchange(other.num_requests_finished_with_metric, 0);
+ total_metric_value = std::exchange(other.total_metric_value, 0);
+ return *this;
+ }
+
BackendMetric& operator+=(const BackendMetric& other) {
num_requests_finished_with_metric +=
other.num_requests_finished_with_metric;
@@ -132,6 +154,9 @@ class LrsClient : public DualRefCounted {
uint64_t total_requests_in_progress = 0;
uint64_t total_error_requests = 0;
uint64_t total_issued_requests = 0;
+ BackendMetric cpu_utilization;
+ BackendMetric mem_utilization;
+ BackendMetric application_utilization;
std::map backend_metrics;
Snapshot& operator+=(const Snapshot& other) {
@@ -139,6 +164,9 @@ class LrsClient : public DualRefCounted {
total_requests_in_progress += other.total_requests_in_progress;
total_error_requests += other.total_error_requests;
total_issued_requests += other.total_issued_requests;
+ cpu_utilization += other.cpu_utilization;
+ mem_utilization += other.mem_utilization;
+ application_utilization += other.application_utilization;
for (const auto& p : other.backend_metrics) {
backend_metrics[p.first] += p.second;
}
@@ -147,7 +175,9 @@ class LrsClient : public DualRefCounted {
bool IsZero() const {
if (total_successful_requests != 0 || total_requests_in_progress != 0 ||
- total_error_requests != 0 || total_issued_requests != 0) {
+ total_error_requests != 0 || total_issued_requests != 0 ||
+ !cpu_utilization.IsZero() || !mem_utilization.IsZero() ||
+ !application_utilization.IsZero()) {
return false;
}
for (const auto& p : backend_metrics) {
@@ -161,16 +191,17 @@ class LrsClient : public DualRefCounted {
absl::string_view lrs_server,
absl::string_view cluster_name,
absl::string_view eds_service_name,
- RefCountedPtr name);
+ RefCountedPtr name,
+ RefCountedPtr
+ backend_metric_propagation);
~ClusterLocalityStats() override;
// Returns a snapshot of this instance and resets all the counters.
Snapshot GetSnapshotAndReset();
void AddCallStarted();
- void AddCallFinished(
- const std::map* named_metrics,
- bool fail = false);
+ void AddCallFinished(const BackendMetricData* backend_metrics,
+ bool fail = false);
XdsLocalityName* locality_name() const { return name_.get(); }
@@ -181,10 +212,10 @@ class LrsClient : public DualRefCounted {
std::atomic total_error_requests{0};
std::atomic total_issued_requests{0};
- // Protects backend_metrics. A mutex is necessary because the length of
- // backend_metrics_ can be accessed by both the callback intercepting the
- // call's recv_trailing_metadata and the load reporting thread.
Mutex backend_metrics_mu;
+ BackendMetric cpu_utilization ABSL_GUARDED_BY(backend_metrics_mu);
+ BackendMetric mem_utilization ABSL_GUARDED_BY(backend_metrics_mu);
+ BackendMetric application_utilization ABSL_GUARDED_BY(backend_metrics_mu);
std::map backend_metrics
ABSL_GUARDED_BY(backend_metrics_mu);
};
@@ -194,6 +225,7 @@ class LrsClient : public DualRefCounted {
absl::string_view cluster_name_;
absl::string_view eds_service_name_;
RefCountedPtr name_;
+ RefCountedPtr backend_metric_propagation_;
PerCpu stats_{PerCpuOptions().SetMaxShards(32).SetCpusPerShard(4)};
};
@@ -204,17 +236,18 @@ class LrsClient : public DualRefCounted {
std::shared_ptr engine);
~LrsClient() override;
- // Adds and removes drop stats for cluster_name and eds_service_name.
+ // Adds drop stats for cluster_name and eds_service_name.
RefCountedPtr AddClusterDropStats(
std::shared_ptr lrs_server,
absl::string_view cluster_name, absl::string_view eds_service_name);
- // Adds and removes locality stats for cluster_name and eds_service_name
- // for the specified locality.
+ // Adds locality stats for cluster_name and eds_service_name for the
+ // specified locality with the specified backend metric propagation.
RefCountedPtr AddClusterLocalityStats(
std::shared_ptr lrs_server,
absl::string_view cluster_name, absl::string_view eds_service_name,
- RefCountedPtr locality);
+ RefCountedPtr locality,
+ RefCountedPtr backend_metric_propagation);
// Resets connection backoff state.
void ResetBackoff();
@@ -267,7 +300,9 @@ class LrsClient : public DualRefCounted {
struct LoadReportState {
struct LocalityState {
- ClusterLocalityStats* locality_stats = nullptr;
+ std::map,
+ ClusterLocalityStats*, BackendMetricPropagation::Less>
+ propagation_stats;
ClusterLocalityStats::Snapshot deleted_locality_stats;
};
@@ -321,6 +356,8 @@ class LrsClient : public DualRefCounted {
absl::string_view lrs_server, absl::string_view cluster_name,
absl::string_view eds_service_name,
const RefCountedPtr& locality,
+ const RefCountedPtr&
+ backend_metric_propagation,
ClusterLocalityStats* cluster_locality_stats);
// Creates an initial LRS request.
diff --git a/src/core/xds/xds_client/xds_backend_metric_propagation.cc b/src/core/xds/xds_client/xds_backend_metric_propagation.cc
new file mode 100644
index 00000000000..1d514a0f25c
--- /dev/null
+++ b/src/core/xds/xds_client/xds_backend_metric_propagation.cc
@@ -0,0 +1,64 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/xds/xds_client/xds_backend_metric_propagation.h"
+
+#include
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+
+#include "src/core/util/useful.h"
+
+namespace grpc_core {
+
+std::string BackendMetricPropagation::AsString() const {
+ std::vector parts;
+ if (propagation_bits & kCpuUtilization) parts.push_back("cpu_utilization");
+ if (propagation_bits & kMemUtilization) parts.push_back("mem_utilization");
+ if (propagation_bits & kApplicationUtilization) {
+ parts.push_back("application_utilization");
+ }
+ if (propagation_bits & kNamedMetricsAll) {
+ parts.push_back("named_metrics.*");
+ } else {
+ // Output keys in sorted order for consistency.
+ std::vector keys(named_metric_keys.begin(),
+ named_metric_keys.end());
+ std::sort(keys.begin(), keys.end());
+ for (const auto& key : keys) {
+ parts.push_back(absl::StrCat("named_metrics.", key));
+ }
+ }
+ return absl::StrCat("{", absl::StrJoin(parts, ","), "}");
+}
+
+bool BackendMetricPropagation::operator<(
+ const BackendMetricPropagation& other) const {
+ int c = QsortCompare(propagation_bits, other.propagation_bits);
+ if (c != 0) return c == -1;
+ auto other_it = other.named_metric_keys.begin();
+ for (auto it = named_metric_keys.begin(); it != named_metric_keys.end();
+ ++it) {
+ if (other_it == other.named_metric_keys.end()) return false;
+ c = QsortCompare(*it, *other_it);
+ if (c != 0) return c == -1;
+ ++other_it;
+ }
+ return false;
+}
+
+} // namespace grpc_core
diff --git a/src/core/xds/xds_client/xds_backend_metric_propagation.h b/src/core/xds/xds_client/xds_backend_metric_propagation.h
new file mode 100644
index 00000000000..4216c0ac47e
--- /dev/null
+++ b/src/core/xds/xds_client/xds_backend_metric_propagation.h
@@ -0,0 +1,60 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef GRPC_SRC_CORE_XDS_XDS_CLIENT_XDS_BACKEND_METRIC_PROPAGATION_H
+#define GRPC_SRC_CORE_XDS_XDS_CLIENT_XDS_BACKEND_METRIC_PROPAGATION_H
+
+#include
+
+#include "absl/container/flat_hash_set.h"
+
+#include "src/core/util/ref_counted.h"
+#include "src/core/util/ref_counted_ptr.h"
+
+namespace grpc_core {
+
+struct BackendMetricPropagation : public RefCounted {
+ static constexpr uint8_t kCpuUtilization = 1;
+ static constexpr uint8_t kMemUtilization = 2;
+ static constexpr uint8_t kApplicationUtilization = 4;
+ static constexpr uint8_t kNamedMetricsAll = 8;
+
+ uint8_t propagation_bits = 0;
+ absl::flat_hash_set named_metric_keys;
+
+ std::string AsString() const;
+
+ bool operator==(const BackendMetricPropagation& other) const {
+ return propagation_bits == other.propagation_bits &&
+ named_metric_keys == other.named_metric_keys;
+ }
+
+ bool operator<(const BackendMetricPropagation& other) const;
+
+ // Sorting functor for RefCountedPtr.
+ struct Less {
+ bool operator()(
+ const RefCountedPtr& p1,
+ const RefCountedPtr& p2) const {
+ if (p1 == nullptr || p2 == nullptr) return p1.get() < p2.get();
+ return *p1 < *p2;
+ }
+ };
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_XDS_XDS_CLIENT_XDS_BACKEND_METRIC_PROPAGATION_H
diff --git a/src/proto/grpc/testing/xds/v3/cluster.proto b/src/proto/grpc/testing/xds/v3/cluster.proto
index a7c438399a4..bc4325e378a 100644
--- a/src/proto/grpc/testing/xds/v3/cluster.proto
+++ b/src/proto/grpc/testing/xds/v3/cluster.proto
@@ -252,6 +252,21 @@ message Cluster {
// from the LRS stream here.]
core.v3.ConfigSource lrs_server = 42;
+ // A list of metric names from ORCA load reports to propagate to LRS.
+ //
+ // For map fields in the ORCA proto, the string will be of the form ``.``.
+ // For example, the string ``named_metrics.foo`` will mean to look for the key ``foo`` in the ORCA
+ // ``named_metrics`` field.
+ //
+ // The special map key ``*`` means to report all entries in the map (e.g., ``named_metrics.*`` means to
+ // report all entries in the ORCA named_metrics field). Note that this should be used only with trusted
+ // backends.
+ //
+ // The metric names in LRS will follow the same semantics as this field. In other words, if this field
+ // contains ``named_metrics.foo``, then the LRS load report will include the data with that same string
+ // as the key.
+ repeated string lrs_report_endpoint_metrics = 57;
+
// The Metadata field can be used to provide additional information about the
// cluster. It can be used for stats, logging, and varying filter behavior.
// Fields should use reverse DNS notation to denote which entity within Envoy
diff --git a/src/proto/grpc/testing/xds/v3/load_report.proto b/src/proto/grpc/testing/xds/v3/load_report.proto
index b8ee86fb485..a62e7835050 100644
--- a/src/proto/grpc/testing/xds/v3/load_report.proto
+++ b/src/proto/grpc/testing/xds/v3/load_report.proto
@@ -51,7 +51,20 @@ message UpstreamLocalityStats {
// upstream endpoints in the locality.
uint64 total_issued_requests = 8;
- // Stats for multi-dimensional load balancing.
+ // CPU utilization stats for multi-dimensional load balancing.
+ // This typically comes from endpoint metrics reported via ORCA.
+ UnnamedEndpointLoadMetricStats cpu_utilization = 12;
+
+ // Memory utilization for multi-dimensional load balancing.
+ // This typically comes from endpoint metrics reported via ORCA.
+ UnnamedEndpointLoadMetricStats mem_utilization = 13;
+
+ // Blended application-defined utilization for multi-dimensional load balancing.
+ // This typically comes from endpoint metrics reported via ORCA.
+ UnnamedEndpointLoadMetricStats application_utilization = 14;
+
+ // Named stats for multi-dimensional load balancing.
+ // These typically come from endpoint metrics reported via ORCA.
repeated EndpointLoadMetricStats load_metric_stats = 5;
// Endpoint granularity stats information for this locality. This information
@@ -117,6 +130,16 @@ message EndpointLoadMetricStats {
double total_metric_value = 3;
}
+// Same as EndpointLoadMetricStats, except without the metric_name field.
+message UnnamedEndpointLoadMetricStats {
+ // Number of calls that finished and included this metric.
+ uint64 num_requests_finished_with_metric = 1;
+
+ // Sum of metric values across all calls that finished with this metric for
+ // load_reporting_interval.
+ double total_metric_value = 2;
+}
+
// Per cluster load stats. Envoy reports these stats a management server in a
// :ref:`LoadStatsRequest`
// [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs.
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index f5b68900662..c7e8f2b4c9f 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -866,6 +866,7 @@ CORE_SOURCE_FILES = [
'src/core/xds/grpc/xds_transport_grpc.cc',
'src/core/xds/xds_client/lrs_client.cc',
'src/core/xds/xds_client/xds_api.cc',
+ 'src/core/xds/xds_client/xds_backend_metric_propagation.cc',
'src/core/xds/xds_client/xds_bootstrap.cc',
'src/core/xds/xds_client/xds_client.cc',
'third_party/abseil-cpp/absl/base/internal/cycleclock.cc',
diff --git a/test/core/xds/xds_cluster_resource_type_test.cc b/test/core/xds/xds_cluster_resource_type_test.cc
index fed2848dc65..804241913e8 100644
--- a/test/core/xds/xds_cluster_resource_type_test.cc
+++ b/test/core/xds/xds_cluster_resource_type_test.cc
@@ -1113,7 +1113,7 @@ TEST_F(TlsConfigTest, CaCertProviderUnset) {
}
//
-// LRS server tests
+// LRS tests
//
using LrsTest = XdsClusterTest;
@@ -1160,6 +1160,92 @@ TEST_F(LrsTest, NotSelfConfigSource) {
<< decode_result.resource.status();
}
+TEST_F(LrsTest, IgnoresPropagationWithoutEnvVar) {
+ Cluster cluster;
+ cluster.set_name("foo");
+ cluster.set_type(cluster.EDS);
+ cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
+ cluster.mutable_lrs_server()->mutable_self();
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.foo");
+ cluster.add_lrs_report_endpoint_metrics("cpu_utilization");
+ std::string serialized_resource;
+ ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsClusterResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource =
+ static_cast(**decode_result.resource);
+ ASSERT_NE(resource.lrs_load_reporting_server, nullptr);
+ EXPECT_EQ(*resource.lrs_load_reporting_server,
+ *xds_client_->bootstrap().servers().front());
+ ASSERT_NE(resource.lrs_backend_metric_propagation, nullptr);
+ EXPECT_EQ(resource.lrs_backend_metric_propagation->AsString(), "{}");
+}
+
+TEST_F(LrsTest, Propagation) {
+ ScopedExperimentalEnvVar env_var(
+ "GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ Cluster cluster;
+ cluster.set_name("foo");
+ cluster.set_type(cluster.EDS);
+ cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
+ cluster.mutable_lrs_server()->mutable_self();
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.foo");
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.bar");
+ cluster.add_lrs_report_endpoint_metrics("cpu_utilization");
+ cluster.add_lrs_report_endpoint_metrics("mem_utilization");
+ cluster.add_lrs_report_endpoint_metrics("application_utilization");
+ cluster.add_lrs_report_endpoint_metrics("unknown_field");
+ std::string serialized_resource;
+ ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsClusterResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource =
+ static_cast(**decode_result.resource);
+ ASSERT_NE(resource.lrs_load_reporting_server, nullptr);
+ EXPECT_EQ(*resource.lrs_load_reporting_server,
+ *xds_client_->bootstrap().servers().front());
+ ASSERT_NE(resource.lrs_backend_metric_propagation, nullptr);
+ EXPECT_EQ(resource.lrs_backend_metric_propagation->AsString(),
+ "{cpu_utilization,mem_utilization,application_utilization,"
+ "named_metrics.bar,named_metrics.foo}");
+}
+
+TEST_F(LrsTest, PropagationNamedMetricsAll) {
+ ScopedExperimentalEnvVar env_var(
+ "GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ Cluster cluster;
+ cluster.set_name("foo");
+ cluster.set_type(cluster.EDS);
+ cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
+ cluster.mutable_lrs_server()->mutable_self();
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.*");
+ cluster.add_lrs_report_endpoint_metrics("cpu_utilization");
+ std::string serialized_resource;
+ ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsClusterResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource =
+ static_cast(**decode_result.resource);
+ ASSERT_NE(resource.lrs_load_reporting_server, nullptr);
+ EXPECT_EQ(*resource.lrs_load_reporting_server,
+ *xds_client_->bootstrap().servers().front());
+ ASSERT_NE(resource.lrs_backend_metric_propagation, nullptr);
+ EXPECT_EQ(resource.lrs_backend_metric_propagation->AsString(),
+ "{cpu_utilization,named_metrics.*}");
+}
+
//
// upstream config tests
//
diff --git a/test/cpp/end2end/xds/xds_cluster_end2end_test.cc b/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
index 24398adf7f3..c10f22d4851 100644
--- a/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
+++ b/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
@@ -1724,6 +1724,325 @@ TEST_P(ClientLoadReportingTest, Vanilla) {
EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
}
+// Tests ORCA to LRS propagation.
+TEST_P(ClientLoadReportingTest, OrcaPropagation) {
+ grpc_core::testing::ScopedExperimentalEnvVar env(
+ "GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ CreateAndStartBackends(4);
+ const size_t kNumRpcsPerAddress = 10;
+ const size_t kNumFailuresPerAddress = 3;
+ Cluster cluster = default_cluster_;
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.foo");
+ cluster.add_lrs_report_endpoint_metrics("cpu_utilization");
+ cluster.add_lrs_report_endpoint_metrics("mem_utilization");
+ cluster.add_lrs_report_endpoint_metrics("application_utilization");
+ cluster.add_lrs_report_endpoint_metrics("unknown_field");
+ balancer_->ads_service()->SetCdsResource(cluster);
+ EdsResourceArgs args({
+ {"locality0", CreateEndpointsForBackends(0, 2)},
+ {"locality1", CreateEndpointsForBackends(2, 4)},
+ });
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Wait until all backends are ready.
+ size_t num_warmup_rpcs =
+ WaitForAllBackends(DEBUG_LOCATION, 0, 4, /*check_status=*/nullptr,
+ WaitForBackendOptions().set_reset_counters(false));
+ // Send kNumRpcsPerAddress RPCs per server with named metrics.
+ xds::data::orca::v3::OrcaLoadReport backend_metrics;
+ backend_metrics.set_cpu_utilization(0.8);
+ backend_metrics.set_mem_utilization(0.6);
+ backend_metrics.set_application_utilization(0.4);
+ auto& named_metrics = (*backend_metrics.mutable_named_metrics());
+ named_metrics["foo"] = 1.0;
+ named_metrics["bar"] = 2.0; // Not propagated.
+ CheckRpcSendOk(DEBUG_LOCATION, kNumRpcsPerAddress * backends_.size(),
+ RpcOptions().set_backend_metrics(backend_metrics));
+ backend_metrics.set_cpu_utilization(0.4);
+ backend_metrics.set_mem_utilization(0.3);
+ backend_metrics.set_application_utilization(0.2);
+ named_metrics["foo"] = 0.3;
+ named_metrics["bar"] = 0.4; // Not propagated.
+ for (size_t i = 0; i < kNumFailuresPerAddress * backends_.size(); ++i) {
+ CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::FAILED_PRECONDITION, "",
+ RpcOptions().set_server_fail(true).set_backend_metrics(
+ backend_metrics));
+ }
+ const size_t total_successful_rpcs_sent =
+ (kNumRpcsPerAddress * backends_.size()) + num_warmup_rpcs;
+ const size_t total_failed_rpcs_sent =
+ kNumFailuresPerAddress * backends_.size();
+ // Check that the backends got the right number of requests.
+ size_t total_rpcs_sent = 0;
+ for (const auto& backend : backends_) {
+ total_rpcs_sent += backend->backend_service()->request_count();
+ }
+ EXPECT_EQ(total_rpcs_sent,
+ total_successful_rpcs_sent + total_failed_rpcs_sent);
+ // The load report received at the balancer should be correct.
+ std::vector load_report =
+ balancer_->lrs_service()->WaitForLoadReport();
+ ASSERT_EQ(load_report.size(), 1UL);
+ ClientStats& client_stats = load_report.front();
+ EXPECT_EQ(client_stats.cluster_name(), kDefaultClusterName);
+ EXPECT_EQ(client_stats.eds_service_name(), kDefaultEdsServiceName);
+ EXPECT_EQ(total_successful_rpcs_sent,
+ client_stats.total_successful_requests());
+ EXPECT_EQ(0U, client_stats.total_requests_in_progress());
+ EXPECT_EQ(total_rpcs_sent, client_stats.total_issued_requests());
+ EXPECT_EQ(total_failed_rpcs_sent, client_stats.total_error_requests());
+ EXPECT_EQ(0U, client_stats.total_dropped_requests());
+ ASSERT_THAT(
+ client_stats.locality_stats(),
+ ::testing::ElementsAre(::testing::Pair("locality0", ::testing::_),
+ ::testing::Pair("locality1", ::testing::_)));
+ size_t num_successful_rpcs = 0;
+ size_t num_failed_rpcs = 0;
+ ClientStats::LocalityStats::LoadMetric cpu_utilization;
+ ClientStats::LocalityStats::LoadMetric mem_utilization;
+ ClientStats::LocalityStats::LoadMetric application_utilization;
+ std::map
+ named_metrics_total;
+ for (const auto& p : client_stats.locality_stats()) {
+ EXPECT_EQ(p.second.total_requests_in_progress, 0U);
+ EXPECT_EQ(
+ p.second.total_issued_requests,
+ p.second.total_successful_requests + p.second.total_error_requests);
+ num_successful_rpcs += p.second.total_successful_requests;
+ num_failed_rpcs += p.second.total_error_requests;
+ cpu_utilization += p.second.cpu_utilization;
+ mem_utilization += p.second.mem_utilization;
+ application_utilization += p.second.application_utilization;
+ for (const auto& s : p.second.load_metrics) {
+ named_metrics_total[s.first] += s.second;
+ }
+ }
+ EXPECT_EQ(num_successful_rpcs, total_successful_rpcs_sent);
+ EXPECT_EQ(num_failed_rpcs, total_failed_rpcs_sent);
+ EXPECT_EQ(num_successful_rpcs + num_failed_rpcs, total_rpcs_sent);
+ EXPECT_THAT(
+ cpu_utilization,
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) * backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 0.8 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.4));
+ EXPECT_THAT(
+ mem_utilization,
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) * backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 0.6 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.3));
+ EXPECT_THAT(
+ application_utilization,
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) * backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 0.4 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.2));
+ EXPECT_THAT(
+ named_metrics_total,
+ ::testing::UnorderedElementsAre(::testing::Pair(
+ "named_metrics.foo",
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) * backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 1.0 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.3))));
+ // The LRS service got a single request, and sent a single response.
+ EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
+ EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
+}
+
+TEST_P(ClientLoadReportingTest, OrcaPropagationNamedMetricsAll) {
+ grpc_core::testing::ScopedExperimentalEnvVar env(
+ "GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ CreateAndStartBackends(4);
+ const size_t kNumRpcsPerAddress = 10;
+ const size_t kNumFailuresPerAddress = 3;
+ Cluster cluster = default_cluster_;
+ cluster.add_lrs_report_endpoint_metrics("named_metrics.*");
+ balancer_->ads_service()->SetCdsResource(cluster);
+ EdsResourceArgs args({
+ {"locality0", CreateEndpointsForBackends(0, 2)},
+ {"locality1", CreateEndpointsForBackends(2, 4)},
+ });
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Wait until all backends are ready.
+ size_t num_warmup_rpcs =
+ WaitForAllBackends(DEBUG_LOCATION, 0, 4, /*check_status=*/nullptr,
+ WaitForBackendOptions().set_reset_counters(false));
+ // Send kNumRpcsPerAddress RPCs per server with named metrics.
+ xds::data::orca::v3::OrcaLoadReport backend_metrics;
+ backend_metrics.set_cpu_utilization(0.8);
+ backend_metrics.set_mem_utilization(0.6);
+ backend_metrics.set_application_utilization(0.4);
+ auto& named_metrics = (*backend_metrics.mutable_named_metrics());
+ named_metrics["foo"] = 1.0;
+ named_metrics["bar"] = 2.0;
+ CheckRpcSendOk(DEBUG_LOCATION, kNumRpcsPerAddress * backends_.size(),
+ RpcOptions().set_backend_metrics(backend_metrics));
+ backend_metrics.set_cpu_utilization(0.4);
+ backend_metrics.set_mem_utilization(0.3);
+ backend_metrics.set_application_utilization(0.2);
+ named_metrics["foo"] = 0.3;
+ named_metrics["bar"] = 0.4;
+ for (size_t i = 0; i < kNumFailuresPerAddress * backends_.size(); ++i) {
+ CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::FAILED_PRECONDITION, "",
+ RpcOptions().set_server_fail(true).set_backend_metrics(
+ backend_metrics));
+ }
+ const size_t total_successful_rpcs_sent =
+ (kNumRpcsPerAddress * backends_.size()) + num_warmup_rpcs;
+ const size_t total_failed_rpcs_sent =
+ kNumFailuresPerAddress * backends_.size();
+ // Check that the backends got the right number of requests.
+ size_t total_rpcs_sent = 0;
+ for (const auto& backend : backends_) {
+ total_rpcs_sent += backend->backend_service()->request_count();
+ }
+ EXPECT_EQ(total_rpcs_sent,
+ total_successful_rpcs_sent + total_failed_rpcs_sent);
+ // The load report received at the balancer should be correct.
+ std::vector load_report =
+ balancer_->lrs_service()->WaitForLoadReport();
+ ASSERT_EQ(load_report.size(), 1UL);
+ ClientStats& client_stats = load_report.front();
+ EXPECT_EQ(client_stats.cluster_name(), kDefaultClusterName);
+ EXPECT_EQ(client_stats.eds_service_name(), kDefaultEdsServiceName);
+ EXPECT_EQ(total_successful_rpcs_sent,
+ client_stats.total_successful_requests());
+ EXPECT_EQ(0U, client_stats.total_requests_in_progress());
+ EXPECT_EQ(total_rpcs_sent, client_stats.total_issued_requests());
+ EXPECT_EQ(total_failed_rpcs_sent, client_stats.total_error_requests());
+ EXPECT_EQ(0U, client_stats.total_dropped_requests());
+ ASSERT_THAT(
+ client_stats.locality_stats(),
+ ::testing::ElementsAre(::testing::Pair("locality0", ::testing::_),
+ ::testing::Pair("locality1", ::testing::_)));
+ size_t num_successful_rpcs = 0;
+ size_t num_failed_rpcs = 0;
+ std::map
+ named_metrics_total;
+ for (const auto& p : client_stats.locality_stats()) {
+ EXPECT_EQ(p.second.total_requests_in_progress, 0U);
+ EXPECT_EQ(
+ p.second.total_issued_requests,
+ p.second.total_successful_requests + p.second.total_error_requests);
+ num_successful_rpcs += p.second.total_successful_requests;
+ num_failed_rpcs += p.second.total_error_requests;
+ for (const auto& s : p.second.load_metrics) {
+ named_metrics_total[s.first] += s.second;
+ }
+ }
+ EXPECT_EQ(num_successful_rpcs, total_successful_rpcs_sent);
+ EXPECT_EQ(num_failed_rpcs, total_failed_rpcs_sent);
+ EXPECT_EQ(num_successful_rpcs + num_failed_rpcs, total_rpcs_sent);
+ EXPECT_THAT(
+ named_metrics_total,
+ ::testing::UnorderedElementsAre(
+ ::testing::Pair(
+ "named_metrics.foo",
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) *
+ backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 1.0 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.3)),
+ ::testing::Pair(
+ "named_metrics.bar",
+ LoadMetricEq(
+ (kNumRpcsPerAddress + kNumFailuresPerAddress) *
+ backends_.size(),
+ (kNumRpcsPerAddress * backends_.size()) * 2.0 +
+ (kNumFailuresPerAddress * backends_.size()) * 0.4))));
+ // The LRS service got a single request, and sent a single response.
+ EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
+ EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
+}
+
+TEST_P(ClientLoadReportingTest, OrcaPropagationNotConfigured) {
+ grpc_core::testing::ScopedExperimentalEnvVar env(
+ "GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION");
+ CreateAndStartBackends(4);
+ const size_t kNumRpcsPerAddress = 10;
+ const size_t kNumFailuresPerAddress = 3;
+ EdsResourceArgs args({
+ {"locality0", CreateEndpointsForBackends(0, 2)},
+ {"locality1", CreateEndpointsForBackends(2, 4)},
+ });
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Wait until all backends are ready.
+ size_t num_warmup_rpcs =
+ WaitForAllBackends(DEBUG_LOCATION, 0, 4, /*check_status=*/nullptr,
+ WaitForBackendOptions().set_reset_counters(false));
+ // Send kNumRpcsPerAddress RPCs per server with named metrics.
+ xds::data::orca::v3::OrcaLoadReport backend_metrics;
+ backend_metrics.set_cpu_utilization(0.8);
+ backend_metrics.set_mem_utilization(0.6);
+ backend_metrics.set_application_utilization(0.4);
+ auto& named_metrics = (*backend_metrics.mutable_named_metrics());
+ named_metrics["foo"] = 1.0;
+ named_metrics["bar"] = 2.0;
+ CheckRpcSendOk(DEBUG_LOCATION, kNumRpcsPerAddress * backends_.size(),
+ RpcOptions().set_backend_metrics(backend_metrics));
+ backend_metrics.set_cpu_utilization(0.4);
+ backend_metrics.set_mem_utilization(0.3);
+ backend_metrics.set_application_utilization(0.2);
+ named_metrics["foo"] = 0.3;
+ named_metrics["bar"] = 0.4;
+ for (size_t i = 0; i < kNumFailuresPerAddress * backends_.size(); ++i) {
+ CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::FAILED_PRECONDITION, "",
+ RpcOptions().set_server_fail(true).set_backend_metrics(
+ backend_metrics));
+ }
+ const size_t total_successful_rpcs_sent =
+ (kNumRpcsPerAddress * backends_.size()) + num_warmup_rpcs;
+ const size_t total_failed_rpcs_sent =
+ kNumFailuresPerAddress * backends_.size();
+ // Check that the backends got the right number of requests.
+ size_t total_rpcs_sent = 0;
+ for (const auto& backend : backends_) {
+ total_rpcs_sent += backend->backend_service()->request_count();
+ }
+ EXPECT_EQ(total_rpcs_sent,
+ total_successful_rpcs_sent + total_failed_rpcs_sent);
+ // The load report received at the balancer should be correct.
+ std::vector load_report =
+ balancer_->lrs_service()->WaitForLoadReport();
+ ASSERT_EQ(load_report.size(), 1UL);
+ ClientStats& client_stats = load_report.front();
+ EXPECT_EQ(client_stats.cluster_name(), kDefaultClusterName);
+ EXPECT_EQ(client_stats.eds_service_name(), kDefaultEdsServiceName);
+ EXPECT_EQ(total_successful_rpcs_sent,
+ client_stats.total_successful_requests());
+ EXPECT_EQ(0U, client_stats.total_requests_in_progress());
+ EXPECT_EQ(total_rpcs_sent, client_stats.total_issued_requests());
+ EXPECT_EQ(total_failed_rpcs_sent, client_stats.total_error_requests());
+ EXPECT_EQ(0U, client_stats.total_dropped_requests());
+ ASSERT_THAT(
+ client_stats.locality_stats(),
+ ::testing::ElementsAre(::testing::Pair("locality0", ::testing::_),
+ ::testing::Pair("locality1", ::testing::_)));
+ size_t num_successful_rpcs = 0;
+ size_t num_failed_rpcs = 0;
+ std::map
+ named_metrics_total;
+ for (const auto& p : client_stats.locality_stats()) {
+ EXPECT_EQ(p.second.total_requests_in_progress, 0U);
+ EXPECT_EQ(
+ p.second.total_issued_requests,
+ p.second.total_successful_requests + p.second.total_error_requests);
+ num_successful_rpcs += p.second.total_successful_requests;
+ num_failed_rpcs += p.second.total_error_requests;
+ for (const auto& s : p.second.load_metrics) {
+ named_metrics_total[s.first] += s.second;
+ }
+ }
+ EXPECT_EQ(num_successful_rpcs, total_successful_rpcs_sent);
+ EXPECT_EQ(num_failed_rpcs, total_failed_rpcs_sent);
+ EXPECT_EQ(num_successful_rpcs + num_failed_rpcs, total_rpcs_sent);
+ EXPECT_THAT(named_metrics_total, ::testing::UnorderedElementsAre());
+ // The LRS service got a single request, and sent a single response.
+ EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
+ EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
+}
+
// Tests send_all_clusters.
TEST_P(ClientLoadReportingTest, SendAllClusters) {
CreateAndStartBackends(2);
diff --git a/test/cpp/end2end/xds/xds_end2end_test_lib.h b/test/cpp/end2end/xds/xds_end2end_test_lib.h
index 5183e9cd562..02e3fcbe50d 100644
--- a/test/cpp/end2end/xds/xds_end2end_test_lib.h
+++ b/test/cpp/end2end/xds/xds_end2end_test_lib.h
@@ -304,6 +304,18 @@ class XdsEnd2endTest : public ::testing::TestWithParam,
if (request->has_param() && request->param().has_backend_metrics()) {
const auto& request_metrics = request->param().backend_metrics();
auto* recorder = context->ExperimentalGetCallMetricRecorder();
+ if (request_metrics.cpu_utilization() != 0) {
+ recorder->RecordCpuUtilizationMetric(
+ request_metrics.cpu_utilization());
+ }
+ if (request_metrics.mem_utilization() != 0) {
+ recorder->RecordMemoryUtilizationMetric(
+ request_metrics.mem_utilization());
+ }
+ if (request_metrics.application_utilization() != 0) {
+ recorder->RecordApplicationUtilizationMetric(
+ request_metrics.application_utilization());
+ }
for (const auto& p : request_metrics.named_metrics()) {
char* key = static_cast(
grpc_call_arena_alloc(context->c_call(), p.first.size() + 1));
diff --git a/test/cpp/end2end/xds/xds_server.h b/test/cpp/end2end/xds/xds_server.h
index 4131362f7b0..2b6c508faf7 100644
--- a/test/cpp/end2end/xds/xds_server.h
+++ b/test/cpp/end2end/xds/xds_server.h
@@ -617,8 +617,19 @@ class LrsServiceImpl
// Stats for a given locality.
struct LocalityStats {
struct LoadMetric {
- uint64_t num_requests_finished_with_metric;
- double total_metric_value;
+ uint64_t num_requests_finished_with_metric = 0;
+ double total_metric_value = 0;
+
+ LoadMetric() = default;
+
+ // Works for both EndpointLoadMetricStats and
+ // UnnamedEndpointLoadMetricStats.
+ template
+ explicit LoadMetric(const T& stats)
+ : num_requests_finished_with_metric(
+ stats.num_requests_finished_with_metric()),
+ total_metric_value(stats.total_metric_value()) {}
+
LoadMetric& operator+=(const LoadMetric& other) {
num_requests_finished_with_metric +=
other.num_requests_finished_with_metric;
@@ -640,10 +651,13 @@ class LrsServiceImpl
total_error_requests(
upstream_locality_stats.total_error_requests()),
total_issued_requests(
- upstream_locality_stats.total_issued_requests()) {
+ upstream_locality_stats.total_issued_requests()),
+ cpu_utilization(upstream_locality_stats.cpu_utilization()),
+ mem_utilization(upstream_locality_stats.mem_utilization()),
+ application_utilization(
+ upstream_locality_stats.application_utilization()) {
for (const auto& s : upstream_locality_stats.load_metric_stats()) {
- load_metrics[s.metric_name()] += LoadMetric{
- s.num_requests_finished_with_metric(), s.total_metric_value()};
+ load_metrics[s.metric_name()] += LoadMetric(s);
}
}
@@ -652,6 +666,9 @@ class LrsServiceImpl
total_requests_in_progress += other.total_requests_in_progress;
total_error_requests += other.total_error_requests;
total_issued_requests += other.total_issued_requests;
+ cpu_utilization += other.cpu_utilization;
+ mem_utilization += other.mem_utilization;
+ application_utilization += other.application_utilization;
for (const auto& p : other.load_metrics) {
load_metrics[p.first] += p.second;
}
@@ -662,6 +679,9 @@ class LrsServiceImpl
uint64_t total_requests_in_progress = 0;
uint64_t total_error_requests = 0;
uint64_t total_issued_requests = 0;
+ LoadMetric cpu_utilization;
+ LoadMetric mem_utilization;
+ LoadMetric application_utilization;
std::map load_metrics;
};
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 994e038c983..4220bb664a0 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -3044,6 +3044,8 @@ src/core/xds/xds_client/lrs_client.cc \
src/core/xds/xds_client/lrs_client.h \
src/core/xds/xds_client/xds_api.cc \
src/core/xds/xds_client/xds_api.h \
+src/core/xds/xds_client/xds_backend_metric_propagation.cc \
+src/core/xds/xds_client/xds_backend_metric_propagation.h \
src/core/xds/xds_client/xds_bootstrap.cc \
src/core/xds/xds_client/xds_bootstrap.h \
src/core/xds/xds_client/xds_channel_args.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 3725bd86978..eae9a2e2ea4 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -2821,6 +2821,8 @@ src/core/xds/xds_client/lrs_client.cc \
src/core/xds/xds_client/lrs_client.h \
src/core/xds/xds_client/xds_api.cc \
src/core/xds/xds_client/xds_api.h \
+src/core/xds/xds_client/xds_backend_metric_propagation.cc \
+src/core/xds/xds_client/xds_backend_metric_propagation.h \
src/core/xds/xds_client/xds_bootstrap.cc \
src/core/xds/xds_client/xds_bootstrap.h \
src/core/xds/xds_client/xds_channel_args.h \
From 40ff7aa6178d243ae9431a875fb4050c4b2534a9 Mon Sep 17 00:00:00 2001
From: Craig Tiller
Date: Fri, 27 Sep 2024 11:31:31 -0700
Subject: [PATCH 07/74] [call-v3] Inline OperationExecutor methods (#37006)
These methods are very short and very inlinable. Further more the specializations are very infrequently repeated.
(I'm essentially hoisting code out of the .cc file and landing it in the .h file with the appropriate inlining annotations here)
Before:
```
----------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------------------------------
grpc_core::BM_UnaryWithSpawnPerEnd 1053 ns 1053 ns 2674404
grpc_core::BM_UnaryWithSpawnPerOp 1191 ns 1191 ns 2337068
grpc_core::BM_ClientToServerStreaming 243 ns 243 ns 11511112
grpc_core::BM_UnaryWithSpawnPerEnd 2723 ns 2724 ns 1033990
grpc_core::BM_UnaryWithSpawnPerOp 2930 ns 2931 ns 942815
grpc_core::BM_ClientToServerStreaming 455 ns 455 ns 6213422
```
After:
```
----------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------------------------------
grpc_core::BM_UnaryWithSpawnPerEnd 986 ns 986 ns 2867870
grpc_core::BM_UnaryWithSpawnPerOp 1101 ns 1101 ns 2472611
grpc_core::BM_ClientToServerStreaming 220 ns 220 ns 12774397
grpc_core::BM_UnaryWithSpawnPerEnd 2512 ns 2512 ns 1111667
grpc_core::BM_UnaryWithSpawnPerOp 2743 ns 2744 ns 1008676
grpc_core::BM_ClientToServerStreaming 420 ns 420 ns 6820805
```
Closes #37006
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37006 from ctiller:inline-filters 24903bd524ae5f4c97fe75318a3fcf73436ff6ea
PiperOrigin-RevId: 679666043
---
src/core/lib/transport/call_filters.cc | 115 +------------------------
src/core/lib/transport/call_filters.h | 108 +++++++++++++++++++++--
2 files changed, 104 insertions(+), 119 deletions(-)
diff --git a/src/core/lib/transport/call_filters.cc b/src/core/lib/transport/call_filters.cc
index f15579db603..822c266b0b3 100644
--- a/src/core/lib/transport/call_filters.cc
+++ b/src/core/lib/transport/call_filters.cc
@@ -23,124 +23,13 @@
#include "src/core/util/crash.h"
namespace grpc_core {
-
-namespace filters_detail {
-
-void RunHalfClose(absl::Span ops, void* call_data) {
- for (const auto& op : ops) {
- op.half_close(Offset(call_data, op.call_offset), op.channel_data);
- }
-}
-
-ServerMetadataHandle RunServerTrailingMetadata(
- absl::Span ops, void* call_data,
- ServerMetadataHandle md) {
- for (auto& op : ops) {
- md = op.server_trailing_metadata(Offset(call_data, op.call_offset),
- op.channel_data, std::move(md));
- }
- return md;
-}
-
-template
-OperationExecutor::~OperationExecutor() {
- if (promise_data_ != nullptr) {
- ops_->early_destroy(promise_data_);
- gpr_free_aligned(promise_data_);
- }
-}
-
-template
-Poll> OperationExecutor::Start(const Layout* layout, T input,
- void* call_data) {
- ops_ = layout->ops.data();
- end_ops_ = ops_ + layout->ops.size();
- if (layout->promise_size == 0) {
- // No call state ==> instantaneously ready
- auto r = InitStep(std::move(input), call_data);
- CHECK(r.ready());
- return r;
- }
- promise_data_ =
- gpr_malloc_aligned(layout->promise_size, layout->promise_alignment);
- return InitStep(std::move(input), call_data);
-}
-
-template
-Poll> OperationExecutor::InitStep(T input, void* call_data) {
- CHECK(input != nullptr);
- while (true) {
- if (ops_ == end_ops_) {
- return ResultOr{std::move(input), nullptr};
- }
- auto p =
- ops_->promise_init(promise_data_, Offset(call_data, ops_->call_offset),
- ops_->channel_data, std::move(input));
- if (auto* r = p.value_if_ready()) {
- if (r->ok == nullptr) return std::move(*r);
- input = std::move(r->ok);
- ++ops_;
- continue;
- }
- return Pending{};
- }
-}
-
-template
-Poll> OperationExecutor::Step(void* call_data) {
- DCHECK_NE(promise_data_, nullptr);
- auto p = ContinueStep(call_data);
- if (p.ready()) {
- gpr_free_aligned(promise_data_);
- promise_data_ = nullptr;
- }
- return p;
-}
-
-template
-Poll> OperationExecutor::ContinueStep(void* call_data) {
- auto p = ops_->poll(promise_data_);
- if (auto* r = p.value_if_ready()) {
- if (r->ok == nullptr) return std::move(*r);
- ++ops_;
- return InitStep(std::move(r->ok), call_data);
- }
- return Pending{};
-}
-
-// Explicit instantiations of some types used in filters.h
-// We'll need to add ServerMetadataHandle to this when it becomes different
-// to ClientMetadataHandle
-template class OperationExecutor;
-template class OperationExecutor;
-
-} // namespace filters_detail
-
-namespace {
// Call data for those calls that don't have any call data
// (we form pointers to this that aren't allowed to be nullptr)
-char g_empty_call_data;
-} // namespace
+char CallFilters::g_empty_call_data_;
///////////////////////////////////////////////////////////////////////////////
// CallFilters
-CallFilters::CallFilters(ClientMetadataHandle client_initial_metadata)
- : call_data_(nullptr),
- push_client_initial_metadata_(std::move(client_initial_metadata)) {}
-
-CallFilters::~CallFilters() {
- if (call_data_ != nullptr && call_data_ != &g_empty_call_data) {
- for (const auto& stack : stacks_) {
- for (const auto& destructor : stack.stack->data_.filter_destructor) {
- destructor.call_destroy(filters_detail::Offset(
- call_data_, stack.call_data_offset + destructor.call_offset));
- }
- }
- gpr_free_aligned(call_data_);
- }
-}
-
void CallFilters::Start() {
CHECK_EQ(call_data_, nullptr);
size_t call_data_alignment = 1;
@@ -161,7 +50,7 @@ void CallFilters::Start() {
if (call_data_size != 0) {
call_data_ = gpr_malloc_aligned(call_data_size, call_data_alignment);
} else {
- call_data_ = &g_empty_call_data;
+ call_data_ = &g_empty_call_data_;
}
for (const auto& stack : stacks_) {
for (const auto& constructor : stack.stack->data_.filter_constructor) {
diff --git a/src/core/lib/transport/call_filters.h b/src/core/lib/transport/call_filters.h
index fb64eb95eca..b1a54f5dfec 100644
--- a/src/core/lib/transport/call_filters.h
+++ b/src/core/lib/transport/call_filters.h
@@ -220,10 +220,22 @@ struct ServerTrailingMetadataOperator {
void* call_data, void* channel_data, ServerMetadataHandle metadata);
};
-void RunHalfClose(absl::Span ops, void* call_data);
-ServerMetadataHandle RunServerTrailingMetadata(
- absl::Span ops, void* call_data,
- ServerMetadataHandle md);
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline void RunHalfClose(
+ absl::Span ops, void* call_data) {
+ for (const auto& op : ops) {
+ op.half_close(Offset(call_data, op.call_offset), op.channel_data);
+ }
+}
+
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline ServerMetadataHandle
+RunServerTrailingMetadata(absl::Span ops,
+ void* call_data, ServerMetadataHandle md) {
+ for (auto& op : ops) {
+ md = op.server_trailing_metadata(Offset(call_data, op.call_offset),
+ op.channel_data, std::move(md));
+ }
+ return md;
+}
// One call finalizer
struct Finalizer {
@@ -1116,6 +1128,76 @@ class OperationExecutor {
const Operator* end_ops_;
};
+template
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline OperationExecutor<
+ T>::~OperationExecutor() {
+ if (promise_data_ != nullptr) {
+ ops_->early_destroy(promise_data_);
+ gpr_free_aligned(promise_data_);
+ }
+}
+
+template
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline Poll>
+OperationExecutor::Start(const Layout* layout, T input, void* call_data) {
+ ops_ = layout->ops.data();
+ end_ops_ = ops_ + layout->ops.size();
+ if (layout->promise_size == 0) {
+ // No call state ==> instantaneously ready
+ auto r = InitStep(std::move(input), call_data);
+ CHECK(r.ready());
+ return r;
+ }
+ promise_data_ =
+ gpr_malloc_aligned(layout->promise_size, layout->promise_alignment);
+ return InitStep(std::move(input), call_data);
+}
+
+template
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline Poll>
+OperationExecutor::InitStep(T input, void* call_data) {
+ CHECK(input != nullptr);
+ while (true) {
+ if (ops_ == end_ops_) {
+ return ResultOr{std::move(input), nullptr};
+ }
+ auto p =
+ ops_->promise_init(promise_data_, Offset(call_data, ops_->call_offset),
+ ops_->channel_data, std::move(input));
+ if (auto* r = p.value_if_ready()) {
+ if (r->ok == nullptr) return std::move(*r);
+ input = std::move(r->ok);
+ ++ops_;
+ continue;
+ }
+ return Pending{};
+ }
+}
+
+template
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline Poll>
+OperationExecutor::Step(void* call_data) {
+ DCHECK_NE(promise_data_, nullptr);
+ auto p = ContinueStep(call_data);
+ if (p.ready()) {
+ gpr_free_aligned(promise_data_);
+ promise_data_ = nullptr;
+ }
+ return p;
+}
+
+template
+GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline Poll>
+OperationExecutor::ContinueStep(void* call_data) {
+ auto p = ops_->poll(promise_data_);
+ if (auto* r = p.value_if_ready()) {
+ if (r->ok == nullptr) return std::move(*r);
+ ++ops_;
+ return InitStep(std::move(r->ok), call_data);
+ }
+ return Pending{};
+}
+
template
class ServerTrailingMetadataInterceptor {
public:
@@ -1276,8 +1358,20 @@ class CallFilters {
filters_detail::StackData data_;
};
- explicit CallFilters(ClientMetadataHandle client_initial_metadata);
- ~CallFilters();
+ explicit CallFilters(ClientMetadataHandle client_initial_metadata)
+ : call_data_(nullptr),
+ push_client_initial_metadata_(std::move(client_initial_metadata)) {}
+ ~CallFilters() {
+ if (call_data_ != nullptr && call_data_ != &g_empty_call_data_) {
+ for (const auto& stack : stacks_) {
+ for (const auto& destructor : stack.stack->data_.filter_destructor) {
+ destructor.call_destroy(filters_detail::Offset(
+ call_data_, stack.call_data_offset + destructor.call_offset));
+ }
+ }
+ gpr_free_aligned(call_data_);
+ }
+ };
CallFilters(const CallFilters&) = delete;
CallFilters& operator=(const CallFilters&) = delete;
@@ -1528,6 +1622,8 @@ class CallFilters {
MessageHandle push_client_to_server_message_;
MessageHandle push_server_to_client_message_;
ServerMetadataHandle push_server_trailing_metadata_;
+
+ static char g_empty_call_data_;
};
} // namespace grpc_core
From 6dbc0bdb106b3b2c319198194ca7b6f18d88f8ff Mon Sep 17 00:00:00 2001
From: Craig Tiller
Date: Fri, 27 Sep 2024 12:20:36 -0700
Subject: [PATCH 08/74] [chaotic-good] Use a party for internal activities
(#37078)
Allows use of the party <-> party wakeup batching stuff, which reduces threadhops drastically for this transport.
Closes #37078
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37078 from ctiller:chaotic-party-3 75c32e6a6467f41e24d3786980a4aed3e8c93a4c
PiperOrigin-RevId: 679685211
---
src/core/BUILD | 7 +--
.../chaotic_good/client_transport.cc | 45 ++++++-------------
.../transport/chaotic_good/client_transport.h | 6 +--
.../chaotic_good/server_transport.cc | 33 +++++++-------
.../transport/chaotic_good/server_transport.h | 3 +-
src/core/lib/promise/party.cc | 21 ++++++---
src/core/lib/promise/party.h | 2 +
.../chaotic_good/client_transport_test.cc | 12 ++---
.../chaotic_good/mock_promise_endpoint.h | 15 +++++++
.../chaotic_good/server_transport_test.cc | 4 +-
10 files changed, 76 insertions(+), 72 deletions(-)
diff --git a/src/core/BUILD b/src/core/BUILD
index 13091d6bd38..a7ae31fe639 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -7946,7 +7946,7 @@ grpc_cc_library(
"absl/base:core_headers",
"absl/container:flat_hash_map",
"absl/log:check",
- "absl/log:log",
+ "absl/log",
"absl/random",
"absl/random:bit_gen_ref",
"absl/status",
@@ -7957,20 +7957,18 @@ grpc_cc_library(
language = "c++",
deps = [
"activity",
- "all_ok",
"arena",
"chaotic_good_frame",
"chaotic_good_frame_header",
"chaotic_good_transport",
"context",
- "event_engine_wakeup_scheduler",
+ "event_engine_context",
"for_each",
"grpc_promise_endpoint",
"if",
"inter_activity_pipe",
"loop",
"map",
- "match",
"memory_quota",
"metadata_batch",
"mpsc",
@@ -7987,7 +7985,6 @@ grpc_cc_library(
"//:grpc_base",
"//:hpack_encoder",
"//:hpack_parser",
- "//:promise",
"//:ref_counted_ptr",
],
)
diff --git a/src/core/ext/transport/chaotic_good/client_transport.cc b/src/core/ext/transport/chaotic_good/client_transport.cc
index 17aff601d45..28af0d5ba98 100644
--- a/src/core/ext/transport/chaotic_good/client_transport.cc
+++ b/src/core/ext/transport/chaotic_good/client_transport.cc
@@ -36,22 +36,15 @@
#include "src/core/ext/transport/chaotic_good/frame.h"
#include "src/core/ext/transport/chaotic_good/frame_header.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
+#include "src/core/lib/event_engine/event_engine_context.h"
#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/promise/activity.h"
-#include "src/core/lib/promise/all_ok.h"
-#include "src/core/lib/promise/event_engine_wakeup_scheduler.h"
#include "src/core/lib/promise/loop.h"
#include "src/core/lib/promise/map.h"
-#include "src/core/lib/promise/promise.h"
-#include "src/core/lib/promise/try_join.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/resource_quota.h"
-#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_buffer.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/promise_endpoint.h"
-#include "src/core/util/match.h"
#include "src/core/util/ref_counted_ptr.h"
namespace grpc_core {
@@ -59,15 +52,12 @@ namespace chaotic_good {
void ChaoticGoodClientTransport::Orphan() {
AbortWithError();
- ActivityPtr writer;
- ActivityPtr reader;
+ RefCountedPtr party;
{
MutexLock lock(&mu_);
- writer = std::move(writer_);
- reader = std::move(reader_);
+ party = std::move(party_);
}
- writer.reset();
- reader.reset();
+ party.reset();
Unref();
}
@@ -211,25 +201,18 @@ ChaoticGoodClientTransport::ChaoticGoodClientTransport(
auto transport = MakeRefCounted(
std::move(control_endpoint), std::move(data_endpoint),
std::move(hpack_parser), std::move(hpack_encoder));
- writer_ = MakeActivity(
- // Continuously write next outgoing frames to promise endpoints.
- TransportWriteLoop(transport), EventEngineWakeupScheduler(event_engine),
- OnTransportActivityDone("write_loop"));
- reader_ = MakeActivity(
- // Continuously read next incoming frames from promise endpoints.
- TransportReadLoop(std::move(transport)),
- EventEngineWakeupScheduler(event_engine),
- OnTransportActivityDone("read_loop"));
+ auto party_arena = SimpleArenaAllocator(0)->MakeArena();
+ party_arena->SetContext(
+ event_engine.get());
+ party_ = Party::Make(std::move(party_arena));
+ party_->Spawn("client-chaotic-writer", TransportWriteLoop(transport),
+ OnTransportActivityDone("write_loop"));
+ party_->Spawn("client-chaotic-reader",
+ TransportReadLoop(std::move(transport)),
+ OnTransportActivityDone("read_loop"));
}
-ChaoticGoodClientTransport::~ChaoticGoodClientTransport() {
- if (writer_ != nullptr) {
- writer_.reset();
- }
- if (reader_ != nullptr) {
- reader_.reset();
- }
-}
+ChaoticGoodClientTransport::~ChaoticGoodClientTransport() { party_.reset(); }
void ChaoticGoodClientTransport::AbortWithError() {
// Mark transport as unavailable when the endpoint write/read failed.
diff --git a/src/core/ext/transport/chaotic_good/client_transport.h b/src/core/ext/transport/chaotic_good/client_transport.h
index 8f2941947d3..f223c551002 100644
--- a/src/core/ext/transport/chaotic_good/client_transport.h
+++ b/src/core/ext/transport/chaotic_good/client_transport.h
@@ -88,9 +88,6 @@ class ChaoticGoodClientTransport final : public ClientTransport {
void AbortWithError();
private:
- // Queue size of each stream pipe is set to 2, so that for each stream read it
- // will queue at most 2 frames.
- static const size_t kServerFrameQueueSize = 2;
using StreamMap = absl::flat_hash_map;
uint32_t MakeStream(CallHandler call_handler);
@@ -112,8 +109,7 @@ class ChaoticGoodClientTransport final : public ClientTransport {
uint32_t next_stream_id_ ABSL_GUARDED_BY(mu_) = 1;
// Map of stream incoming server frames, key is stream_id.
StreamMap stream_map_ ABSL_GUARDED_BY(mu_);
- ActivityPtr writer_;
- ActivityPtr reader_;
+ RefCountedPtr party_;
ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(mu_){
"chaotic_good_client", GRPC_CHANNEL_READY};
};
diff --git a/src/core/ext/transport/chaotic_good/server_transport.cc b/src/core/ext/transport/chaotic_good/server_transport.cc
index 4110af2fbcc..6588227a264 100644
--- a/src/core/ext/transport/chaotic_good/server_transport.cc
+++ b/src/core/ext/transport/chaotic_good/server_transport.cc
@@ -356,12 +356,14 @@ ChaoticGoodServerTransport::ChaoticGoodServerTransport(
auto transport = MakeRefCounted(
std::move(control_endpoint), std::move(data_endpoint),
std::move(hpack_parser), std::move(hpack_encoder));
- writer_ = MakeActivity(TransportWriteLoop(transport),
- EventEngineWakeupScheduler(event_engine),
- OnTransportActivityDone("writer"));
- reader_ = MakeActivity(TransportReadLoop(std::move(transport)),
- EventEngineWakeupScheduler(event_engine),
- OnTransportActivityDone("reader"));
+ auto party_arena = SimpleArenaAllocator(0)->MakeArena();
+ party_arena->SetContext(
+ event_engine.get());
+ party_ = Party::Make(std::move(party_arena));
+ party_->Spawn("server-chaotic-writer", TransportWriteLoop(transport),
+ OnTransportActivityDone("writer"));
+ party_->Spawn("server-chaotic-reader", TransportReadLoop(transport),
+ OnTransportActivityDone("reader"));
}
void ChaoticGoodServerTransport::SetCallDestination(
@@ -373,15 +375,13 @@ void ChaoticGoodServerTransport::SetCallDestination(
}
void ChaoticGoodServerTransport::Orphan() {
- ActivityPtr writer;
- ActivityPtr reader;
+ AbortWithError();
+ RefCountedPtr party;
{
MutexLock lock(&mu_);
- writer = std::move(writer_);
- reader = std::move(reader_);
+ party = std::move(party_);
}
- writer.reset();
- reader.reset();
+ party.reset();
Unref();
}
@@ -461,7 +461,7 @@ absl::Status ChaoticGoodServerTransport::NewStream(
}
void ChaoticGoodServerTransport::PerformOp(grpc_transport_op* op) {
- std::vector cancelled;
+ RefCountedPtr cancelled_party;
MutexLock lock(&mu_);
bool did_stuff = false;
if (op->start_connectivity_watch != nullptr) {
@@ -482,8 +482,11 @@ void ChaoticGoodServerTransport::PerformOp(grpc_transport_op* op) {
did_stuff = true;
}
if (!op->goaway_error.ok() || !op->disconnect_with_error.ok()) {
- cancelled.push_back(std::move(writer_));
- cancelled.push_back(std::move(reader_));
+ cancelled_party = std::move(party_);
+ outgoing_frames_.MarkClosed();
+ state_tracker_.SetState(GRPC_CHANNEL_SHUTDOWN,
+ absl::UnavailableError("transport closed"),
+ "transport closed");
did_stuff = true;
}
if (!did_stuff) {
diff --git a/src/core/ext/transport/chaotic_good/server_transport.h b/src/core/ext/transport/chaotic_good/server_transport.h
index 23909768b68..d8244ab32fe 100644
--- a/src/core/ext/transport/chaotic_good/server_transport.h
+++ b/src/core/ext/transport/chaotic_good/server_transport.h
@@ -146,8 +146,7 @@ class ChaoticGoodServerTransport final : public ServerTransport {
// Map of stream incoming server frames, key is stream_id.
StreamMap stream_map_ ABSL_GUARDED_BY(mu_);
uint32_t last_seen_new_stream_id_ = 0;
- ActivityPtr writer_ ABSL_GUARDED_BY(mu_);
- ActivityPtr reader_ ABSL_GUARDED_BY(mu_);
+ RefCountedPtr party_;
ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(mu_){
"chaotic_good_server", GRPC_CHANNEL_READY};
};
diff --git a/src/core/lib/promise/party.cc b/src/core/lib/promise/party.cc
index cfc34ebedee..79c310c9806 100644
--- a/src/core/lib/promise/party.cc
+++ b/src/core/lib/promise/party.cc
@@ -149,15 +149,24 @@ Party::Participant::~Participant() {
Party::~Party() {}
void Party::CancelRemainingParticipants() {
- if ((state_.load(std::memory_order_relaxed) & kAllocatedMask) == 0) return;
+ uint64_t prev_state = state_.load(std::memory_order_relaxed);
+ if ((prev_state & kAllocatedMask) == 0) return;
ScopedActivity activity(this);
promise_detail::Context arena_ctx(arena_.get());
- for (size_t i = 0; i < party_detail::kMaxParticipants; i++) {
- if (auto* p =
- participants_[i].exchange(nullptr, std::memory_order_acquire)) {
- p->Destroy();
+ uint64_t clear_state = 0;
+ do {
+ for (size_t i = 0; i < party_detail::kMaxParticipants; i++) {
+ if (auto* p =
+ participants_[i].exchange(nullptr, std::memory_order_acquire)) {
+ clear_state |= 1ull << i << kAllocatedShift;
+ p->Destroy();
+ }
}
- }
+ if (clear_state == 0) return;
+ } while (!state_.compare_exchange_weak(prev_state, prev_state & ~clear_state,
+ std::memory_order_acq_rel));
+ LogStateChange("CancelRemainingParticipants", prev_state,
+ prev_state & ~clear_state);
}
std::string Party::ActivityDebugTag(WakeupMask wakeup_mask) const {
diff --git a/src/core/lib/promise/party.h b/src/core/lib/promise/party.h
index a38467a924b..d2051aa6083 100644
--- a/src/core/lib/promise/party.h
+++ b/src/core/lib/promise/party.h
@@ -430,12 +430,14 @@ void Party::BulkSpawner::Spawn(absl::string_view name, Factory promise_factory,
template
void Party::Spawn(absl::string_view name, Factory promise_factory,
OnComplete on_complete) {
+ GRPC_TRACE_LOG(party_state, INFO) << "PARTY[" << this << "]: spawn " << name;
AddParticipant(new ParticipantImpl(
name, std::move(promise_factory), std::move(on_complete)));
}
template
auto Party::SpawnWaitable(absl::string_view name, Factory promise_factory) {
+ GRPC_TRACE_LOG(party_state, INFO) << "PARTY[" << this << "]: spawn " << name;
auto participant = MakeRefCounted>(
name, std::move(promise_factory));
Participant* p = participant->Ref().release();
diff --git a/test/core/transport/chaotic_good/client_transport_test.cc b/test/core/transport/chaotic_good/client_transport_test.cc
index d4f7037b733..aad18ee1601 100644
--- a/test/core/transport/chaotic_good/client_transport_test.cc
+++ b/test/core/transport/chaotic_good/client_transport_test.cc
@@ -102,8 +102,8 @@ ChannelArgs MakeChannelArgs() {
}
TEST_F(TransportTest, AddOneStream) {
- MockPromiseEndpoint control_endpoint;
- MockPromiseEndpoint data_endpoint;
+ MockPromiseEndpoint control_endpoint(1000);
+ MockPromiseEndpoint data_endpoint(1001);
control_endpoint.ExpectRead(
{SerializedFrameHeader(FrameType::kFragment, 7, 1, 26, 8, 56, 15),
EventEngineSlice::FromCopiedBuffer(kPathDemoServiceStep,
@@ -120,7 +120,6 @@ TEST_F(TransportTest, AddOneStream) {
std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
event_engine(), HPackParser(), HPackCompressor());
auto call = MakeCall(TestInitialMetadata());
- transport->StartCall(call.handler.StartCall());
StrictMock> on_done;
EXPECT_CALL(on_done, Call());
control_endpoint.ExpectWrite(
@@ -136,6 +135,7 @@ TEST_F(TransportTest, AddOneStream) {
{EventEngineSlice::FromCopiedString("0"), Zeros(63)}, nullptr);
control_endpoint.ExpectWrite(
{SerializedFrameHeader(FrameType::kFragment, 4, 1, 0, 0, 0, 0)}, nullptr);
+ transport->StartCall(call.handler.StartCall());
call.initiator.SpawnGuarded("test-send",
[initiator = call.initiator]() mutable {
return SendClientToServerMessages(initiator, 1);
@@ -183,8 +183,8 @@ TEST_F(TransportTest, AddOneStream) {
}
TEST_F(TransportTest, AddOneStreamMultipleMessages) {
- MockPromiseEndpoint control_endpoint;
- MockPromiseEndpoint data_endpoint;
+ MockPromiseEndpoint control_endpoint(1000);
+ MockPromiseEndpoint data_endpoint(1001);
control_endpoint.ExpectRead(
{SerializedFrameHeader(FrameType::kFragment, 3, 1, 26, 8, 56, 0),
EventEngineSlice::FromCopiedBuffer(kPathDemoServiceStep,
@@ -206,7 +206,6 @@ TEST_F(TransportTest, AddOneStreamMultipleMessages) {
std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
event_engine(), HPackParser(), HPackCompressor());
auto call = MakeCall(TestInitialMetadata());
- transport->StartCall(call.handler.StartCall());
StrictMock> on_done;
EXPECT_CALL(on_done, Call());
control_endpoint.ExpectWrite(
@@ -227,6 +226,7 @@ TEST_F(TransportTest, AddOneStreamMultipleMessages) {
{EventEngineSlice::FromCopiedString("1"), Zeros(63)}, nullptr);
control_endpoint.ExpectWrite(
{SerializedFrameHeader(FrameType::kFragment, 4, 1, 0, 0, 0, 0)}, nullptr);
+ transport->StartCall(call.handler.StartCall());
call.initiator.SpawnGuarded("test-send",
[initiator = call.initiator]() mutable {
return SendClientToServerMessages(initiator, 2);
diff --git a/test/core/transport/chaotic_good/mock_promise_endpoint.h b/test/core/transport/chaotic_good/mock_promise_endpoint.h
index d90133feb9d..bf073e4644f 100644
--- a/test/core/transport/chaotic_good/mock_promise_endpoint.h
+++ b/test/core/transport/chaotic_good/mock_promise_endpoint.h
@@ -20,6 +20,7 @@
#include
+#include "src/core/lib/event_engine/tcp_socket_utils.h"
#include "src/core/lib/transport/promise_endpoint.h"
namespace grpc_core {
@@ -54,6 +55,20 @@ class MockEndpoint
};
struct MockPromiseEndpoint {
+ explicit MockPromiseEndpoint(int port) {
+ if (GRPC_TRACE_FLAG_ENABLED(chaotic_good)) {
+ EXPECT_CALL(*endpoint, GetPeerAddress)
+ .WillRepeatedly(
+ [peer_address =
+ std::make_shared(
+ grpc_event_engine::experimental::URIToResolvedAddress(
+ absl::StrCat("ipv4:127.0.0.1:", port))
+ .value())]()
+ -> const grpc_event_engine::experimental::EventEngine::
+ ResolvedAddress& { return *peer_address; });
+ }
+ }
::testing::StrictMock* endpoint =
new ::testing::StrictMock();
PromiseEndpoint promise_endpoint = PromiseEndpoint(
diff --git a/test/core/transport/chaotic_good/server_transport_test.cc b/test/core/transport/chaotic_good/server_transport_test.cc
index af5b223c2fb..f3ab7f3a350 100644
--- a/test/core/transport/chaotic_good/server_transport_test.cc
+++ b/test/core/transport/chaotic_good/server_transport_test.cc
@@ -91,8 +91,8 @@ class MockCallDestination : public UnstartedCallDestination {
};
TEST_F(TransportTest, ReadAndWriteOneMessage) {
- MockPromiseEndpoint control_endpoint;
- MockPromiseEndpoint data_endpoint;
+ MockPromiseEndpoint control_endpoint(1);
+ MockPromiseEndpoint data_endpoint(2);
auto call_destination = MakeRefCounted>();
EXPECT_CALL(*call_destination, Orphaned()).Times(1);
auto transport = MakeOrphanable(
From e56d766a45a61e6b476958ad0bb68e2d022dcfbb Mon Sep 17 00:00:00 2001
From: "Mark D. Roth"
Date: Fri, 27 Sep 2024 13:23:29 -0700
Subject: [PATCH 09/74] [GCP auth filter] add "blackboard" mechanism for
retaining global state, and use it for cache in GCP auth filter (#37646)
This is the last piece of gRFC A83 (https://github.com/grpc/proposal/pull/438).
Note that although this is the first use-case for this "blackboard" mechanism, we will also use it in the future for the xDS rate-limiting filter on the gRPC server side.
Closes #37646
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37646 from markdroth:gcp_auth_filter_state 72d0d96c79f1576a0085f1887829ffcab93fe5ff
PiperOrigin-RevId: 679707134
---
BUILD | 2 +
CMakeLists.txt | 62 ++++++++++++++++
Makefile | 1 +
Package.swift | 2 +
build_autogenerated.yaml | 57 +++++++++++++++
config.m4 | 2 +
config.w32 | 2 +
gRPC-C++.podspec | 2 +
gRPC-Core.podspec | 3 +
grpc.gemspec | 2 +
package.xml | 2 +
src/core/BUILD | 24 +++++++
src/core/client_channel/client_channel.cc | 7 +-
src/core/client_channel/client_channel.h | 3 +
.../client_channel/client_channel_filter.cc | 7 +-
.../client_channel/client_channel_filter.h | 3 +
src/core/client_channel/dynamic_filters.cc | 12 ++--
src/core/client_channel/dynamic_filters.h | 4 +-
.../gcp_authentication_filter.cc | 62 ++++++++++++----
.../gcp_authentication_filter.h | 32 ++++++---
src/core/filter/blackboard.cc | 33 +++++++++
src/core/filter/blackboard.h | 71 +++++++++++++++++++
src/core/lib/channel/channel_stack.cc | 5 +-
src/core/lib/channel/channel_stack.h | 17 ++---
.../lib/channel/channel_stack_builder_impl.cc | 2 +-
.../lib/channel/channel_stack_builder_impl.h | 13 ++++
src/core/lib/channel/promise_based_filter.h | 39 ++++++++--
src/core/lib/transport/interception_chain.h | 17 +++--
src/core/util/lru_cache.h | 36 +++++++---
src/python/grpcio/grpc_core_dependencies.py | 1 +
test/core/filters/BUILD | 13 ++++
test/core/filters/blackboard_test.cc | 66 +++++++++++++++++
test/core/util/lru_cache_test.cc | 33 +++++++++
.../end2end/xds/xds_gcp_authn_end2end_test.cc | 69 ++++++++++++++++++
tools/doxygen/Doxyfile.c++.internal | 2 +
tools/doxygen/Doxyfile.core.internal | 2 +
tools/run_tests/generated/tests.json | 24 +++++++
37 files changed, 675 insertions(+), 59 deletions(-)
create mode 100644 src/core/filter/blackboard.cc
create mode 100644 src/core/filter/blackboard.h
create mode 100644 test/core/filters/blackboard_test.cc
diff --git a/BUILD b/BUILD
index 17b278b61e6..c2d1c88a7d6 100644
--- a/BUILD
+++ b/BUILD
@@ -2043,6 +2043,7 @@ grpc_cc_library(
"//src/core:arena_promise",
"//src/core:atomic_utils",
"//src/core:bitset",
+ "//src/core:blackboard",
"//src/core:call_destination",
"//src/core:call_filters",
"//src/core:call_final_info",
@@ -3780,6 +3781,7 @@ grpc_cc_library(
"//src/core:arena",
"//src/core:arena_promise",
"//src/core:backend_metric_parser",
+ "//src/core:blackboard",
"//src/core:call_destination",
"//src/core:call_filters",
"//src/core:call_spine",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3836f7beac9..ec604861f22 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -960,6 +960,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx binder_server_test)
add_dependencies(buildtests_cxx binder_transport_test)
add_dependencies(buildtests_cxx bitset_test)
+ add_dependencies(buildtests_cxx blackboard_test)
add_dependencies(buildtests_cxx buffer_list_test)
add_dependencies(buildtests_cxx byte_buffer_test)
add_dependencies(buildtests_cxx c_slice_buffer_test)
@@ -2246,6 +2247,7 @@ add_library(grpc
src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c
src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.c
src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c
+ src/core/filter/blackboard.cc
src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
src/core/handshaker/handshaker.cc
src/core/handshaker/handshaker_registry.cc
@@ -3053,6 +3055,7 @@ add_library(grpc_unsecure
src/core/ext/upb-gen/validate/validate.upb_minitable.c
src/core/ext/upb-gen/xds/data/orca/v3/orca_load_report.upb_minitable.c
src/core/ext/upb-gen/xds/service/orca/v3/orca.upb_minitable.c
+ src/core/filter/blackboard.cc
src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
src/core/handshaker/handshaker.cc
src/core/handshaker/handshaker_registry.cc
@@ -5280,6 +5283,7 @@ add_library(grpc_authorization_provider
src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+ src/core/filter/blackboard.cc
src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
src/core/handshaker/handshaker.cc
src/core/handshaker/handshaker_registry.cc
@@ -8406,6 +8410,63 @@ target_link_libraries(bitset_test
)
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(blackboard_test
+ src/core/filter/blackboard.cc
+ src/core/lib/address_utils/sockaddr_utils.cc
+ src/core/lib/channel/channel_args.cc
+ src/core/lib/iomgr/sockaddr_utils_posix.cc
+ src/core/lib/iomgr/socket_utils_windows.cc
+ src/core/lib/surface/channel_stack_type.cc
+ src/core/resolver/endpoint_addresses.cc
+ src/core/util/ref_counted_string.cc
+ src/core/util/time.cc
+ src/core/util/uri.cc
+ test/core/filters/blackboard_test.cc
+)
+if(WIN32 AND MSVC)
+ if(BUILD_SHARED_LIBS)
+ target_compile_definitions(blackboard_test
+ PRIVATE
+ "GPR_DLL_IMPORTS"
+ )
+ endif()
+endif()
+target_compile_features(blackboard_test PUBLIC cxx_std_14)
+target_include_directories(blackboard_test
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ ${_gRPC_RE2_INCLUDE_DIR}
+ ${_gRPC_SSL_INCLUDE_DIR}
+ ${_gRPC_UPB_GENERATED_DIR}
+ ${_gRPC_UPB_GRPC_GENERATED_DIR}
+ ${_gRPC_UPB_INCLUDE_DIR}
+ ${_gRPC_XXHASH_INCLUDE_DIR}
+ ${_gRPC_ZLIB_INCLUDE_DIR}
+ third_party/googletest/googletest/include
+ third_party/googletest/googletest
+ third_party/googletest/googlemock/include
+ third_party/googletest/googlemock
+ ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(blackboard_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ gtest
+ absl::config
+ absl::flat_hash_map
+ absl::function_ref
+ absl::hash
+ absl::type_traits
+ absl::statusor
+ gpr
+)
+
+
endif()
if(gRPC_BUILD_TESTS)
@@ -9012,6 +9073,7 @@ add_executable(call_utils_test
src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+ src/core/filter/blackboard.cc
src/core/handshaker/handshaker_registry.cc
src/core/handshaker/proxy_mapper_registry.cc
src/core/lib/address_utils/parse_address.cc
diff --git a/Makefile b/Makefile
index 70828125ba2..078484c1fd6 100644
--- a/Makefile
+++ b/Makefile
@@ -1057,6 +1057,7 @@ LIBGRPC_SRC = \
src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c \
src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.c \
src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c \
+ src/core/filter/blackboard.cc \
src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc \
src/core/handshaker/handshaker.cc \
src/core/handshaker/handshaker_registry.cc \
diff --git a/Package.swift b/Package.swift
index 8b1ae1392cc..c21dedc5f8b 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1070,6 +1070,8 @@ let package = Package(
"src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h",
"src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c",
"src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h",
+ "src/core/filter/blackboard.cc",
+ "src/core/filter/blackboard.h",
"src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc",
"src/core/handshaker/endpoint_info/endpoint_info_handshaker.h",
"src/core/handshaker/handshaker.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 33b9da00c33..b45eb26192f 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -781,6 +781,7 @@ libs:
- src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.h
- src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h
- src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h
+ - src/core/filter/blackboard.h
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.h
- src/core/handshaker/handshaker.h
- src/core/handshaker/handshaker_factory.h
@@ -1662,6 +1663,7 @@ libs:
- src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c
- src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.c
- src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c
+ - src/core/filter/blackboard.cc
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
- src/core/handshaker/handshaker.cc
- src/core/handshaker/handshaker_registry.cc
@@ -2359,6 +2361,7 @@ libs:
- src/core/ext/upb-gen/xds/data/orca/v3/orca_load_report.upb_minitable.h
- src/core/ext/upb-gen/xds/service/orca/v3/orca.upb.h
- src/core/ext/upb-gen/xds/service/orca/v3/orca.upb_minitable.h
+ - src/core/filter/blackboard.h
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.h
- src/core/handshaker/handshaker.h
- src/core/handshaker/handshaker_factory.h
@@ -2819,6 +2822,7 @@ libs:
- src/core/ext/upb-gen/validate/validate.upb_minitable.c
- src/core/ext/upb-gen/xds/data/orca/v3/orca_load_report.upb_minitable.c
- src/core/ext/upb-gen/xds/service/orca/v3/orca.upb_minitable.c
+ - src/core/filter/blackboard.cc
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
- src/core/handshaker/handshaker.cc
- src/core/handshaker/handshaker_registry.cc
@@ -4467,6 +4471,7 @@ libs:
- src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.h
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb.h
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.h
+ - src/core/filter/blackboard.h
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.h
- src/core/handshaker/handshaker.h
- src/core/handshaker/handshaker_factory.h
@@ -4803,6 +4808,7 @@ libs:
- src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
- src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+ - src/core/filter/blackboard.cc
- src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc
- src/core/handshaker/handshaker.cc
- src/core/handshaker/handshaker_registry.cc
@@ -6278,6 +6284,55 @@ targets:
- absl/log:check
- absl/numeric:bits
uses_polling: false
+- name: blackboard_test
+ gtest: true
+ build: test
+ language: c++
+ headers:
+ - src/core/filter/blackboard.h
+ - src/core/lib/address_utils/sockaddr_utils.h
+ - src/core/lib/channel/channel_args.h
+ - src/core/lib/iomgr/port.h
+ - src/core/lib/iomgr/resolved_address.h
+ - src/core/lib/iomgr/sockaddr.h
+ - src/core/lib/iomgr/sockaddr_posix.h
+ - src/core/lib/iomgr/sockaddr_windows.h
+ - src/core/lib/iomgr/socket_utils.h
+ - src/core/lib/surface/channel_stack_type.h
+ - src/core/resolver/endpoint_addresses.h
+ - src/core/util/atomic_utils.h
+ - src/core/util/avl.h
+ - src/core/util/down_cast.h
+ - src/core/util/dual_ref_counted.h
+ - src/core/util/orphanable.h
+ - src/core/util/ref_counted.h
+ - src/core/util/ref_counted_ptr.h
+ - src/core/util/ref_counted_string.h
+ - src/core/util/time.h
+ - src/core/util/unique_type_name.h
+ - src/core/util/uri.h
+ src:
+ - src/core/filter/blackboard.cc
+ - src/core/lib/address_utils/sockaddr_utils.cc
+ - src/core/lib/channel/channel_args.cc
+ - src/core/lib/iomgr/sockaddr_utils_posix.cc
+ - src/core/lib/iomgr/socket_utils_windows.cc
+ - src/core/lib/surface/channel_stack_type.cc
+ - src/core/resolver/endpoint_addresses.cc
+ - src/core/util/ref_counted_string.cc
+ - src/core/util/time.cc
+ - src/core/util/uri.cc
+ - test/core/filters/blackboard_test.cc
+ deps:
+ - gtest
+ - absl/base:config
+ - absl/container:flat_hash_map
+ - absl/functional:function_ref
+ - absl/hash:hash
+ - absl/meta:type_traits
+ - absl/status:statusor
+ - gpr
+ uses_polling: false
- name: buffer_list_test
gtest: true
build: test
@@ -6738,6 +6793,7 @@ targets:
- src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.h
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb.h
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.h
+ - src/core/filter/blackboard.h
- src/core/handshaker/handshaker_factory.h
- src/core/handshaker/handshaker_registry.h
- src/core/handshaker/proxy_mapper.h
@@ -7043,6 +7099,7 @@ targets:
- src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
- src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
- src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+ - src/core/filter/blackboard.cc
- src/core/handshaker/handshaker_registry.cc
- src/core/handshaker/proxy_mapper_registry.cc
- src/core/lib/address_utils/parse_address.cc
diff --git a/config.m4 b/config.m4
index a5d57181f70..ae67f344840 100644
--- a/config.m4
+++ b/config.m4
@@ -432,6 +432,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c \
src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.c \
src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c \
+ src/core/filter/blackboard.cc \
src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc \
src/core/handshaker/handshaker.cc \
src/core/handshaker/handshaker_registry.cc \
@@ -1528,6 +1529,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-gen/xds/core/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-gen/xds/type/matcher/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-gen/xds/type/v3)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/filter)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/handshaker)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/handshaker/endpoint_info)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/handshaker/http_connect)
diff --git a/config.w32 b/config.w32
index c0acf9bfb23..94e02c3e172 100644
--- a/config.w32
+++ b/config.w32
@@ -397,6 +397,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\upbdefs-gen\\xds\\type\\v3\\cel.upbdefs.c " +
"src\\core\\ext\\upbdefs-gen\\xds\\type\\v3\\range.upbdefs.c " +
"src\\core\\ext\\upbdefs-gen\\xds\\type\\v3\\typed_struct.upbdefs.c " +
+ "src\\core\\filter\\blackboard.cc " +
"src\\core\\handshaker\\endpoint_info\\endpoint_info_handshaker.cc " +
"src\\core\\handshaker\\handshaker.cc " +
"src\\core\\handshaker\\handshaker_registry.cc " +
@@ -1666,6 +1667,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-gen\\xds\\type\\matcher");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-gen\\xds\\type\\matcher\\v3");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-gen\\xds\\type\\v3");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\filter");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\handshaker");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\handshaker\\endpoint_info");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\handshaker\\http_connect");
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 481f51c2ea4..a63753dd7d1 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -870,6 +870,7 @@ Pod::Spec.new do |s|
'src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h',
+ 'src/core/filter/blackboard.h',
'src/core/handshaker/endpoint_info/endpoint_info_handshaker.h',
'src/core/handshaker/handshaker.h',
'src/core/handshaker/handshaker_factory.h',
@@ -2173,6 +2174,7 @@ Pod::Spec.new do |s|
'src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h',
+ 'src/core/filter/blackboard.h',
'src/core/handshaker/endpoint_info/endpoint_info_handshaker.h',
'src/core/handshaker/handshaker.h',
'src/core/handshaker/handshaker_factory.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 2867cb57323..5eda92de512 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1190,6 +1190,8 @@ Pod::Spec.new do |s|
'src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c',
'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h',
+ 'src/core/filter/blackboard.cc',
+ 'src/core/filter/blackboard.h',
'src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc',
'src/core/handshaker/endpoint_info/endpoint_info_handshaker.h',
'src/core/handshaker/handshaker.cc',
@@ -2960,6 +2962,7 @@ Pod::Spec.new do |s|
'src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h',
'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h',
+ 'src/core/filter/blackboard.h',
'src/core/handshaker/endpoint_info/endpoint_info_handshaker.h',
'src/core/handshaker/handshaker.h',
'src/core/handshaker/handshaker_factory.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index bd39eda2bda..3ba44548b25 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1076,6 +1076,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.h )
s.files += %w( src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c )
s.files += %w( src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.h )
+ s.files += %w( src/core/filter/blackboard.cc )
+ s.files += %w( src/core/filter/blackboard.h )
s.files += %w( src/core/handshaker/endpoint_info/endpoint_info_handshaker.cc )
s.files += %w( src/core/handshaker/endpoint_info/endpoint_info_handshaker.h )
s.files += %w( src/core/handshaker/handshaker.cc )
diff --git a/package.xml b/package.xml
index befa4e97aa3..76be79fd6b5 100644
--- a/package.xml
+++ b/package.xml
@@ -1058,6 +1058,8 @@
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index a7ae31fe639..0de80c1f68a 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -3309,6 +3309,29 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "blackboard",
+ srcs = [
+ "filter/blackboard.cc",
+ ],
+ hdrs = [
+ "filter/blackboard.h",
+ ],
+ external_deps = [
+ "absl/container:flat_hash_map",
+ "absl/strings",
+ ],
+ language = "c++",
+ deps = [
+ "ref_counted",
+ "unique_type_name",
+ "useful",
+ "//:debug_location",
+ "//:endpoint_addresses",
+ "//:ref_counted_ptr",
+ ],
+)
+
grpc_cc_library(
name = "subchannel_connector",
hdrs = [
@@ -5034,6 +5057,7 @@ grpc_cc_library(
language = "c++",
deps = [
"arena",
+ "blackboard",
"channel_args",
"channel_fwd",
"context",
diff --git a/src/core/client_channel/client_channel.cc b/src/core/client_channel/client_channel.cc
index bf87078b474..0d12c4b292a 100644
--- a/src/core/client_channel/client_channel.cc
+++ b/src/core/client_channel/client_channel.cc
@@ -1279,8 +1279,12 @@ void ClientChannel::UpdateServiceConfigInDataPlaneLocked(
config_selector =
MakeRefCounted(saved_service_config_);
}
+ // Modify channel args.
+ ChannelArgs new_args = args.SetObject(this).SetObject(saved_service_config_);
// Construct filter stack.
- InterceptionChainBuilder builder(args.SetObject(this));
+ auto new_blackboard = MakeRefCounted();
+ InterceptionChainBuilder builder(new_args, blackboard_.get(),
+ new_blackboard.get());
if (idle_timeout_ != Duration::Zero()) {
builder.AddOnServerTrailingMetadata([this](ServerMetadata&) {
if (idle_state_.DecreaseCallCount()) StartIdleTimer();
@@ -1300,6 +1304,7 @@ void ClientChannel::UpdateServiceConfigInDataPlaneLocked(
}
// Create call destination.
auto top_of_stack_call_destination = builder.Build(call_destination_);
+ blackboard_ = std::move(new_blackboard);
// Send result to data plane.
if (!top_of_stack_call_destination.ok()) {
resolver_data_for_calls_.Set(MaybeRewriteIllegalStatusCode(
diff --git a/src/core/client_channel/client_channel.h b/src/core/client_channel/client_channel.h
index f268f6bfcb7..a7f7d75c705 100644
--- a/src/core/client_channel/client_channel.h
+++ b/src/core/client_channel/client_channel.h
@@ -27,6 +27,7 @@
#include "src/core/client_channel/config_selector.h"
#include "src/core/client_channel/subchannel.h"
#include "src/core/ext/filters/channel_idle/idle_filter_state.h"
+#include "src/core/filter/blackboard.h"
#include "src/core/lib/promise/observable.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/metadata.h"
@@ -215,6 +216,8 @@ class ClientChannel : public Channel {
ABSL_GUARDED_BY(*work_serializer_);
RefCountedPtr saved_config_selector_
ABSL_GUARDED_BY(*work_serializer_);
+ RefCountedPtr blackboard_
+ ABSL_GUARDED_BY(*work_serializer_);
OrphanablePtr lb_policy_
ABSL_GUARDED_BY(*work_serializer_);
RefCountedPtr subchannel_pool_
diff --git a/src/core/client_channel/client_channel_filter.cc b/src/core/client_channel/client_channel_filter.cc
index 8bedc588914..82caeb27ffc 100644
--- a/src/core/client_channel/client_channel_filter.cc
+++ b/src/core/client_channel/client_channel_filter.cc
@@ -1498,6 +1498,7 @@ void ClientChannelFilter::UpdateServiceConfigInDataPlaneLocked(
config_selector =
MakeRefCounted(saved_service_config_);
}
+ // Modify channel args.
ChannelArgs new_args = args.SetObject(this).SetObject(service_config);
bool enable_retries =
!new_args.WantMinimalStack() &&
@@ -1510,9 +1511,11 @@ void ClientChannelFilter::UpdateServiceConfigInDataPlaneLocked(
} else {
filters.push_back(&DynamicTerminationFilter::kFilterVtable);
}
- RefCountedPtr dynamic_filters =
- DynamicFilters::Create(new_args, std::move(filters));
+ auto new_blackboard = MakeRefCounted();
+ RefCountedPtr dynamic_filters = DynamicFilters::Create(
+ new_args, std::move(filters), blackboard_.get(), new_blackboard.get());
CHECK(dynamic_filters != nullptr);
+ blackboard_ = std::move(new_blackboard);
// Grab data plane lock to update service config.
//
// We defer unreffing the old values (and deallocating memory) until
diff --git a/src/core/client_channel/client_channel_filter.h b/src/core/client_channel/client_channel_filter.h
index 2741006a38a..0ca401df455 100644
--- a/src/core/client_channel/client_channel_filter.h
+++ b/src/core/client_channel/client_channel_filter.h
@@ -43,6 +43,7 @@
#include "src/core/client_channel/dynamic_filters.h"
#include "src/core/client_channel/subchannel.h"
#include "src/core/client_channel/subchannel_pool_interface.h"
+#include "src/core/filter/blackboard.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/channel/channel_stack.h"
@@ -316,6 +317,8 @@ class ClientChannelFilter final {
ABSL_GUARDED_BY(*work_serializer_);
RefCountedPtr saved_config_selector_
ABSL_GUARDED_BY(*work_serializer_);
+ RefCountedPtr blackboard_
+ ABSL_GUARDED_BY(*work_serializer_);
OrphanablePtr lb_policy_
ABSL_GUARDED_BY(*work_serializer_);
RefCountedPtr subchannel_pool_
diff --git a/src/core/client_channel/dynamic_filters.cc b/src/core/client_channel/dynamic_filters.cc
index 45e7d4ffcbc..c2825925fa4 100644
--- a/src/core/client_channel/dynamic_filters.cc
+++ b/src/core/client_channel/dynamic_filters.cc
@@ -139,8 +139,10 @@ void DynamicFilters::Call::IncrementRefCount(const DebugLocation& /*location*/,
namespace {
absl::StatusOr> CreateChannelStack(
- const ChannelArgs& args, std::vector filters) {
+ const ChannelArgs& args, std::vector filters,
+ const Blackboard* old_blackboard, Blackboard* new_blackboard) {
ChannelStackBuilderImpl builder("DynamicFilters", GRPC_CLIENT_DYNAMIC, args);
+ builder.SetBlackboards(old_blackboard, new_blackboard);
for (auto filter : filters) {
builder.AppendFilter(filter);
}
@@ -150,15 +152,17 @@ absl::StatusOr> CreateChannelStack(
} // namespace
RefCountedPtr DynamicFilters::Create(
- const ChannelArgs& args, std::vector filters) {
+ const ChannelArgs& args, std::vector filters,
+ const Blackboard* old_blackboard, Blackboard* new_blackboard) {
// Attempt to create channel stack from requested filters.
- auto p = CreateChannelStack(args, std::move(filters));
+ auto p = CreateChannelStack(args, std::move(filters), old_blackboard,
+ new_blackboard);
if (!p.ok()) {
// Channel stack creation failed with requested filters.
// Create with lame filter instead.
auto error = p.status();
p = CreateChannelStack(args.Set(MakeLameClientErrorArg(&error)),
- {&LameClientFilter::kFilter});
+ {&LameClientFilter::kFilter}, nullptr, nullptr);
}
return MakeRefCounted(std::move(p.value()));
}
diff --git a/src/core/client_channel/dynamic_filters.h b/src/core/client_channel/dynamic_filters.h
index 142217d72d3..30a5354f935 100644
--- a/src/core/client_channel/dynamic_filters.h
+++ b/src/core/client_channel/dynamic_filters.h
@@ -24,6 +24,7 @@
#include
+#include "src/core/filter/blackboard.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/channel/channel_stack.h"
@@ -90,7 +91,8 @@ class DynamicFilters final : public RefCounted {
};
static RefCountedPtr Create(
- const ChannelArgs& args, std::vector filters);
+ const ChannelArgs& args, std::vector filters,
+ const Blackboard* old_blackboard, Blackboard* new_blackboard);
explicit DynamicFilters(RefCountedPtr channel_stack)
: channel_stack_(std::move(channel_stack)) {}
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
index c3a6ab3e71b..7e51b20dca3 100644
--- a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
@@ -37,6 +37,10 @@
namespace grpc_core {
+//
+// GcpAuthenticationFilter::Call
+//
+
const NoInterceptor GcpAuthenticationFilter::Call::OnClientToServerMessage;
const NoInterceptor GcpAuthenticationFilter::Call::OnClientToServerHalfClose;
const NoInterceptor GcpAuthenticationFilter::Call::OnServerInitialMetadata;
@@ -98,7 +102,7 @@ absl::Status GcpAuthenticationFilter::Call::OnClientInitialMetadata(
cluster_name));
}
// Get the call creds instance.
- auto creds = filter->GetCallCredentials(
+ auto creds = filter->cache_->Get(
DownCast(metadata_value)->url());
// Add the call creds instance to the call.
auto* arena = GetContext();
@@ -113,6 +117,34 @@ absl::Status GcpAuthenticationFilter::Call::OnClientInitialMetadata(
return absl::OkStatus();
}
+//
+// GcpAuthenticationFilter::CallCredentialsCache
+//
+
+UniqueTypeName GcpAuthenticationFilter::CallCredentialsCache::Type() {
+ static UniqueTypeName::Factory factory("gcp_auth_call_creds_cache");
+ return factory.Create();
+}
+
+void GcpAuthenticationFilter::CallCredentialsCache::SetMaxSize(
+ size_t max_size) {
+ MutexLock lock(&mu_);
+ cache_.SetMaxSize(max_size);
+}
+
+RefCountedPtr
+GcpAuthenticationFilter::CallCredentialsCache::Get(
+ const std::string& audience) {
+ MutexLock lock(&mu_);
+ return cache_.GetOrInsert(audience, [](const std::string& audience) {
+ return MakeRefCounted(audience);
+ });
+}
+
+//
+// GcpAuthenticationFilter
+//
+
const grpc_channel_filter GcpAuthenticationFilter::kFilter =
MakePromiseBasedFilter();
@@ -120,6 +152,7 @@ const grpc_channel_filter GcpAuthenticationFilter::kFilter =
absl::StatusOr>
GcpAuthenticationFilter::Create(const ChannelArgs& args,
ChannelFilter::Args filter_args) {
+ // Get filter config.
auto* service_config = args.GetObject();
if (service_config == nullptr) {
return absl::InvalidArgumentError(
@@ -136,29 +169,32 @@ GcpAuthenticationFilter::Create(const ChannelArgs& args,
return absl::InvalidArgumentError(
"gcp_auth: filter instance ID not found in filter config");
}
+ // Get XdsConfig so that we can look up CDS resources.
auto xds_config = args.GetObjectRef();
if (xds_config == nullptr) {
return absl::InvalidArgumentError(
"gcp_auth: xds config not found in channel args");
}
- return std::make_unique(filter_config,
- std::move(xds_config));
+ // Get existing cache or create new one.
+ auto cache = filter_args.GetOrCreateState(
+ filter_config->filter_instance_name, [&]() {
+ return MakeRefCounted(filter_config->cache_size);
+ });
+ // Make sure size is updated, in case we're reusing a pre-existing
+ // cache but it has the wrong size.
+ cache->SetMaxSize(filter_config->cache_size);
+ // Instantiate filter.
+ return std::unique_ptr(new GcpAuthenticationFilter(
+ filter_config, std::move(xds_config), std::move(cache)));
}
GcpAuthenticationFilter::GcpAuthenticationFilter(
const GcpAuthenticationParsedConfig::Config* filter_config,
- RefCountedPtr xds_config)
+ RefCountedPtr xds_config,
+ RefCountedPtr cache)
: filter_config_(filter_config),
xds_config_(std::move(xds_config)),
- cache_(filter_config->cache_size) {}
-
-RefCountedPtr
-GcpAuthenticationFilter::GetCallCredentials(const std::string& audience) {
- MutexLock lock(&mu_);
- return cache_.GetOrInsert(audience, [](const std::string& audience) {
- return MakeRefCounted(audience);
- });
-}
+ cache_(std::move(cache)) {}
void GcpAuthenticationFilterRegister(CoreConfiguration::Builder* builder) {
GcpAuthenticationServiceConfigParser::Register(builder);
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
index 18109c70c1b..f8fc704c9e8 100644
--- a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
@@ -25,6 +25,7 @@
#include "absl/strings/string_view.h"
#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
+#include "src/core/filter/blackboard.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/channel/promise_based_filter.h"
@@ -49,10 +50,6 @@ class GcpAuthenticationFilter
static absl::StatusOr> Create(
const ChannelArgs& args, ChannelFilter::Args filter_args);
- GcpAuthenticationFilter(
- const GcpAuthenticationParsedConfig::Config* filter_config,
- RefCountedPtr xds_config);
-
class Call {
public:
absl::Status OnClientInitialMetadata(ClientMetadata& /*md*/,
@@ -66,15 +63,30 @@ class GcpAuthenticationFilter
};
private:
- RefCountedPtr GetCallCredentials(
- const std::string& audience);
+ class CallCredentialsCache : public Blackboard::Entry {
+ public:
+ explicit CallCredentialsCache(size_t max_size) : cache_(max_size) {}
+
+ static UniqueTypeName Type();
+
+ void SetMaxSize(size_t max_size);
+
+ RefCountedPtr Get(const std::string& audience);
+
+ private:
+ Mutex mu_;
+ LruCache>
+ cache_ ABSL_GUARDED_BY(&mu_);
+ };
+
+ GcpAuthenticationFilter(
+ const GcpAuthenticationParsedConfig::Config* filter_config,
+ RefCountedPtr xds_config,
+ RefCountedPtr cache);
const GcpAuthenticationParsedConfig::Config* filter_config_;
const RefCountedPtr xds_config_;
-
- Mutex mu_;
- LruCache>
- cache_ ABSL_GUARDED_BY(&mu_);
+ const RefCountedPtr cache_;
};
} // namespace grpc_core
diff --git a/src/core/filter/blackboard.cc b/src/core/filter/blackboard.cc
new file mode 100644
index 00000000000..b916bf77d8f
--- /dev/null
+++ b/src/core/filter/blackboard.cc
@@ -0,0 +1,33 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/filter/blackboard.h"
+
+namespace grpc_core {
+
+RefCountedPtr Blackboard::Get(UniqueTypeName type,
+ const std::string& key) const {
+ auto it = map_.find(std::make_pair(type, key));
+ if (it == map_.end()) return nullptr;
+ return it->second;
+}
+
+void Blackboard::Set(UniqueTypeName type, const std::string& key,
+ RefCountedPtr entry) {
+ map_[std::make_pair(type, key)] = std::move(entry);
+}
+
+} // namespace grpc_core
diff --git a/src/core/filter/blackboard.h b/src/core/filter/blackboard.h
new file mode 100644
index 00000000000..972758162f0
--- /dev/null
+++ b/src/core/filter/blackboard.h
@@ -0,0 +1,71 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef GRPC_SRC_CORE_FILTER_BLACKBOARD_H
+#define GRPC_SRC_CORE_FILTER_BLACKBOARD_H
+
+#include
+#include
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/strings/string_view.h"
+
+#include "src/core/resolver/endpoint_addresses.h"
+#include "src/core/util/debug_location.h"
+#include "src/core/util/ref_counted.h"
+#include "src/core/util/ref_counted_ptr.h"
+#include "src/core/util/unique_type_name.h"
+#include "src/core/util/useful.h"
+
+namespace grpc_core {
+
+// A blackboard is a place where dynamic filters can stash global state
+// that they may want to retain across resolver updates. Entries are
+// identified by by the unique type and a name that identifies the instance,
+// which means that it's possible for two filter instances to use the same
+// type (e.g., if there are two instantiations of the same filter).
+class Blackboard : public RefCounted {
+ public:
+ // All entries must derive from this type.
+ // They must also have a static method with the following signature:
+ // static UniqueTypeName Type();
+ class Entry : public RefCounted {};
+
+ // Returns an entry for a particular type and name, or null if not present.
+ template
+ RefCountedPtr Get(const std::string& key) const {
+ return Get(T::Type(), key).template TakeAsSubclass();
+ }
+
+ // Sets an entry for a particular type and name.
+ template
+ void Set(const std::string& key, RefCountedPtr entry) {
+ Set(T::Type(), key, std::move(entry));
+ }
+
+ private:
+ RefCountedPtr Get(UniqueTypeName type, const std::string& key) const;
+ void Set(UniqueTypeName type, const std::string& key,
+ RefCountedPtr entry);
+
+ absl::flat_hash_map,
+ RefCountedPtr>
+ map_;
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_FILTER_BLACKBOARD_H
diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc
index 2590ab4590d..14e618a7fd8 100644
--- a/src/core/lib/channel/channel_stack.cc
+++ b/src/core/lib/channel/channel_stack.cc
@@ -116,7 +116,8 @@ grpc_error_handle grpc_channel_stack_init(
int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
const grpc_channel_filter** filters, size_t filter_count,
const grpc_core::ChannelArgs& channel_args, const char* name,
- grpc_channel_stack* stack) {
+ grpc_channel_stack* stack, const grpc_core::Blackboard* old_blackboard,
+ grpc_core::Blackboard* new_blackboard) {
if (GRPC_TRACE_FLAG_ENABLED(channel_stack)) {
LOG(INFO) << "CHANNEL_STACK: init " << name;
for (size_t i = 0; i < filter_count; i++) {
@@ -145,6 +146,8 @@ grpc_error_handle grpc_channel_stack_init(
sizeof(grpc_channel_element));
// init per-filter data
+ args.old_blackboard = old_blackboard;
+ args.new_blackboard = new_blackboard;
grpc_error_handle first_error;
for (i = 0; i < filter_count; i++) {
args.channel_stack = stack;
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 8ed7b4eafe1..56bcb62f900 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -19,13 +19,6 @@
#ifndef GRPC_SRC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
#define GRPC_SRC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
-//////////////////////////////////////////////////////////////////////////////
-// IMPORTANT NOTE:
-//
-// When you update this API, please make the corresponding changes to
-// the C++ API in src/cpp/common/channel_filter.{h,cc}
-//////////////////////////////////////////////////////////////////////////////
-
// A channel filter defines how operations on a channel are implemented.
// Channel filters are chained together to create full channels, and if those
// chains are linear, then channel stacks provide a mechanism to minimize
@@ -74,11 +67,17 @@
#include "src/core/util/time_precise.h"
#include "src/core/util/unique_type_name.h"
+namespace grpc_core {
+class Blackboard;
+} // namespace grpc_core
+
struct grpc_channel_element_args {
grpc_channel_stack* channel_stack;
grpc_core::ChannelArgs channel_args;
int is_first;
int is_last;
+ const grpc_core::Blackboard* old_blackboard;
+ grpc_core::Blackboard* new_blackboard;
};
struct grpc_call_element_args {
grpc_call_stack* call_stack;
@@ -262,7 +261,9 @@ grpc_error_handle grpc_channel_stack_init(
int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
const grpc_channel_filter** filters, size_t filter_count,
const grpc_core::ChannelArgs& args, const char* name,
- grpc_channel_stack* stack);
+ grpc_channel_stack* stack,
+ const grpc_core::Blackboard* old_blackboard = nullptr,
+ grpc_core::Blackboard* new_blackboard = nullptr);
// Destroy a channel stack
void grpc_channel_stack_destroy(grpc_channel_stack* stack);
diff --git a/src/core/lib/channel/channel_stack_builder_impl.cc b/src/core/lib/channel/channel_stack_builder_impl.cc
index 953a60a9232..360cd7aa7db 100644
--- a/src/core/lib/channel/channel_stack_builder_impl.cc
+++ b/src/core/lib/channel/channel_stack_builder_impl.cc
@@ -77,7 +77,7 @@ ChannelStackBuilderImpl::Build() {
gpr_free(stk);
},
channel_stack, stack.data(), stack.size(), channel_args(), name(),
- channel_stack);
+ channel_stack, old_blackboard_, new_blackboard_);
if (!error.ok()) {
grpc_channel_stack_destroy(channel_stack);
diff --git a/src/core/lib/channel/channel_stack_builder_impl.h b/src/core/lib/channel/channel_stack_builder_impl.h
index 3bce0f5db3f..78df9809c90 100644
--- a/src/core/lib/channel/channel_stack_builder_impl.h
+++ b/src/core/lib/channel/channel_stack_builder_impl.h
@@ -25,6 +25,8 @@
namespace grpc_core {
+class Blackboard;
+
// Build a channel stack.
// Allows interested parties to add filters to the stack, and to query an
// in-progress build.
@@ -34,13 +36,24 @@ class ChannelStackBuilderImpl final : public ChannelStackBuilder {
public:
using ChannelStackBuilder::ChannelStackBuilder;
+ void SetBlackboards(const Blackboard* old_blackboard,
+ Blackboard* new_blackboard) {
+ old_blackboard_ = old_blackboard;
+ new_blackboard_ = new_blackboard;
+ }
+
// Build the channel stack.
// After success, *result holds the new channel stack,
// prefix_bytes are allocated before the channel stack,
// initial_refs, destroy, destroy_arg are as per grpc_channel_stack_init
// On failure, *result is nullptr.
absl::StatusOr> Build() override;
+
+ private:
+ const Blackboard* old_blackboard_ = nullptr;
+ Blackboard* new_blackboard_ = nullptr;
};
+
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_IMPL_H
diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h
index 0ac59932e0f..6b2ba31ce6b 100644
--- a/src/core/lib/channel/promise_based_filter.h
+++ b/src/core/lib/channel/promise_based_filter.h
@@ -42,6 +42,7 @@
#include
#include
+#include "src/core/filter/blackboard.h"
#include "src/core/lib/channel/call_finalization.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h"
@@ -81,15 +82,23 @@ class ChannelFilter {
public:
Args() : Args(nullptr, nullptr) {}
Args(grpc_channel_stack* channel_stack,
- grpc_channel_element* channel_element)
- : impl_(ChannelStackBased{channel_stack, channel_element}) {}
+ grpc_channel_element* channel_element,
+ const Blackboard* old_blackboard = nullptr,
+ Blackboard* new_blackboard = nullptr)
+ : impl_(ChannelStackBased{channel_stack, channel_element}),
+ old_blackboard_(old_blackboard),
+ new_blackboard_(new_blackboard) {}
// While we're moving to call-v3 we need to have access to
// grpc_channel_stack & friends here. That means that we can't rely on this
// type signature from interception_chain.h, which means that we need a way
// of constructing this object without naming it ===> implicit construction.
// TODO(ctiller): remove this once we're fully on call-v3
// NOLINTNEXTLINE(google-explicit-constructor)
- Args(size_t instance_id) : impl_(V3Based{instance_id}) {}
+ Args(size_t instance_id, const Blackboard* old_blackboard = nullptr,
+ Blackboard* new_blackboard = nullptr)
+ : impl_(V3Based{instance_id}),
+ old_blackboard_(old_blackboard),
+ new_blackboard_(new_blackboard) {}
ABSL_DEPRECATED("Direct access to channel stack is deprecated")
grpc_channel_stack* channel_stack() const {
@@ -113,6 +122,21 @@ class ChannelFilter {
[](const V3Based& v3) { return v3.instance_id; });
}
+ // If a filter state object of type T exists for key from a previous
+ // filter stack, retains it for the new filter stack we're constructing.
+ // Otherwise, invokes create_func() to create a new filter state
+ // object for the new filter stack. Returns the new filter state object.
+ template
+ RefCountedPtr GetOrCreateState(
+ const std::string& key,
+ absl::FunctionRef()> create_func) {
+ RefCountedPtr state;
+ if (old_blackboard_ != nullptr) state = old_blackboard_->Get(key);
+ if (state == nullptr) state = create_func();
+ if (new_blackboard_ != nullptr) new_blackboard_->Set(key, state);
+ return state;
+ }
+
private:
friend class ChannelFilter;
@@ -127,6 +151,9 @@ class ChannelFilter {
using Impl = absl::variant;
Impl impl_;
+
+ const Blackboard* old_blackboard_ = nullptr;
+ Blackboard* new_blackboard_ = nullptr;
};
// Perform post-initialization step (if any).
@@ -1620,8 +1647,10 @@ struct ChannelFilterWithFlagsMethods {
static absl::Status InitChannelElem(grpc_channel_element* elem,
grpc_channel_element_args* args) {
CHECK(args->is_last == ((kFlags & kFilterIsLast) != 0));
- auto status = F::Create(args->channel_args,
- ChannelFilter::Args(args->channel_stack, elem));
+ auto status = F::Create(
+ args->channel_args,
+ ChannelFilter::Args(args->channel_stack, elem, args->old_blackboard,
+ args->new_blackboard));
if (!status.ok()) {
new (elem->channel_data) F*(nullptr);
return absl_status_to_grpc_error(status.status());
diff --git a/src/core/lib/transport/interception_chain.h b/src/core/lib/transport/interception_chain.h
index 82608e3a005..a204985afc0 100644
--- a/src/core/lib/transport/interception_chain.h
+++ b/src/core/lib/transport/interception_chain.h
@@ -28,6 +28,7 @@
namespace grpc_core {
+class Blackboard;
class InterceptionChainBuilder;
// One hijacked call. Using this we can get access to the CallHandler for the
@@ -153,8 +154,12 @@ class InterceptionChainBuilder final {
absl::variant,
RefCountedPtr