Skip to content
Open
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
10 changes: 10 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ build:clang-common --action_env=CXX=clang++-18 --host_action_env=CXX=clang++-18
build:rbe-toolchain-clang --action_env=CC=clang-18 --action_env=CXX=clang++-18
build:rbe-toolchain-arm64-clang --action_env=CC=clang-18 --action_env=CXX=clang++-18

coverage --config=coverage

build:coverage --combined_report=lcov
build:coverage --action_env=CC=clang-18 --host_action_env=CC=clang-18
build:coverage --action_env=CXX=clang++-18 --host_action_env=CXX=clang++-18
#build:coverage --test_arg="--log-path /dev/null"
build:coverage --test_tag_filters=-nocoverage,-fuzz_target
build:coverage --remote_download_minimal
build:coverage --coverage_report_generator=//tools/coverage:cilium_report_generator

# Use platforms based toolchain resolution
build --incompatible_enable_cc_toolchain_resolution
build --platform_mappings=bazel/platform_mappings
Expand Down
100 changes: 100 additions & 0 deletions .github/workflows/ci-check-coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: CI Check coverage
on:
pull_request: {}

permissions:
# To be able to access the repository with actions/checkout
contents: read
pull-requests: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }}
cancel-in-progress: true

jobs:
coverage:
timeout-minutes: 460
name: Check coverage for pull request #${{ github.event.pull_request.number }}
runs-on: ubuntu-22.04
steps:
- name: Clear Workspace
shell: bash
run: |
sudo rm -r /usr/local/.ghcup
sudo rm -r /usr/local/lib/android
sudo rm -r /opt/hostedtoolcache
- name: Check disk space
shell: bash
run: |
df . -h
- name: Check out the repository to the runner
uses: actions/checkout@v4
- name: Setup gcloud credentials
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.CI_CILIUM_PROXY_SA_KEY }}
- name: set up google cloud sdk
uses: 'google-github-actions/setup-gcloud@v2'
with:
version: '>= 507.0.0'
- name: Install deps (for C++)
shell: bash
run: |
sudo apt-get update && \
sudo apt-get upgrade -y --no-install-recommends && \
sudo apt-get install -y --no-install-recommends \
ca-certificates libc6-dev autoconf automake cmake coreutils curl git libtool make ninja-build patch patchelf \
python3 python-is-python3 unzip virtualenv wget zip software-properties-common && \
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
sudo apt-add-repository -y "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" && \
sudo apt-get update && \
sudo apt-get install -y --no-install-recommends \
clang-18 clangd-18 clang-tidy-18 clang-tools-18 llvm-18-dev lldb-18 lld-18 clang-format-18 libc++-18-dev libc++abi-18-dev libclang-rt-18-dev lcov && \
sudo apt-get purge --auto-remove && \
sudo apt-get clean && \
sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
cp /usr/lib/llvm-18/bin/llvm-cov /usr/local/bin
cp /usr/lib/llvm-18/bin/llvm-profdata /usr/local/bin
- name: Install Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
# renovate: datasource=golang-version depName=go
go-version: 1.24.6
- name: Sync crate lockfile with bazel
shell: bash
run: |
CARGO_BAZEL_ISOLATED=0 CARGO_BAZEL_REPIN=1 bazel sync --only=crate_index
- name: Build proxylib
shell: bash
run: |
go version
make -C proxylib
- name: Generate coverage data
shell: bash
run: |
echo "Generating bazel coverage: "
./tests/run_bazel_coverage.sh
ls -la /home/runner/work/cilium-proxy/cilium-proxy/generated/coverage/
- name: Upload (sync) to GCS bucket
if: '!cancelled()'
shell: bash
run: |
UPLOAD_DIR="/home/runner/work/cilium-proxy/cilium-proxy/generated/coverage/"
SHA=${{ github.sha }}
BUCKET_PATH="${{ vars.GCS_ARTIFACT_BUCKET_COVERAGE }}/${SHA:0:7}/coverage"
echo "Uploading to gs://$BUCKET_PATH ..."
gsutil \
-mq rsync \
-dr "$UPLOAD_DIR" \
"gs://$BUCKET_PATH"
echo "Artifacts uploaded to: https://storage.googleapis.com/$BUCKET_PATH/html/index.html" >&2
strategy:
fail-fast: false
matrix:
include:
- target: coverage
name: Coverage
diskspace-hack: true
diskspace-hack-paths: |
/opt/hostedtoolcache
/usr/local/lib/android
4 changes: 4 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ git_repository(
# // clang-format on
)

load("//bazel:repo.bzl", "cilium_proxy_repo")

cilium_proxy_repo()

#
# Bazel does not do transitive dependencies, so we must basically
# include all of Envoy's WORKSPACE file below, with the following
Expand Down
75 changes: 75 additions & 0 deletions bazel/repo.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# `@cilium_proxy_repo` repository rule for managing the repo and querying its metadata.

