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
6 changes: 6 additions & 0 deletions .github/actions/gpu-mig-kind/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/installer-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/k8s-compat-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ runs:

- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/k8s-compat-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ runs:

- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/lint/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
77 changes: 77 additions & 0 deletions .github/actions/node-storage-kind/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: "zxporter: node-storage-kind"
description: |
End-to-end validation of node storage occupancy collection against a real
kubelet on a real kind cluster: the production KubeletSummaryClient reads
node.fs and node.runtime.imageFs through the API-server nodes/proxy
subresource, and the spec asserts the invariants the feature rests on.

Why a live cluster earns its keep here. Every other test of this feature
reads a captured fixture, which cannot catch the kubelet dropping a
section, renaming a field, or the nodes/proxy RBAC verb going missing.
More importantly, imagefs-is-a-subset-of-nodefs -- the invariant that
stops consumers double-counting disk -- has otherwise only ever been
checked against numbers we wrote ourselves, and the shared-device
classifier is a heuristic precisely because the kubelet does not name the
device, so the only honest test of it is a node whose real layout we know.

The cheapest kind spec in this tree: no image to build, no operator to
install, no fixture workload, and no port-forward. The client reads
through the API server, the same path kubectl already proves reachable
from the runner, so a plain cluster with no add-ons is enough.

Assertions live in a Go/Ginkgo spec (test/e2e/node_storage_test.go) rather
than a shell heredoc, matching oom-flow-kind: the interesting logic is
Kubernetes-API-shaped, not HTTP-response-shaped.

Consumed by two callers:
- operators/zxporter/.github/workflows/node-storage-kind-test.yml
(published to devzero-inc/zxporter; uses this via
./.github/actions/node-storage-kind)
- .github/workflows/zxporter-node-storage-kind.yml at services root
(uses this via ./operators/zxporter/.github/actions/node-storage-kind
with working-directory: operators/zxporter)

Caller checks out the repo; this action assumes cwd contains the
zxporter source (or the working-directory input points at it).

inputs:
working-directory:
description: "Path to the zxporter tree relative to the repo root."
required: false
default: "."

runs:
using: composite
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
cache-dependency-path: ${{ inputs.working-directory }}/go.sum

# Two nodes on purpose: the spec walks every node in the cluster, so a
# multi-node cluster exercises the per-node loop rather than a
# single-node special case. kind's control-plane and worker both run
# containerd with its state on the same filesystem as the kubelet's,
# which is what makes the shared-device assertion meaningful.
- name: Create kind cluster
uses: helm/kind-action@v1
with:
version: v0.27.0
node_image: kindest/node:v1.32.3
cluster_name: kind-node-storage
config: ${{ inputs.working-directory }}/.github/actions/node-storage-kind/kind-config.yaml
wait: 120s

- name: Run node-storage e2e spec
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
go test ./test/e2e/... -v -ginkgo.v -ginkgo.label-filter=node-storage -timeout 10m
9 changes: 9 additions & 0 deletions .github/actions/node-storage-kind/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Two nodes on purpose. The node-storage spec walks every node in the cluster,
# so a multi-node cluster exercises the per-node loop rather than a single-node
# special case -- and it means the shared-device assertion has to hold on more
# than one kubelet before the suite goes green.
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
6 changes: 6 additions & 0 deletions .github/actions/oom-flow-kind/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/policy-kind/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down
63 changes: 61 additions & 2 deletions .github/actions/runtime-metrics-kind/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand Down Expand Up @@ -58,6 +64,7 @@ runs:
# The deprecated key must render the exact same manifests as the
# canonical one (privileges, env, RBAC), and disabling via the
# deprecated key alone must still work.
helm dependency build ./helm-chart/zxporter-nodemon
helm template zxporter-nodemon ./helm-chart/zxporter-nodemon \
--set global.k8sProvider=other --set dcgmExporter.enabled=false \
--set jvmMetrics.enabled=true > /tmp/render-deprecated.yaml
Expand Down Expand Up @@ -149,6 +156,8 @@ runs:
kubectl -n jvm-spike rollout status deploy/java21-precedence-env --timeout=300s
kubectl -n jvm-spike rollout status deploy/java21-precedence-cmdline --timeout=300s
kubectl -n jvm-spike rollout status deploy/java21-per-flag-sources --timeout=300s
kubectl -n jvm-spike rollout status deploy/zipkin-writable-rootfs --timeout=300s
kubectl -n jvm-spike rollout status deploy/zipkin-readonly-rootfs --timeout=300s
kubectl -n jvm-spike rollout status deploy/not-java --timeout=300s

