Skip to content

Commit 77a4332

Browse files
committed
Reduce boiler plate for Go container image C++ headers
Signed-off-by: Dom Del Nano <ddelnano@gmail.com> (cherry picked from commit 056e62fc42cb26d18b8a91d2ab496c0656058044)
1 parent 8142de8 commit 77a4332

28 files changed

+362
-1139
lines changed

bazel/go_container.bzl

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
# Copyright 2018- The Pixie Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
17+
load("//bazel:pl_build_system.bzl", "pl_boringcrypto_go_sdk")
18+
19+
"""
20+
Bazel rules and macros for generating Go container test libraries.
21+
22+
This module provides a custom rule and macros to generate C++ header files
23+
for Go container test fixtures at build time. This eliminates the need for
24+
manually maintaining per-version header files.
25+
26+
There are two types of container sources:
27+
- bazel_sdk_versions: Built from source using Bazel's Go SDK cross-compilation
28+
- prebuilt_container_versions: Use pre-built container images from the containers directory
29+
30+
Usage:
31+
In BUILD.bazel:
32+
load("//bazel:go_container.bzl", "go_container_libraries")
33+
34+
go_container_libraries(
35+
container_type = "grpc_server",
36+
bazel_sdk_versions = ["1.23", "1.24"],
37+
prebuilt_container_versions = ["1.18", "1.19"],
38+
)
39+
"""
40+
41+
load("//bazel:pl_build_system.bzl", "pl_cc_test_library")
42+
43+
_LICENSE_HEADER = """\
44+
/*
45+
* Copyright 2018- The Pixie Authors.
46+
*
47+
* Licensed under the Apache License, Version 2.0 (the "License");
48+
* you may not use this file except in compliance with the License.
49+
* You may obtain a copy of the License at
50+
*
51+
* http://www.apache.org/licenses/LICENSE-2.0
52+
*
53+
* Unless required by applicable law or agreed to in writing, software
54+
* distributed under the License is distributed on an "AS IS" BASIS,
55+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
56+
* See the License for the specific language governing permissions and
57+
* limitations under the License.
58+
*
59+
* SPDX-License-Identifier: Apache-2.0
60+
*/
61+
62+
// AUTO-GENERATED FILE - DO NOT EDIT",
63+
// Generated by //bazel:go_container.bzl",
64+
65+
#pragma once
66+
67+
"""
68+
69+
70+
# Template for container header content
71+
_CONTAINER_HEADER_TEMPLATE = _LICENSE_HEADER + """\
72+
73+
#include <string>
74+
75+
#include "src/common/testing/test_environment.h"
76+
#include "src/common/testing/test_utils/container_runner.h"
77+
78+
namespace px {{
79+
namespace stirling {{
80+
namespace testing {{
81+
82+
class {class_name} : public ContainerRunner {{
83+
public:
84+
{class_name}()
85+
: ContainerRunner(::px::testing::BazelRunfilePath(kBazelImageTar), kContainerNamePrefix,
86+
kReadyMessage) {{}}
87+
88+
private:
89+
static constexpr std::string_view kBazelImageTar =
90+
"{tar_path}";
91+
static constexpr std::string_view kContainerNamePrefix = "{container_prefix}";
92+
static constexpr std::string_view kReadyMessage = {ready_message};
93+
}};
94+
95+
}} // namespace testing
96+
}} // namespace stirling
97+
}} // namespace px
98+
"""
99+
100+
# Configuration for each use case
101+
# Keys: container_type name
102+
# Values: dict with container_prefix, ready_message, tar patterns
103+
_GO_CONTAINER_CONFIGS = {
104+
"grpc_server": {
105+
"container_prefix": "grpc_server",
106+
"ready_message": '"Starting HTTP/2 server"',
107+
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_{version}_grpc_tls_server.tar",
108+
"tar_pattern_prebuilt": "src/stirling/source_connectors/socket_tracer/testing/containers/golang_{version}_grpc_server_with_buildinfo.tar",
109+
"class_suffix": "GRPCServerContainer",
110+
},
111+
"grpc_client": {
112+
"container_prefix": "grpc_client",
113+
"ready_message": '""',
114+
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_grpc_tls_pl/client/golang_{version}_grpc_tls_client.tar",
115+
"tar_pattern_prebuilt": None,
116+
"class_suffix": "GRPCClientContainer",
117+
},
118+
"tls_server": {
119+
"container_prefix": "https_server",
120+
"ready_message": '"Starting HTTPS service"',
121+
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_https/server/golang_{version}_https_server.tar",
122+
"tar_pattern_prebuilt": "src/stirling/source_connectors/socket_tracer/testing/containers/golang_{version}_https_server_with_buildinfo.tar",
123+
"class_suffix": "TLSServerContainer",
124+
},
125+
"tls_client": {
126+
"container_prefix": "https_client",
127+
"ready_message": 'R"({"status":"ok"})"',
128+
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_https/client/golang_{version}_https_client.tar",
129+
"tar_pattern_prebuilt": None,
130+
"class_suffix": "TLSClientContainer",
131+
},
132+
}
133+
134+
def _version_to_class_prefix(version):
135+
"""Convert version string to class name prefix.
136+
137+
Args:
138+
version: Go SDK version string (e.g., "1.24", "1.23.11")
139+
140+
Returns:
141+
Class name prefix (e.g., "Go1_24_", "GoBoringCrypto")
142+
"""
143+
144+
if version in pl_boringcrypto_go_sdk:
145+
return "GoBoringCrypto"
146+
return "Go" + version.replace(".", "_") + "_"
147+
148+
def _version_to_label_suffix(version):
149+
"""Convert version string to bazel label suffix.
150+
151+
Args:
152+
version: Go SDK version string (e.g., "1.24", "1.23.11")
153+
154+
Returns:
155+
Label suffix (e.g., "1_24", "boringcrypto")
156+
"""
157+
158+
if version in pl_boringcrypto_go_sdk:
159+
return "boringcrypto"
160+
return version.replace(".", "_")
161+
162+
def _go_container_header_impl(ctx):
163+
"""Generate a Go container header file."""
164+
output = ctx.actions.declare_file(ctx.attr.header_name)
165+
166+
ctx.actions.write(
167+
output = output,
168+
content = _CONTAINER_HEADER_TEMPLATE.format(
169+
class_name = ctx.attr.class_name,
170+
tar_path = ctx.attr.tar_path,
171+
container_prefix = ctx.attr.container_prefix,
172+
ready_message = ctx.attr.ready_message,
173+
),
174+
)
175+
return [DefaultInfo(files = depset([output]))]
176+
177+
go_container_header = rule(
178+
implementation = _go_container_header_impl,
179+
attrs = {
180+
"class_name": attr.string(mandatory = True),
181+
"container_prefix": attr.string(mandatory = True),
182+
"header_name": attr.string(mandatory = True),
183+
"ready_message": attr.string(mandatory = True),
184+
"tar_path": attr.string(mandatory = True),
185+
},
186+
)
187+
188+
def go_container_library(name, container_type, version, use_prebuilt = False):
189+
"""
190+
Create a container library for a specific Go version and use case.
191+
192+
This macro generates a C++ header file and wraps it in a pl_cc_test_library
193+
that can be used as a dependency in tests.
194+
195+
Args:
196+
name: Target name for the library
197+
container_type: One of "grpc_server", "grpc_client", "tls_server", "tls_client"
198+
version: Go SDK version (e.g., "1.24", "1.23.11")
199+
use_prebuilt: Whether to use prebuilt container tar path (for older Go versions that are no longer built via bazel)
200+
"""
201+
if container_type not in _GO_CONTAINER_CONFIGS:
202+
fail("Invalid container type'{}'. Must be one of: {}".format(
203+
container_type,
204+
", ".join(_GO_CONTAINER_CONFIGS.keys()),
205+
))
206+
config = _GO_CONTAINER_CONFIGS[container_type]
207+
label_suffix = _version_to_label_suffix(version)
208+
class_prefix = _version_to_class_prefix(version)
209+
210+
# Determine tar path pattern based on container source
211+
if use_prebuilt:
212+
tar_pattern = config["tar_pattern_prebuilt"]
213+
if not tar_pattern:
214+
fail("container_type '{}' does not support prebuilt containers".format(container_type))
215+
else:
216+
tar_pattern = config["tar_pattern_bazel_sdk"]
217+
218+
tar_path = tar_pattern.format(version = label_suffix)
219+
220+
# Class name: Go{version}_{UseCase}Container or GoBoringCrypto{UseCase}Container
221+
class_name = class_prefix + config["class_suffix"]
222+
223+
header_name = "go_{}_{}_container.h".format(label_suffix, container_type)
224+
225+
# Generate the header
226+
go_container_header(
227+
name = name + "_header",
228+
header_name = header_name,
229+
class_name = class_name,
230+
tar_path = tar_path,
231+
container_prefix = config["container_prefix"],
232+
ready_message = config["ready_message"],
233+
)
234+
235+
# Parse tar path to get the Bazel label
236+
# e.g., "src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_1_24_grpc_tls_server.tar"
237+
# becomes "//src/stirling/testing/demo_apps/go_grpc_tls_pl/server:golang_1_24_grpc_tls_server.tar"
238+
tar_dir = tar_path.rsplit("/", 1)[0]
239+
tar_file = tar_path.rsplit("/", 1)[1]
240+
tar_label = "//" + tar_dir + ":" + tar_file
241+
242+
# Create the test library
243+
pl_cc_test_library(
244+
name = name,
245+
hdrs = [":" + name + "_header"],
246+
data = [tar_label],
247+
deps = ["//src/common/testing/test_utils:cc_library"],
248+
)
249+
250+
def _get_header_path(container_type, label_suffix):
251+
"""Get the generated header path for a container."""
252+
return "src/stirling/source_connectors/socket_tracer/testing/container_images/go_{}_{}_container.h".format(
253+
label_suffix,
254+
container_type,
255+
)
256+
257+
def go_container_libraries(container_type, bazel_sdk_versions = [], prebuilt_container_versions = []):
258+
"""
259+
Generate container libraries for all versions of a use case.
260+
261+
This is a convenience macro that generates multiple go_container_library
262+
targets in a single call. The two version lists are mutually exclusive -
263+
each version should appear in exactly one list.
264+
265+
Args:
266+
container_type: One of "grpc_server", "grpc_client", "tls_server", "tls_client"
267+
bazel_sdk_versions: List of Go SDK versions built from source using Bazel
268+
prebuilt_container_versions: List of Go versions using pre-built container images
269+
"""
270+
all_versions = prebuilt_container_versions + bazel_sdk_versions
271+
include_paths = []
272+
deps = []
273+
274+
# Generate libraries for prebuilt container versions
275+
for version in prebuilt_container_versions:
276+
label_suffix = _version_to_label_suffix(version)
277+
target_name = "go_{}_{}_container".format(label_suffix, container_type)
278+
go_container_library(
279+
name = target_name,
280+
container_type = container_type,
281+
version = version,
282+
use_prebuilt = True,
283+
)
284+
include_paths.append(_get_header_path(container_type, label_suffix))
285+
deps.append(":" + target_name)
286+
287+
# Generate libraries for Bazel SDK versions (built from source)
288+
for version in bazel_sdk_versions:
289+
label_suffix = _version_to_label_suffix(version)
290+
target_name = "go_{}_{}_container".format(label_suffix, container_type)
291+
go_container_library(
292+
name = target_name,
293+
container_type = container_type,
294+
version = version,
295+
use_prebuilt = False,
296+
)
297+
include_paths.append(_get_header_path(container_type, label_suffix))
298+
deps.append(":" + target_name)
299+
300+
# Generate the aggregated includes header
301+
if include_paths:
302+
# Header name: go_{container_type}_containers.h
303+
# e.g., "grpc_server" -> "go_grpc_server_containers.h"
304+
header_name = "go_{}_containers.h".format(container_type)
305+
includes_target_name = "go_{}_containers".format(container_type)
306+
307+
# Build the header content
308+
header_lines = _LICENSE_HEADER.splitlines()
309+
for include_path in include_paths:
310+
header_lines.append('#include "{}"'.format(include_path))
311+
header_content = "\\n".join(header_lines)
312+
313+
# Use genrule to generate the header
314+
native.genrule(
315+
name = includes_target_name + "_gen",
316+
outs = [header_name],
317+
cmd = "printf '{}' > $@".format(header_content),
318+
)
319+
320+
pl_cc_test_library(
321+
name = includes_target_name,
322+
hdrs = [":" + includes_target_name + "_gen"],
323+
deps = deps,
324+
)