def _cilium_proxy_repo_impl(repository_ctx):
"""This provides information about the Envoy repository

You can access the current project and api versions and the path to the repository in
.bzl/BUILD files as follows:

```starlark
load("@cilium_proxy_repo//:version.bzl", "VERSION", "API_VERSION")
```

`*VERSION` can be used to derive version-specific rules and can be passed
to the rules.

The `VERSION`s and also the local `PATH` to the repo can be accessed in
python libraries/binaries. By adding `@cilium_proxy_repo` to `deps` they become
importable through the `cilium_proxy_repo` namespace.

As the `PATH` is local to the machine, it is generally only useful for
jobs that will run locally.

This can be useful, for example, for bazel run jobs to run bazel queries that cannot be run
within the constraints of a `genquery`, or that otherwise need access to the repository
files.

Project and repo data can be accessed in JSON format using `@cilium_proxy_repo//:project`, eg:

```starlark
load("@aspect_bazel_lib//lib:jq.bzl", "jq")

jq(
name = "project_version",
srcs = ["@cilium_proxy_repo//:data"],
out = "version.txt",
args = ["-r"],
filter = ".version",
)

```

"""
repo_version_path = repository_ctx.path(repository_ctx.attr.envoy_version)
api_version_path = repository_ctx.path(repository_ctx.attr.envoy_api_version)
version = repository_ctx.read(repo_version_path).strip()
api_version = repository_ctx.read(api_version_path).strip()
repository_ctx.file("version.bzl", "VERSION = '%s'\nAPI_VERSION = '%s'" % (version, api_version))
repository_ctx.file("path.bzl", "PATH = '%s'" % repo_version_path.dirname)
repository_ctx.file("__init__.py", "PATH = '%s'\nVERSION = '%s'\nAPI_VERSION = '%s'" % (repo_version_path.dirname, version, api_version))
repository_ctx.file("WORKSPACE", "")
repository_ctx.file("BUILD", '''
load("@rules_python//python:defs.bzl", "py_library")
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
load("//:path.bzl", "PATH")

py_library(
name = "cilium_proxy_repo",
srcs = ["__init__.py"],
visibility = ["//visibility:public"],
)

''')

_cilium_proxy_repo = repository_rule(
implementation = _cilium_proxy_repo_impl,
attrs = {
#todo(nezdolik) add cilium version
"envoy_version": attr.label(default = "@envoy//:VERSION.txt"),
"envoy_api_version": attr.label(default = "@envoy//:API_VERSION.txt"),
},
)

