Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pl_go_overrides()

go_download_sdk(
name = "go_sdk",
version = "1.24.6",
version = "1.25.5",
)

go_rules_dependencies()
Expand Down Expand Up @@ -220,8 +220,8 @@ load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
gazelle_dependencies(go_sdk = "go_sdk")

go_download_sdk(
name = "go_sdk_1_23",
version = "1.23.12",
name = "go_sdk_1_24",
version = "1.24.11",
)

# The go_sdk_boringcrypto SDK is used for testing boringcrypto specific functionality (TLS tracing).
Expand All @@ -234,7 +234,7 @@ go_download_sdk(
go_download_sdk(
name = "go_sdk_boringcrypto",
experiments = ["boringcrypto"],
version = "1.23.11",
version = "1.24.10",
)

pip_parse(
Expand Down
16 changes: 16 additions & 0 deletions bazel/container_images.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,14 @@ def stirling_test_images():
digest = "sha256:0f14818a1046dfdb7d5ac27e173d99e071219897a1d9969c8d7604acbd0d9541",
)

# Tag: 1.0
# Arch: linux/amd64
_container_image(
name = "golang_1_23_https_server_with_buildinfo",
repository = "golang_1_23_https_server_with_buildinfo",
digest = "sha256:df8ad6fd2cc2c45b7e6713dd365be908f77f006c190c7f79f74b38338b550544",
)

# Tag: 1.0
# Arch: linux/amd64
_container_image(
Expand Down Expand Up @@ -367,3 +375,11 @@ def stirling_test_images():
repository = "golang_1_22_grpc_server_with_buildinfo",
digest = "sha256:67adba5e8513670fa37bd042862e7844f26239e8d2997ed8c3b0aa527bc04cc3",
)

# Tag: 1.0
# Arch: linux/amd64
_container_image(
name = "golang_1_23_grpc_server_with_buildinfo",
repository = "golang_1_23_grpc_server_with_buildinfo",
digest = "sha256:7950a79e492dbdbe18608db5829a129754df5b6b5cb9d6ba822cfd91c43ba61a",
)
324 changes: 324 additions & 0 deletions bazel/go_container.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
# Copyright 2018- The Pixie Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

load("//bazel:pl_build_system.bzl", "pl_boringcrypto_go_sdk")

"""
Bazel rules and macros for generating Go container test libraries.

This module provides a custom rule and macros to generate C++ header files
for Go container test fixtures at build time. This eliminates the need for
manually maintaining per-version header files.

There are two types of container sources:
- bazel_sdk_versions: Built from source using Bazel's Go SDK cross-compilation
- prebuilt_container_versions: Use pre-built container images from the containers directory

Usage:
In BUILD.bazel:
load("//bazel:go_container.bzl", "go_container_libraries")

go_container_libraries(
container_type = "grpc_server",
bazel_sdk_versions = ["1.23", "1.24"],
prebuilt_container_versions = ["1.18", "1.19"],
)
"""

load("//bazel:pl_build_system.bzl", "pl_cc_test_library")

_LICENSE_HEADER = """\
/*
* Copyright 2018- The Pixie Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

// AUTO-GENERATED FILE - DO NOT EDIT",
// Generated by //bazel:go_container.bzl",

#pragma once

"""


# Template for container header content
_CONTAINER_HEADER_TEMPLATE = _LICENSE_HEADER + """\

#include <string>

#include "src/common/testing/test_environment.h"
#include "src/common/testing/test_utils/container_runner.h"

namespace px {{
namespace stirling {{
namespace testing {{

class {class_name} : public ContainerRunner {{
public:
{class_name}()
: ContainerRunner(::px::testing::BazelRunfilePath(kBazelImageTar), kContainerNamePrefix,
kReadyMessage) {{}}

private:
static constexpr std::string_view kBazelImageTar =
"{tar_path}";
static constexpr std::string_view kContainerNamePrefix = "{container_prefix}";
static constexpr std::string_view kReadyMessage = {ready_message};
}};

}} // namespace testing
}} // namespace stirling
}} // namespace px
"""

# Configuration for each use case
# Keys: container_type name
# Values: dict with container_prefix, ready_message, tar patterns
_GO_CONTAINER_CONFIGS = {
"grpc_server": {
"container_prefix": "grpc_server",
"ready_message": '"Starting HTTP/2 server"',
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_{version}_grpc_tls_server.tar",
"tar_pattern_prebuilt": "src/stirling/source_connectors/socket_tracer/testing/containers/golang_{version}_grpc_server_with_buildinfo.tar",
"class_suffix": "GRPCServerContainer",
},
"grpc_client": {
"container_prefix": "grpc_client",
"ready_message": '""',
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_grpc_tls_pl/client/golang_{version}_grpc_tls_client.tar",
"tar_pattern_prebuilt": None,
"class_suffix": "GRPCClientContainer",
},
"tls_server": {
"container_prefix": "https_server",
"ready_message": '"Starting HTTPS service"',
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_https/server/golang_{version}_https_server.tar",
"tar_pattern_prebuilt": "src/stirling/source_connectors/socket_tracer/testing/containers/golang_{version}_https_server_with_buildinfo.tar",
"class_suffix": "TLSServerContainer",
},
"tls_client": {
"container_prefix": "https_client",
"ready_message": 'R"({"status":"ok"})"',
"tar_pattern_bazel_sdk": "src/stirling/testing/demo_apps/go_https/client/golang_{version}_https_client.tar",
"tar_pattern_prebuilt": None,
"class_suffix": "TLSClientContainer",
},
}

def _version_to_class_prefix(version):
"""Convert version string to class name prefix.

Args:
version: Go SDK version string (e.g., "1.24", "1.23.11")

Returns:
Class name prefix (e.g., "Go1_24_", "GoBoringCrypto")
"""

if version in pl_boringcrypto_go_sdk:
return "GoBoringCrypto"
return "Go" + version.replace(".", "_") + "_"

def _version_to_label_suffix(version):
"""Convert version string to bazel label suffix.

Args:
version: Go SDK version string (e.g., "1.24", "1.23.11")

Returns:
Label suffix (e.g., "1_24", "boringcrypto")
"""

if version in pl_boringcrypto_go_sdk:
return "boringcrypto"
return version.replace(".", "_")

def _go_container_header_impl(ctx):
"""Generate a Go container header file."""
output = ctx.actions.declare_file(ctx.attr.header_name)

ctx.actions.write(
output = output,
content = _CONTAINER_HEADER_TEMPLATE.format(
class_name = ctx.attr.class_name,
tar_path = ctx.attr.tar_path,
container_prefix = ctx.attr.container_prefix,
ready_message = ctx.attr.ready_message,
),
)
return [DefaultInfo(files = depset([output]))]

go_container_header = rule(
implementation = _go_container_header_impl,
attrs = {
"class_name": attr.string(mandatory = True),
"container_prefix": attr.string(mandatory = True),
"header_name": attr.string(mandatory = True),
"ready_message": attr.string(mandatory = True),
"tar_path": attr.string(mandatory = True),
},
)

def go_container_library(name, container_type, version, use_prebuilt = False):
"""
Create a container library for a specific Go version and use case.

This macro generates a C++ header file and wraps it in a pl_cc_test_library
that can be used as a dependency in tests.

Args:
name: Target name for the library
container_type: One of "grpc_server", "grpc_client", "tls_server", "tls_client"
version: Go SDK version (e.g., "1.24", "1.23.11")
use_prebuilt: Whether to use prebuilt container tar path (for older Go versions that are no longer built via bazel)
"""
if container_type not in _GO_CONTAINER_CONFIGS:
fail("Invalid container type'{}'. Must be one of: {}".format(
container_type,
", ".join(_GO_CONTAINER_CONFIGS.keys()),
))
config = _GO_CONTAINER_CONFIGS[container_type]
label_suffix = _version_to_label_suffix(version)
class_prefix = _version_to_class_prefix(version)

# Determine tar path pattern based on container source
if use_prebuilt:
tar_pattern = config["tar_pattern_prebuilt"]
if not tar_pattern:
fail("container_type '{}' does not support prebuilt containers".format(container_type))
else:
tar_pattern = config["tar_pattern_bazel_sdk"]

tar_path = tar_pattern.format(version = label_suffix)

# Class name: Go{version}_{UseCase}Container or GoBoringCrypto{UseCase}Container
class_name = class_prefix + config["class_suffix"]

header_name = "go_{}_{}_container.h".format(label_suffix, container_type)

# Generate the header
go_container_header(
name = name + "_header",
header_name = header_name,
class_name = class_name,
tar_path = tar_path,
container_prefix = config["container_prefix"],
ready_message = config["ready_message"],
)

# Parse tar path to get the Bazel label
# e.g., "src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_1_24_grpc_tls_server.tar"
# becomes "//src/stirling/testing/demo_apps/go_grpc_tls_pl/server:golang_1_24_grpc_tls_server.tar"
tar_dir = tar_path.rsplit("/", 1)[0]
tar_file = tar_path.rsplit("/", 1)[1]
tar_label = "//" + tar_dir + ":" + tar_file

# Create the test library
pl_cc_test_library(
name = name,
hdrs = [":" + name + "_header"],
data = [tar_label],
deps = ["//src/common/testing/test_utils:cc_library"],
)

def _get_header_path(container_type, label_suffix):
"""Get the generated header path for a container."""
return "src/stirling/source_connectors/socket_tracer/testing/container_images/go_{}_{}_container.h".format(
label_suffix,
container_type,
)

def go_container_libraries(container_type, bazel_sdk_versions = [], prebuilt_container_versions = []):
"""
Generate container libraries for all versions of a use case.

This is a convenience macro that generates multiple go_container_library
targets in a single call. The two version lists are mutually exclusive -
each version should appear in exactly one list.

Args:
container_type: One of "grpc_server", "grpc_client", "tls_server", "tls_client"
bazel_sdk_versions: List of Go SDK versions built from source using Bazel
prebuilt_container_versions: List of Go versions using pre-built container images
"""
all_versions = prebuilt_container_versions + bazel_sdk_versions
include_paths = []
deps = []

# Generate libraries for prebuilt container versions
for version in prebuilt_container_versions:
label_suffix = _version_to_label_suffix(version)
target_name = "go_{}_{}_container".format(label_suffix, container_type)
go_container_library(
name = target_name,
container_type = container_type,
version = version,
use_prebuilt = True,
)
include_paths.append(_get_header_path(container_type, label_suffix))
deps.append(":" + target_name)

# Generate libraries for Bazel SDK versions (built from source)
for version in bazel_sdk_versions:
label_suffix = _version_to_label_suffix(version)
target_name = "go_{}_{}_container".format(label_suffix, container_type)
go_container_library(
name = target_name,
container_type = container_type,
version = version,
use_prebuilt = False,
)
include_paths.append(_get_header_path(container_type, label_suffix))
deps.append(":" + target_name)

# Generate the aggregated includes header
if include_paths:
# Header name: go_{container_type}_containers.h
# e.g., "grpc_server" -> "go_grpc_server_containers.h"
header_name = "go_{}_containers.h".format(container_type)
includes_target_name = "go_{}_containers".format(container_type)

# Build the header content
header_lines = _LICENSE_HEADER.splitlines()
for include_path in include_paths:
header_lines.append('#include "{}"'.format(include_path))
header_content = "\\n".join(header_lines)

# Use genrule to generate the header
native.genrule(
name = includes_target_name + "_gen",
outs = [header_name],
cmd = "printf '{}' > $@".format(header_content),
)

pl_cc_test_library(
name = includes_target_name,
hdrs = [":" + includes_target_name + "_gen"],
deps = deps,
)
7 changes: 4 additions & 3 deletions bazel/pl_build_system.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load("@rules_python//python:defs.bzl", "py_test")
load("//bazel:toolchain_transitions.bzl", "qemu_interactive_runner")

pl_boringcrypto_go_sdk = ["1.23.11"]
pl_go_test_versions = ["1.18", "1.19", "1.20", "1.21", "1.22"]
pl_supported_go_sdk_versions = ["1.23", "1.24"]
pl_boringcrypto_go_sdk = ["1.24.10"]
pl_go_test_versions = ["1.18", "1.19", "1.20", "1.21", "1.22", "1.23"]
pl_supported_go_sdk_versions = ["1.24", "1.25"]

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

def pl_go_sdk_version_template_to_label(tpl, version):
Expand Down
Loading
Loading