bazel/pl_build_system.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pl_go_test_versions = ["1.18", "1.19", "1.20", "1.21", "1.22"]
2828
pl_supported_go_sdk_versions = ["1.23", "1.24"]
2929

3030
# The last version in this list corresponds to the boringcrypto go sdk version.
31+
# This list is used for generating container libraries and other version-specific targets.
3132
pl_all_supported_go_sdk_versions = pl_supported_go_sdk_versions + pl_boringcrypto_go_sdk
3233

3334
def pl_go_sdk_version_template_to_label(tpl, version):

src/stirling/source_connectors/socket_tracer/BUILD.bazel

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -344,17 +344,8 @@ pl_cc_bpf_test(
344344
"//src/common/exec:cc_library",
345345
"//src/common/testing/test_utils:cc_library",
346346
"//src/stirling/source_connectors/socket_tracer/testing:cc_library",
347-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_18_grpc_server_container",
348-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_19_grpc_server_container",
349-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_20_grpc_server_container",
350-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_21_grpc_server_container",
351-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_22_grpc_server_container",
352-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_23_grpc_client_container",
353-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_23_grpc_server_container",
354-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_24_grpc_client_container",
355-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_24_grpc_server_container",
356-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_boringcrypto_grpc_client_container",
357-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_boringcrypto_grpc_server_container",
347+
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_grpc_client_containers",
348+
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_grpc_server_containers",
358349
"//src/stirling/source_connectors/socket_tracer/testing/container_images:product_catalog_client_container",
359350
"//src/stirling/source_connectors/socket_tracer/testing/container_images:product_catalog_service_container",
360351
"//src/stirling/testing:cc_library",
@@ -563,17 +554,8 @@ pl_cc_bpf_test(
563554
"//src/common/exec:cc_library",
564555
"//src/common/testing/test_utils:cc_library",
565556
"//src/stirling/source_connectors/socket_tracer/testing:cc_library",
566-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_18_tls_server_container",
567-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_19_tls_server_container",
568-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_20_tls_server_container",
569-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_21_tls_server_container",
570-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_22_tls_server_container",
571-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_23_tls_client_container",
572-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_23_tls_server_container",
573-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_24_tls_client_container",
574-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_1_24_tls_server_container",
575-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_boringcrypto_tls_client_container",
576-
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_boringcrypto_tls_server_container",
557+
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_tls_client_containers",
558+
"//src/stirling/source_connectors/socket_tracer/testing/container_images:go_tls_server_containers",
577559
"//src/stirling/testing:cc_library",
578560
],
579561
)

src/stirling/source_connectors/socket_tracer/go_tls_trace_bpf_test.cc

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,8 @@
2020
#include <gtest/gtest.h>
2121

2222
#include "src/common/testing/testing.h"
23-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_18_tls_server_container.h"
24-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_19_tls_server_container.h"
25-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_20_tls_server_container.h"
26-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_21_tls_server_container.h"
27-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_22_tls_server_container.h"
28-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_23_tls_client_container.h"
29-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_23_tls_server_container.h"
30-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_24_tls_client_container.h"
31-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_1_24_tls_server_container.h"
32-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_boringcrypto_tls_client_container.h"
33-
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_boringcrypto_tls_server_container.h"
23+
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_tls_client_containers.h"
24+
#include "src/stirling/source_connectors/socket_tracer/testing/container_images/go_tls_server_containers.h"
3425
#include "src/stirling/source_connectors/socket_tracer/testing/protocol_checkers.h"
3526
#include "src/stirling/source_connectors/socket_tracer/testing/socket_trace_bpf_test_fixture.h"
3627
#include "src/stirling/testing/common.h"

0 commit comments

Comments
 (0)