- name: Deploy Node.js test workloads
Expand Down Expand Up @@ -213,10 +222,17 @@ runs:
# until everything expected has appeared, then run the strict
# assertions (which give precise failure messages if it never does).
need_versions = ['node-version-env', 'node-version-binaryscan', 'python-app',
'ruby-app', 'go-app', 'dotnet-app', 'deno-app', 'bun-app', 'rust-app']
'ruby-app', 'go-app', 'dotnet-app', 'deno-app', 'bun-app', 'rust-app',
# hsperfdata-less JVM: version comes from the image's
# JAVA_VERSION env, so it resolves like any other.
'zipkin-readonly-rootfs']
need_jvm = ['java8-xmx-only', 'zipkin-writable-rootfs']
def all_present():
c = fetch('/container/runtime-metrics')
if not any((m.get('pod') or '').startswith('java8-xmx-only') for m in c.get('jvm', [])):
jvm = c.get('jvm', [])
if not all(
any((m.get('pod') or '').startswith(p) for m in jvm)
for p in need_jvm):
return False
rt = c.get('runtimes', [])
return all(
Expand Down Expand Up @@ -381,6 +397,49 @@ runs:
if any((p or '').startswith('not-node') for p in all_runtime_pods):
raise SystemExit(f'runtime-metrics unexpectedly includes not-node in runtimes bucket; got {all_runtime_pods}')

# ============ hsperfdata-less JVM fallback ============
# zipkin-{writable,readonly}-rootfs are the same image and uid, differing
# only in readOnlyRootFilesystem. With a read-only rootfs and no writable
# /tmp, HotSpot cannot create /tmp/hsperfdata_<user>/<pid>, so the
# hsperfdata pipeline has nothing to read — the process must still be
# reported, as runtime "java" in the generic bucket.
jvm_entries = runtime.get('jvm', [])

# Writable rootfs: full JVM pipeline, real heap metrics.
m_rw = [m for m in jvm_entries if (m.get('pod') or '').startswith('zipkin-writable-rootfs')]
if not m_rw:
raise SystemExit(f'zipkin-writable-rootfs missing from jvm bucket; got {jvm_pods}')
if (m_rw[0].get('heap_max_size_bytes') or 0) <= 0:
raise SystemExit(f'zipkin-writable-rootfs expected heap.max_bytes > 0; got {m_rw[0]!r}')
# The image's entrypoint sets -Xms160m -Xmx160m; proves the flags are
# read from the live cmdline, not from the pod spec (which has neither).
if m_rw[0].get('flags_extracted', {}).get('xmx_bytes') != 167772160:
raise SystemExit(
f'zipkin-writable-rootfs expected xmx_bytes=167772160 from the image entrypoint; '
f'got {m_rw[0].get("flags_extracted")!r}')
if any((p or '').startswith('zipkin-writable-rootfs') for p in all_runtime_pods):
raise SystemExit('zipkin-writable-rootfs must not be double-reported in the runtimes bucket')

# Read-only rootfs: no heap metrics are possible, so it must NOT be in
# the jvm bucket — and must NOT vanish entirely either.
if any((p or '').startswith('zipkin-readonly-rootfs') for p in jvm_pods):
raise SystemExit('zipkin-readonly-rootfs has no hsperfdata and must not appear in the jvm bucket')
m_ro = [m for m in runtime.get('runtimes', [])
if (m.get('pod') or '').startswith('zipkin-readonly-rootfs')]
if not m_ro:
raise SystemExit(
'zipkin-readonly-rootfs missing from BOTH buckets — a JVM without hsperfdata '
f'must fall back to the runtimes bucket; got runtimes={all_runtime_pods} jvm={jvm_pods}')
if m_ro[0].get('runtime') != 'java':
raise SystemExit(f'zipkin-readonly-rootfs expected runtime="java"; got {m_ro[0]!r}')
# Version still resolves passively (JAVA_VERSION env in the image).
if not (m_ro[0].get('version') or '').startswith('21.'):
raise SystemExit(f'zipkin-readonly-rootfs expected a 21.x version from env; got {m_ro[0]!r}')
if m_ro[0].get('version_source') != 'env':
raise SystemExit(f'zipkin-readonly-rootfs expected version_source=env; got {m_ro[0]!r}')
if m_ro[0].get('namespace') != 'jvm-spike' or not m_ro[0].get('container_id'):
raise SystemExit(f'zipkin-readonly-rootfs has bad pod metadata: {m_ro[0]!r}')

# ============ Generic runtimes bucket ============
# dotnet-app deliberately exercises the apphost probe path (comm is the
# app name, not "dotnet"); go-app exercises the buildinfo probe.
Expand Down
15 changes: 15 additions & 0 deletions .github/actions/tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ runs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
# setup-go runs `go version` / `go env` from the workspace root. In the
# services monorepo that is the root module, whose newer go line would make
# GOTOOLCHAIN=auto download that toolchain (unused, and it collides with the
# cache restore). local keeps the Go this module's go.mod asks for.
env:
GOTOOLCHAIN: local
with:
go-version-file: ${{ inputs.working-directory }}/go.mod
cache: true
Expand All @@ -34,6 +40,15 @@ runs:
working-directory: ${{ inputs.working-directory }}
run: go mod download

# helm-chart/*/chart_resources_test.go shells out to `helm template`, and
# skips itself when helm is absent. Install it explicitly so the chart
# guards actually run instead of reporting a silent green -- the runner
# image is not guaranteed to carry helm. Pinned to the same version the
# tunr chart tests use (.github/workflows/tunr-test.yml).
- uses: azure/setup-helm@v5
with:
version: "3.12.3"

- name: Run make test
shell: bash
working-directory: ${{ inputs.working-directory }}
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/chart-zxporter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ jobs:
- name: Package and push chart
run: |
rm -f helm-chart/zxporter/charts/zxporter-nodemon-*.tgz
# Vendor nodemon's own devzero-common first, so the nodemon copy
# bundled into this chart is complete on its own.
helm dependency build helm-chart/zxporter-nodemon
helm dependency update helm-chart/${{ env.CHART_NAME }}
helm lint helm-chart/${{ env.CHART_NAME }}
mkdir -p helm-chart/packages
Expand Down
18 changes: 6 additions & 12 deletions .github/workflows/image-netmon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ jobs:
if [[ ! "$VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
echo "::error::version '$VERSION' must match vX.Y.Z"; exit 1
fi
# The image's version interface (KUB-151 S7). The Dockerfile splits
# VERSION into the major/minor/patch the binary reports.
{
echo "MAJOR=${BASH_REMATCH[1]}"
echo "MINOR=${BASH_REMATCH[2]}"
echo "PATCH=${BASH_REMATCH[3]}"
echo "GITVERSION=${VERSION}"
echo "COMMIT_HASH=$(git rev-parse --short HEAD)"
echo "GIT_TREE_STATE=clean"
echo "VERSION=${VERSION}"
echo "COMMIT=$(git rev-parse --short HEAD)"
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
} >> "$GITHUB_ENV"

Expand Down Expand Up @@ -82,12 +80,8 @@ jobs:
-t public.ecr.aws/devzeroinc/zxporter-netmon:${{ inputs.version }} \
--build-arg TARGETOS \
--build-arg TARGETARCH \
--build-arg MAJOR="$MAJOR" \
--build-arg MINOR="$MINOR" \
--build-arg PATCH="$PATCH" \
--build-arg GITVERSION="$GITVERSION" \
--build-arg COMMIT_HASH="$COMMIT_HASH" \
--build-arg GIT_TREE_STATE="$GIT_TREE_STATE" \
--build-arg VERSION="$VERSION" \
--build-arg COMMIT="$COMMIT" \
--build-arg BUILD_DATE="$BUILD_DATE" \
-f Dockerfile.netmon \
.
18 changes: 6 additions & 12 deletions .github/workflows/image-nodemon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ jobs:
if [[ ! "$VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
echo "::error::version '$VERSION' must match vX.Y.Z"; exit 1
fi
# The image's version interface (KUB-151 S7). The Dockerfile splits
# VERSION into the major/minor/patch the binary reports.
{
echo "MAJOR=${BASH_REMATCH[1]}"
echo "MINOR=${BASH_REMATCH[2]}"
echo "PATCH=${BASH_REMATCH[3]}"
echo "GITVERSION=${VERSION}"
echo "COMMIT_HASH=$(git rev-parse --short HEAD)"
echo "GIT_TREE_STATE=clean"
echo "VERSION=${VERSION}"
echo "COMMIT=$(git rev-parse --short HEAD)"
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
} >> "$GITHUB_ENV"

Expand Down Expand Up @@ -82,12 +80,8 @@ jobs:
-t public.ecr.aws/devzeroinc/zxporter-nodemon:${{ inputs.version }} \
--build-arg TARGETOS \
--build-arg TARGETARCH \
--build-arg MAJOR="$MAJOR" \
--build-arg MINOR="$MINOR" \
--build-arg PATCH="$PATCH" \
--build-arg GITVERSION="$GITVERSION" \
--build-arg COMMIT_HASH="$COMMIT_HASH" \
--build-arg GIT_TREE_STATE="$GIT_TREE_STATE" \
--build-arg VERSION="$VERSION" \
--build-arg COMMIT="$COMMIT" \
--build-arg BUILD_DATE="$BUILD_DATE" \
-f Dockerfile.nodemon \
.
Loading
Loading