def cilium_proxy_repo():
if "cilium_proxy_repo" not in native.existing_rules().keys():
_cilium_proxy_repo(name = "cilium_proxy_repo")
9 changes: 9 additions & 0 deletions tests/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
load("@aspect_bazel_lib//lib:yq.bzl", "yq")
load(
"@envoy//bazel:envoy_build_system.bzl",
"envoy_cc_test",
Expand All @@ -18,6 +19,14 @@ api_cc_py_proto_library(
srcs = ["bpf_metadata.proto"],
)

yq(
name = "coverage_config",
srcs = [":coverage.yaml"],
outs = ["cilium_coverage_config.json"],
args = ["-o=json"],
visibility = ["//visibility:public"],
)

envoy_cc_test_library(
name = "accesslog_server_lib",
srcs = ["accesslog_server.cc"],
Expand Down
7 changes: 7 additions & 0 deletions tests/coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
thresholds:
total: 95.0
per_directory: 95.0

directories:
cilium: 95.0
linux: 95.0
112 changes: 112 additions & 0 deletions tests/run_bazel_coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env bash

set -e -o pipefail
set +x
set -u

LLVM_VERSION=${LLVM_VERSION:-"18.1.8"}
CLANG_VERSION=$(clang-18 --version | grep version | sed -e 's/\ *Ubuntu clang version \([0-9.]*\).*/\1/')
LLVM_COV_VERSION=$(llvm-cov --version | grep version | sed -e 's/\ *Ubuntu LLVM version \([0-9.]*\).*/\1/')
LLVM_PROFDATA_VERSION=$(llvm-profdata show --version | grep version | sed -e 's/\ *Ubuntu LLVM version \(.*\)/\1/')
SRCDIR=${SRCDIR:-"${PWD}"}

#ERROR: clang version Ubuntu18.1.3 does not match expected 18.1.3
if [[ "${CLANG_VERSION}" != "${LLVM_VERSION}" ]]; then
echo "ERROR: clang version ${CLANG_VERSION} does not match expected ${LLVM_VERSION}" >&2
exit 1
fi

if [[ "${LLVM_COV_VERSION}" != "${LLVM_VERSION}" ]]; then
echo "ERROR: llvm-cov version ${LLVM_COV_VERSION} does not match expected ${LLVM_VERSION}" >&2
exit 1
fi

if [[ "${LLVM_PROFDATA_VERSION}" != "${LLVM_VERSION}" ]]; then
echo "ERROR: llvm-profdata version ${LLVM_PROFDATA_VERSION} does not match expected ${LLVM_VERSION}" >&2
exit 1
fi

COVERAGE_TARGET="${COVERAGE_TARGET:-}"
#TBD propogate any important global build options
read -ra BAZEL_BUILD_OPTIONS <<< "${BAZEL_BUILD_OPTION_LIST:-}"
read -ra BAZEL_GLOBAL_OPTIONS <<< "${BAZEL_GLOBAL_OPTION_LIST:-}"

# This is the target that will be run to generate coverage data. It can be overridden by consumer
# projects that want to run coverage on a different/combined target.
# Command-line arguments take precedence over ${COVERAGE_TARGET}.
if [[ $# -gt 0 ]]; then
COVERAGE_TARGETS=("$@")
elif [[ -n "${COVERAGE_TARGET}" ]]; then
COVERAGE_TARGETS=("${COVERAGE_TARGET}")
else
COVERAGE_TARGETS=(//tests/...)
fi

BAZEL_COVERAGE_OPTIONS=()
BAZEL_COVERAGE_OPTIONS+=(--heap_dump_on_oom)
BAZEL_COVERAGE_OPTIONS+=(--action_env=BAZEL_USE_LLVM_NATIVE_COVERAGE=1)
BAZEL_COVERAGE_OPTIONS+=(--combined_report=lcov)
BAZEL_COVERAGE_OPTIONS+=(--coverage_report_generator=//tools/coverage:cilium_report_generator)
BAZEL_COVERAGE_OPTIONS+=(--experimental_use_llvm_covmap)
BAZEL_COVERAGE_OPTIONS+=(--experimental_generate_llvm_lcov)
BAZEL_COVERAGE_OPTIONS+=(--experimental_split_coverage_postprocessing)
BAZEL_COVERAGE_OPTIONS+=(--experimental_fetch_all_coverage_outputs)
BAZEL_COVERAGE_OPTIONS+=(--collect_code_coverage)
BAZEL_COVERAGE_OPTIONS+=(--remote_download_minimal)
BAZEL_COVERAGE_OPTIONS+=(--copt=-DNDEBUG)
BAZEL_COVERAGE_OPTIONS+=(--build_tests_only)
#from envoy
BAZEL_COVERAGE_OPTIONS+=(--experimental_repository_cache_hardlinks)
BAZEL_COVERAGE_OPTIONS+=(--verbose_failures)
BAZEL_COVERAGE_OPTIONS+=(--experimental_generate_json_trace_profile)
BAZEL_COVERAGE_OPTIONS+=(--action_env=GCOV=llvm-profdata)
BAZEL_VALIDATE_OPTIONS=()


# Output unusually long logs due to trace logging.
BAZEL_COVERAGE_OPTIONS+=("--experimental_ui_max_stdouterr_bytes=80000000")
BAZEL_BUILD_OPTIONS+=("--remote_cache=https://storage.googleapis.com/cilium-proxy-bazel-remote-cache")
BAZEL_BUILD_OPTIONS+=("--google_default_credentials")

COVERAGE_DIR="${SRCDIR}/generated/coverage"

COVERAGE_DATA="${COVERAGE_DIR}/coverage.dat"


run_coverage() {
echo "Running bazel coverage with:"
echo " Options: ${BAZEL_BUILD_OPTIONS[*]} ${BAZEL_COVERAGE_OPTIONS[*]}"
echo " Targets: ${COVERAGE_TARGETS[*]}"
bazel coverage "${COVERAGE_TARGETS[@]}" "${BAZEL_BUILD_OPTIONS[@]}" "${BAZEL_COVERAGE_OPTIONS[@]}" --compiler=clang-18 --verbose_failures --sandbox_writable_path=$(bazel info output_path) --test_timeout=300 --local_test_jobs=1 --flaky_test_attempts=3 --instrument_test_targets --instrumentation_filter='^//'

if [[ ! -e bazel-out/_coverage/_coverage_report.dat ]]; then
echo "ERROR: No coverage report found (bazel-out/_coverage/_coverage_report.dat)" >&2
exit 1
elif [[ ! -s bazel-out/_coverage/_coverage_report.dat ]]; then
echo "ERROR: Coverage report is empty (bazel-out/_coverage/_coverage_report.dat)" >&2
exit 1
fi
}

unpack_coverage_results() {
rm -rf "${COVERAGE_DIR}"
mkdir -p "${COVERAGE_DIR}"
rm -f bazel-out/_coverage/_coverage_report.tar.zst
mv bazel-out/_coverage/_coverage_report.dat bazel-out/_coverage/_coverage_report.tar.zst
bazel run "${BAZEL_BUILD_OPTIONS[@]}" --nobuild_tests_only @envoy//tools/zstd -- -d -c "${PWD}/bazel-out/_coverage/_coverage_report.tar.zst" \
| tar -xf - -C "${COVERAGE_DIR}"
COVERAGE_JSON="${COVERAGE_DIR}/coverage.json"
}

validate_coverage() {
bazel run \
"${BAZEL_BUILD_OPTIONS[@]}" \
"${BAZEL_VALIDATE_OPTIONS[@]}" \
--nobuild_tests_only \
//tools/coverage:validate \
"$COVERAGE_JSON"
}

run_coverage
unpack_coverage_results
validate_coverage
Loading
Loading