Skip to content

ci: enable selective x86 E2E execution #24077

ci: enable selective x86 E2E execution

ci: enable selective x86 E2E execution #24077

name: Build x86 Image
run-name: ${{ github.event_name == 'workflow_dispatch' && format('x86-e2e pr={0} head={1} approval={2} generation={3} mode={4} groups={5} labels={6} full={7}', inputs.prNumber, inputs.headSHA, inputs.approvalGeneration, inputs.dispatchGeneration, inputs.automatic && 'automatic' || 'approved', inputs.requestedGroupNames, inputs.controlledLabelNames, inputs.full && '1' || '0') || '' }}
permissions:
contents: read
packages: read
defaults:
run:
shell: >-
/usr/bin/env -u ACTIONS_RUNTIME_TOKEN -u ACTIONS_RUNTIME_URL -u ACTIONS_RESULTS_URL
-u ACTIONS_CACHE_URL -u ACTIONS_ID_TOKEN_REQUEST_TOKEN -u ACTIONS_ID_TOKEN_REQUEST_URL
-u LD_PRELOAD -u LD_LIBRARY_PATH -u BASH_ENV -u ENV -u PYTHONPATH -u PYTHONHOME
-u NODE_OPTIONS -u PERL5OPT -u RUBYOPT -u GIT_CONFIG_COUNT
python3 -c "import os,pathlib,shutil,subprocess,sys,tempfile;
realEnv=os.environ['GITHUB_ENV']; shadowDir=tempfile.mkdtemp();
os.environ['GITHUB_ENV']=shadowDir+'/env'; os.environ['GITHUB_PATH']=shadowDir+'/path';
pathlib.Path(os.environ['GITHUB_ENV']).touch(); pathlib.Path(os.environ['GITHUB_PATH']).touch();
result=subprocess.run(['bash','--noprofile','--norc','-e','-o','pipefail',sys.argv[1]],env=os.environ);
allowed=('TAG','GO_VERSION','E2E_DIR','VERSION','DEBUG_WRAPPER');
lines=[line for line in pathlib.Path(os.environ['GITHUB_ENV']).read_text().splitlines() if line.partition('=')[0] in allowed];
open(realEnv,'a').write(('\n'.join(lines)+'\n') if lines else '');
shutil.rmtree(shadowDir); sys.exit(result.returncode)" {0}
on:
pull_request:
branches:
- master
- release-*
paths-ignore:
- 'docs/**'
- '**.md'
push:
branches:
- master
- release-*
paths-ignore:
- 'docs/**'
- '**.md'
workflow_dispatch:
inputs:
prNumber:
description: Open pull request number
required: true
type: number
headSHA:
description: Exact current pull request HEAD SHA
required: true
type: string
baseSHA:
description: Exact trusted pull request base SHA
required: true
type: string
approvalGeneration:
description: Durable authorized comment generation
required: true
type: number
automatic:
description: Execute automatic smoke or fail-closed full coverage
required: true
default: false
type: boolean
dispatchGeneration:
description: Unique trusted reducer run generation
required: true
type: number
requestedGroups:
description: JSON array of explicitly requested stable groups
required: true
default: '[]'
type: string
requestedGroupNames:
description: Canonical comma-separated groups, or a single dash
required: true
default: '-'
type: string
controlledLabels:
description: JSON array of trusted persistent E2E labels
required: true
default: '[]'
type: string
controlledLabelNames:
description: Canonical comma-separated controlled labels, or a single dash
required: true
default: '-'
type: string
full:
description: Run the complete x86 E2E suite
required: true
default: false
type: boolean
requestKey:
description: Dispatcher-generated idempotency key
required: true
type: string
catalogRevision:
description: Trusted E2E catalog revision bound by the dispatcher
required: true
type: string
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-{1}', github.workflow, inputs.requestKey) || format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: true
env:
EXECUTION_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || inputs.headSHA || github.sha }}
# renovate: datasource=github-releases depName=kind packageName=kubernetes-sigs/kind
KIND_VERSION: v0.32.0
# renovate: datasource=github-releases depName=golangci-lint packageName=golangci/golangci-lint
GOLANGCI_LINT_VERSION: v2.12.2
# renovate: datasource=github-releases depName=helm packageName=helm/helm
HELM_VERSION: v4.2.4
# renovate: datasource=github-releases depName=submariner packageName=submariner-io/submariner
SUBMARINER_VERSION: 0.24.0
# renovate: datasource=github-releases depName=talos packageName=siderolabs/talos
TALOS_VERSION: v1.13.8
jobs:
e2e-selection:
name: x86 E2E Selection
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ github.event_name == 'workflow_dispatch' && github.token || '' }}
PYTHONDONTWRITEBYTECODE: "1"
outputs:
executionJobIds: ${{ steps.outputs.outputs.executionJobIds }}
k8sConformanceMatrix: ${{ steps.outputs.outputs.k8sConformanceMatrix || steps.fallbackMatrices.outputs.k8sConformanceMatrix }}
kubeOvnConformanceMatrix: ${{ steps.outputs.outputs.kubeOvnConformanceMatrix || steps.fallbackMatrices.outputs.kubeOvnConformanceMatrix }}
headSHA: ${{ steps.context.outputs.headSHA }}
baseSHA: ${{ steps.context.outputs.baseSHA }}
prNumber: ${{ steps.context.outputs.prNumber }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.baseSHA || github.sha }}
persist-credentials: false
fetch-depth: 0
- name: Initialize fail-closed conformance matrices
id: fallbackMatrices
if: always()
run: |
matrix='{"include":[{"ip-family":"ipv4","mode":"overlay"},{"ip-family":"ipv4","mode":"underlay"},{"ip-family":"ipv6","mode":"overlay"},{"ip-family":"ipv6","mode":"underlay"},{"ip-family":"dual","mode":"overlay"},{"ip-family":"dual","mode":"underlay"}]}'
echo "k8sConformanceMatrix=$matrix" >> "$GITHUB_OUTPUT"
echo "kubeOvnConformanceMatrix=$matrix" >> "$GITHUB_OUTPUT"
- name: Collect trusted selection context
id: context
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_HEAD_SHA: ${{ inputs.headSHA }}
INPUT_BASE_SHA: ${{ inputs.baseSHA }}
INPUT_AUTOMATIC: ${{ inputs.automatic }}
INPUT_CONTROLLED_LABELS: ${{ inputs.controlledLabels }}
INPUT_CONTROLLED_LABEL_NAMES: ${{ inputs.controlledLabelNames }}
INPUT_PR_NUMBER: ${{ inputs.prNumber }}
INPUT_REQUESTED_GROUPS: ${{ inputs.requestedGroups }}
INPUT_REQUESTED_GROUP_NAMES: ${{ inputs.requestedGroupNames }}
INPUT_CATALOG_REVISION: ${{ inputs.catalogRevision }}
INPUT_FULL: ${{ inputs.full }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
printf '{}' > selector-event.json
: > changed-paths.txt
requestFull=false
forceFullReason=''
requestedGroups='[]'
headSHA="$GITHUB_SHA"
baseSHA="$GITHUB_SHA"
prNumber=0
checkedOutSHA=$(git rev-parse HEAD)
if [ "$EVENT_NAME" = workflow_dispatch ] && [ "$checkedOutSHA" != "$INPUT_BASE_SHA" ]; then
echo 'trusted selector checkout does not match the approved base revision' >&2
exit 1
fi
if [ "$EVENT_NAME" = pull_request ]; then
git diff --name-status --diff-filter=ACDMRT -z -M \
"$PR_BASE_SHA...$PR_HEAD_SHA" > changed-name-status.bin
python3 - <<'PY'
import sys
from pathlib import Path
sys.path.insert(0, "hack")
import e2e_selector as e2eSelector
paths = e2eSelector.changedPathsFromNameStatus(
Path("changed-name-status.bin").read_bytes()
)
Path("changed-paths.txt").write_bytes(
b"".join(path.encode("utf-8", errors="surrogateescape") + b"\0" for path in paths)
)
PY
cp "$GITHUB_EVENT_PATH" selector-event.json
python3 - <<'PY'
import json
from pathlib import Path
event = json.loads(Path("selector-event.json").read_text())
event["pull_request"]["labels"] = []
Path("selector-event.json").write_text(json.dumps(event))
PY
headSHA="$PR_HEAD_SHA"
baseSHA="$PR_BASE_SHA"
prNumber="$PR_NUMBER"
elif [ "$EVENT_NAME" = workflow_dispatch ]; then
gh api "repos/$GITHUB_REPOSITORY/pulls/$INPUT_PR_NUMBER" > pull-request.json
python3 - "$INPUT_HEAD_SHA" "$INPUT_BASE_SHA" "$GITHUB_REF_NAME" "$GITHUB_SHA" <<'PY'
import json
import os
import re
import sys
from pathlib import Path
pullRequest = json.loads(Path("pull-request.json").read_text())
if pullRequest.get("state") != "open":
raise SystemExit("pull request is not open")
if not re.fullmatch(r"[0-9a-f]{40}", sys.argv[1]):
raise SystemExit("invalid requested HEAD SHA")
if pullRequest["head"]["sha"] != sys.argv[1]:
raise SystemExit("pull request HEAD changed; dispatch again")
if pullRequest["base"]["sha"] != sys.argv[2]:
raise SystemExit("pull request base revision changed; dispatch again")
if pullRequest["base"]["ref"] != sys.argv[3]:
raise SystemExit("executor must run from the pull request base branch")
if sys.argv[4] != sys.argv[2]:
raise SystemExit("executor workflow revision does not match the approved base")
controlledLabels = json.loads(os.environ["INPUT_CONTROLLED_LABELS"])
if not isinstance(controlledLabels, list) or any(
not isinstance(label, str) for label in controlledLabels
):
raise SystemExit("controlledLabels must be a JSON array of strings")
if os.environ["INPUT_AUTOMATIC"] != "true":
controlledLabels = []
pullRequest["labels"] = [{"name": label} for label in controlledLabels]
Path("selector-event.json").write_text(json.dumps({"pull_request": pullRequest}))
PY
gh api --paginate --slurp \
"repos/$GITHUB_REPOSITORY/pulls/$INPUT_PR_NUMBER/files?per_page=100" > pull-request-files.json
python3 - <<'PY'
import json
from pathlib import Path
pullRequest = json.loads(Path("pull-request.json").read_text())
pages = json.loads(Path("pull-request-files.json").read_text())
changedFiles = [changedFile for page in pages for changedFile in page]
expectedCount = pullRequest.get("changed_files")
if (
not isinstance(expectedCount, int)
or expectedCount >= 3000
or expectedCount != len(changedFiles)
):
Path("force-full-reason.txt").write_text(
"pull request file list is incomplete; the full suite is required"
)
with Path("changed-paths.txt").open("wb") as stream:
for changedFile in changedFiles:
for field in ("previous_filename", "filename"):
if field in changedFile:
stream.write(changedFile[field].encode() + b"\0")
PY
if [ -s force-full-reason.txt ]; then
forceFullReason=$(cat force-full-reason.txt)
fi
python3 - "$INPUT_REQUESTED_GROUPS" "$INPUT_REQUESTED_GROUP_NAMES" "$INPUT_CATALOG_REVISION" "$INPUT_CONTROLLED_LABELS" "$INPUT_CONTROLLED_LABEL_NAMES" "$INPUT_AUTOMATIC" "$INPUT_FULL" <<'PY'
import hashlib
import json
import sys
from pathlib import Path
groups = json.loads(sys.argv[1])
if not isinstance(groups, list) or any(not isinstance(group, str) for group in groups):
raise SystemExit("requestedGroups must be a JSON array of strings")
canonicalGroups = sorted(set(groups))
catalog = json.loads(Path(".github/e2e-selection.json").read_text())
catalogRevision = hashlib.sha256(
json.dumps(catalog, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
if catalogRevision != sys.argv[3]:
raise SystemExit("executor catalog revision does not match dispatcher")
unknownGroups = sorted(set(canonicalGroups) - set(catalog["groups"]))
if unknownGroups:
raise SystemExit(f"unknown requested E2E group: {unknownGroups[0]}")
canonical = ",".join(canonicalGroups) or "-"
if canonical != sys.argv[2]:
raise SystemExit("requested group names do not match requestedGroups")
labels = json.loads(sys.argv[4])
knownLabels = {"e2e:full"} | {f"e2e:{group}" for group in catalog["groups"]}
if (
not isinstance(labels, list)
or any(not isinstance(label, str) for label in labels)
or set(labels) - knownLabels
):
raise SystemExit("controlledLabels contains an unknown label")
canonicalLabels = ",".join(sorted(set(labels))) or "-"
if canonicalLabels != sys.argv[5]:
raise SystemExit("controlled label names do not match controlledLabels")
automatic = sys.argv[6] == "true"
if automatic and (canonicalGroups or sys.argv[7] == "true"):
raise SystemExit("automatic execution cannot contain an approved request")
if not automatic and labels:
raise SystemExit("approved execution cannot carry automatic controlled labels")
PY
headSHA="$INPUT_HEAD_SHA"
baseSHA="$INPUT_BASE_SHA"
prNumber="$INPUT_PR_NUMBER"
requestedGroups="$INPUT_REQUESTED_GROUPS"
requestFull="$INPUT_FULL"
else
forceFullReason='push events always run the full x86 E2E suite'
fi
echo "headSHA=$headSHA" >> "$GITHUB_OUTPUT"
echo "baseSHA=$baseSHA" >> "$GITHUB_OUTPUT"
echo "prNumber=$prNumber" >> "$GITHUB_OUTPUT"
echo "requestFull=$requestFull" >> "$GITHUB_OUTPUT"
echo "forceFullReason=$forceFullReason" >> "$GITHUB_OUTPUT"
echo "requestedGroups=$requestedGroups" >> "$GITHUB_OUTPUT"
- name: Compute the selection plan
env:
FORCE_FULL_REASON: ${{ steps.context.outputs.forceFullReason }}
HEAD_SHA: ${{ steps.context.outputs.headSHA }}
REQUESTED_FULL: ${{ steps.context.outputs.requestFull }}
REQUESTED_GROUPS: ${{ steps.context.outputs.requestedGroups }}
run: |
args=(
--paths-file changed-paths.txt
--event-file selector-event.json
--request-groups-json "$REQUESTED_GROUPS"
--head-sha "$HEAD_SHA"
--base-sha "${{ steps.context.outputs.baseSHA }}"
--pr-number "${{ steps.context.outputs.prNumber }}"
--force-full-reason "$FORCE_FULL_REASON"
--plan-file e2e-selection-plan.json
--summary-file e2e-selection-summary.md
)
if [ "$REQUESTED_FULL" = true ]; then
args+=(--request-full)
fi
python3 hack/e2e_selector.py "${args[@]}"
- name: Export executor job IDs
id: outputs
env:
EVENT_NAME: ${{ inputs.automatic && 'pull_request' || github.event_name }}
run: |
python3 - <<'PY'
import json
import os
import sys
from pathlib import Path
sys.path.insert(0, "hack")
import e2e_selector as e2eSelector
try:
catalog = e2eSelector.loadCatalog(".github/e2e-selection.json")
except Exception as error:
print(f"failed to reload the E2E catalog: {error}", file=sys.stderr)
catalog = None
plan = json.loads(Path("e2e-selection-plan.json").read_text())
executionPlan = e2eSelector.executionPlan(catalog, plan, os.environ["EVENT_NAME"])
e2eSelector.writePlan(
executionPlan,
e2eSelector.readPaths("changed-paths.txt"),
"e2e-selection-plan.json",
"e2e-selection-summary.md",
)
jobIds = sorted({entry["job"] for entry in executionPlan["matrix"]})
matrices = {
"k8sConformanceMatrix": e2eSelector.jobMatrix(
executionPlan,
"k8s-conformance-e2e",
),
"kubeOvnConformanceMatrix": e2eSelector.jobMatrix(
executionPlan,
"kube-ovn-conformance-e2e",
),
}
with Path(os.environ["GITHUB_OUTPUT"]).open("a") as stream:
stream.write("executionJobIds=" + json.dumps(jobIds, separators=(",", ":")) + "\n")
for name, matrix in matrices.items():
stream.write(name + "=" + json.dumps(matrix, separators=(",", ":")) + "\n")
PY
cat e2e-selection-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload the selection plan
if: always()
uses: actions/upload-artifact@v7
with:
name: x86-e2e-selection-${{ steps.context.outputs.prNumber }}-${{ steps.context.outputs.headSHA }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
changed-paths.txt
e2e-selection-plan.json
e2e-selection-summary.md
retention-days: 30
e2e-control-validation:
name: Validate x86 E2E control modules
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
permissions:
contents: read
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.baseSHA || github.sha }}
persist-credentials: false
- name: Run control module tests
run: python3 -m unittest hack/test_e2e_selector.py hack/test_e2e_control.py
prepare-kind-node-images:
name: Prepare private Kind node image (${{ matrix.k8s-version }})
if: >-
(github.event_name == 'workflow_dispatch' && github.actor == 'github-actions[bot]') ||
github.event_name == 'push'
needs: e2e-selection
permissions:
contents: read
packages: read
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
k8s-version:
- v1.36.1
- v1.29.14
steps:
- name: Pull private Kind node image with trusted token
env:
GHCR_TOKEN: ${{ github.token }}
K8S_VERSION: ${{ matrix.k8s-version }}
run: |
set -euo pipefail
dockerConfig=$(mktemp -d)
trap 'rm -rf "$dockerConfig"' EXIT
export DOCKER_CONFIG="$dockerConfig"
printf '%s' "$GHCR_TOKEN" | docker login ghcr.io -u github-actions --password-stdin
docker pull "ghcr.io/kubeovn/kindest-node:$K8S_VERSION"
docker tag "ghcr.io/kubeovn/kindest-node:$K8S_VERSION" "kindest/node:$K8S_VERSION"
docker save "kindest/node:$K8S_VERSION" -o "kind-node-$K8S_VERSION.tar"
- name: Upload private Kind node image without credentials
uses: actions/upload-artifact@v7
with:
name: kind-node-${{ matrix.k8s-version }}
path: kind-node-${{ matrix.k8s-version }}.tar
retention-days: 2
build-kube-ovn-base:
name: Build kube-ovn-base
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
runs-on: ubuntu-24.04
outputs:
build-base: ${{ steps.check.outputs.build-base }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
fetch-depth: 0
- id: check
run: |
if [ ${{ github.event_name }} != 'pull_request' ]; then
exit
fi
tmp_dir=`mktemp -d`
cat > "$tmp_dir/on_changes.txt" <<EOF
dist/images/Dockerfile.base
dist/images/OpenBFDD-compile.patch
dist/images/patches/
dist/images/go-deps/download-go-deps.sh
dist/images/go-deps/rebuild-go-deps.sh
EOF
if git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" | grep -Ff "$tmp_dir/on_changes.txt"; then
echo build-base=1 >> "$GITHUB_OUTPUT"
fi
rm -frv "$tmp_dir"
- uses: jlumbroso/free-disk-space@v1.3.1
if: steps.check.outputs.build-base == 1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: docker/setup-buildx-action@v4
if: steps.check.outputs.build-base == 1
with:
driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=50000000
- uses: actions/setup-go@v7
if: steps.check.outputs.build-base == 1
id: setup-go
with:
go-version-file: go.mod
check-latest: true
cache: false
- name: Build kube-ovn-base image
id: build
if: steps.check.outputs.build-base == 1
env:
GO_VERSION: ${{ steps.setup-go.outputs.go-version }}
run: |
make base-amd64
make base-tar-amd64
- name: Upload base images to artifact
if: steps.check.outputs.build-base == 1
uses: actions/upload-artifact@v7
with:
name: kube-ovn-base
path: image-amd64.tar
build-kube-ovn-dpdk-base:
name: Build kube-ovn-dpdk-base
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
runs-on: ubuntu-24.04
outputs:
build-dpdk-base: ${{ steps.check.outputs.build-dpdk-base }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
fetch-depth: 0
- id: check
run: |
if [ ${{ github.event_name }} != 'pull_request' ]; then
exit
fi
tmp_dir=`mktemp -d`
cat > "$tmp_dir/on_changes.txt" <<EOF
dist/images/Dockerfile.base-dpdk
dist/images/patches/
EOF
if git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" | grep -Ff "$tmp_dir/on_changes.txt"; then
echo build-dpdk-base=1 >> "$GITHUB_OUTPUT"
fi
rm -frv "$tmp_dir"
- uses: jlumbroso/free-disk-space@v1.3.1
if: steps.check.outputs.build-dpdk-base == 1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: docker/setup-buildx-action@v4
if: steps.check.outputs.build-dpdk-base == 1
- name: Build kube-ovn-dpdk-base image
id: build
if: steps.check.outputs.build-dpdk-base == 1
run: |
make base-amd64-dpdk
make base-tar-amd64-dpdk
- name: Upload dpdk base images to artifact
if: steps.check.outputs.build-dpdk-base == 1
uses: actions/upload-artifact@v7
with:
name: kube-ovn-dpdk-base
path: image-amd64-dpdk.tar
build-kube-ovn:
name: Build kube-ovn
runs-on: ubuntu-24.04
needs:
- e2e-selection
- prepare-kind-node-images
- build-kube-ovn-base
- build-kube-ovn-dpdk-base
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- uses: docker/setup-buildx-action@v4
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: go.mod
check-latest: true
cache: false
- name: Setup environment variables
run: |
echo "TAG=$(cat VERSION)" >> "$GITHUB_ENV"
echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
if: github.event_name == 'push'
uses: actions/cache@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Unit test
run: make ut
- uses: shogo82148/actions-goveralls@v1
continue-on-error: true
with:
path-to-profile: profile.cov
- name: Install golangci-lint
run: |
curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b $(go env GOPATH)/bin $GOLANGCI_LINT_VERSION
- name: Download base images
if: needs.build-kube-ovn-base.outputs.build-base == 1
uses: actions/download-artifact@v8
with:
name: kube-ovn-base
- name: Load base images
if: needs.build-kube-ovn-base.outputs.build-base == 1
run: |
docker load --input image-amd64.tar
docker tag kubeovn/kube-ovn-base:$TAG-amd64 kubeovn/kube-ovn-base:$TAG
docker tag kubeovn/kube-ovn-base:$TAG-debug-amd64 kubeovn/kube-ovn-base:$TAG-debug
- name: Download dpdk base images
if: needs.build-kube-ovn-dpdk-base.outputs.build-dpdk-base == 1
uses: actions/download-artifact@v8
with:
name: kube-ovn-dpdk-base
- name: Load dpdk base images
if: needs.build-kube-ovn-dpdk-base.outputs.build-dpdk-base == 1
run: |
docker load --input image-amd64-dpdk.tar
docker tag kubeovn/kube-ovn-base:$TAG-amd64-dpdk kubeovn/kube-ovn-base:$TAG-dpdk
- name: Scan base image
uses: aquasecurity/trivy-action@v0.36.0
env:
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
with:
scan-type: image
scanners: vuln
image-ref: docker.io/kubeovn/kube-ovn-base:${{ env.TAG }}
format: json
output: trivy-result.json
ignore-unfixed: true
trivyignores: .trivyignore
vuln-type: library
- name: Build kubectl and CNI plugins from source
env:
CGO_ENABLED: "0"
GO_INSTALL: "go install -v -mod=mod -trimpath"
run: |
go mod tidy
cat trivy-result.json
dockerfile=${{ github.workspace }}/dist/images/Dockerfile
export GOBIN=`dirname "$dockerfile"`
cni_plugins_version=`go list -m -f '{{.Version}}' github.com/containernetworking/plugins`
cni_plugins_build_flags="-ldflags '-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=$cni_plugins_version'"
jq -r '.Results[] | select((.Type=="gobinary") and (.Vulnerabilities!=null)) | .Target' trivy-result.json | while read f; do
bin=`basename $f`
case $bin in
loopback|macvlan|ipvlan)
echo "Building $bin@$cni_plugins_version from source..."
sh -c "$GO_INSTALL $cni_plugins_build_flags github.com/containernetworking/plugins/plugins/main/$bin"
echo "COPY $bin /$f" >> "$dockerfile"
;;
portmap)
echo "Building $bin@$cni_plugins_version from source..."
sh -c "$GO_INSTALL $cni_plugins_build_flags github.com/containernetworking/plugins/plugins/meta/$bin"
echo "COPY $bin /$f" >> "$dockerfile"
;;
kubectl)
version=`go list -m -f '{{.Version}}' k8s.io/kubernetes`
mod_dir=`go list -m -f '{{.Dir}}' k8s.io/kubernetes`
source "$mod_dir/hack/lib/util.sh"
source "$mod_dir/hack/lib/logging.sh"
source "$mod_dir/hack/lib/version.sh"
repo=kubernetes/kubernetes
commit=unknown
read type tag_sha < <(echo $(curl -s "https://api.github.com/repos/$repo/git/ref/tags/$version" |
jq -r '.object.type,.object.sha'))
if [ $type = "commit" ]; then
commit=$tag_sha
else
commit=$(curl -s "https://api.github.com/repos/$repo/git/tags/$tag_sha" | jq -r '.object.sha')
fi
export KUBE_GIT_COMMIT="${commit}"
export KUBE_GIT_TREE_STATE='clean'
export KUBE_GIT_VERSION="${version}"
export KUBE_GIT_MAJOR=`echo $KUBE_GIT_VERSION | cut -d. -f1 | sed 's/$v//'`
export KUBE_GIT_MINOR=`echo $KUBE_GIT_VERSION | cut -d. -f2`
goldflags="all=$(kube::version::ldflags) -s -w"
echo "Building $bin@$version from source..."
$GO_INSTALL -ldflags="${goldflags}" k8s.io/kubernetes/cmd/kubectl
echo "COPY $bin /$f" >> "$dockerfile"
;;
gobgp)
version=`go list -m -f '{{.Version}}' github.com/osrg/gobgp/v4`
echo "Building $bin@$version from source..."
$GO_INSTALL github.com/osrg/gobgp/v4/cmd/$bin
echo "COPY $bin /$f" >> "$dockerfile"
;;
*)
;;
esac
done
- name: Build
run: |
go mod tidy
git diff --exit-code -- go.mod go.sum
make verify-crd
make lint
if [ ${{ needs.build-kube-ovn-base.outputs.build-base || 0 }} = 1 ]; then
make build-kube-ovn
else
make image-kube-ovn
fi
make tar-kube-ovn
- name: Build dpdk
run: |
if [ ${{ needs.build-kube-ovn-dpdk-base.outputs.build-dpdk-base || 0 }} = 1 ]; then
make build-kube-ovn-dpdk
else
make image-kube-ovn-dpdk
fi
make tar-kube-ovn-dpdk
- name: Upload images to artifact
uses: actions/upload-artifact@v7
with:
name: kube-ovn
path: kube-ovn.tar
- name: Upload dpdk images to artifact
uses: actions/upload-artifact@v7
if: github.event_name != 'pull_request'
with:
name: kube-ovn-dpdk
path: kube-ovn-dpdk.tar
build-vpc-nat-gateway:
name: Build vpc-nat-gateway
needs: e2e-selection
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
runs-on: ubuntu-24.04
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Build
run: |
make image-vpc-nat-gateway
make tar-vpc-nat-gateway
- name: Upload image to artifact
uses: actions/upload-artifact@v7
with:
name: vpc-nat-gateway
path: vpc-nat-gateway.tar
build-e2e-binaries:
name: Build E2E Binaries
needs: e2e-selection
if: github.event_name != 'workflow_dispatch' || github.actor == 'github-actions[bot]'
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Lookup Go cache
id: lookup-go-cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
lookup-only: true
- uses: jlumbroso/free-disk-space@v1.3.1
if: steps.lookup-go-cache.outputs.cache-hit != 'true'
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- name: Go cache
if: steps.lookup-go-cache.outputs.cache-hit != 'true' && github.event_name == 'push'
uses: actions/cache@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- run: make e2e-build
if: steps.lookup-go-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.E2E_DIR }}
k8s-conformance-e2e:
name: Kubernetes Conformance E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'k8s-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 25
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.e2e-selection.outputs.k8sConformanceMatrix) }}
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Remove DNS search domain
run: |
sudo sed -i '/^search/d' /etc/resolv.conf
sudo systemctl restart docker
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.mode }}-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: ${{ matrix.mode }}
run: make k8s-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-events.yaml
tar zcf k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-events.tar.gz k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-events
path: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-audit-log
path: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log
path: k8s-conformance-e2e-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log.tar.gz
- name: Check valgrind result
run: |
if [ "x$DEBUG_WRAPPER" != "xvalgrind" ]; then
exit
fi
kubectl -n kube-system rollout restart ds ovs-ovn
kubectl -n kube-system rollout status ds ovs-ovn
sleep 10
kubectl -n kube-system rollout restart deploy ovn-central
kubectl -n kube-system rollout status deploy ovn-central
while true; do
if [ $(kubectl -n kube-system get pod -l app=ovs -o name | wc -l) -eq $(kubectl get node -o name | wc -l) ]; then
break
fi
sleep 1
done
kubectl ko log ovn
kubectl ko log ovs
for daemon in ovsdb-nb ovsdb-sb ovn-northd ovn-controller ovsdb-server ovs-vswitchd; do
echo "Checking if valgrind log file for $daemon exists..."
find kubectl-ko-log -type f -name "$daemon.valgrind.log.[[:digit:]]*" -exec false {} + && exit 1
done
find kubectl-ko-log -type f -name '*.valgrind.log.*' | while read f; do
if grep -qw 'definitely lost' "$f"; then
echo "Memory leak detected in $(basename $f | awk -F. '{print $1}')."
echo $f
cat "$f"
exit 1
fi;
done
k8s-netpol-e2e:
name: Kubernetes Network Policy E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'k8s-netpol-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
np-enforcement:
- standard
- lax
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Remove DNS search domain
run: |
sudo sed -i '/^search/d' /etc/resolv.conf
sudo systemctl restart docker
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
env:
NP_ENFORCEMENT: "${{ matrix.np-enforcement }}"
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
run: make k8s-netpol-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > k8s-netpol-e2e-${{ matrix.ip-family }}-events.yaml
tar zcf k8s-netpol-e2e-${{ matrix.ip-family }}-events.tar.gz k8s-netpol-e2e-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: k8s-netpol-e2e-${{ matrix.ip-family }}-events
path: k8s-netpol-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf k8s-netpol-e2e-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: k8s-netpol-e2e-${{ matrix.ip-family }}-audit-log
path: k8s-netpol-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz k8s-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: k8s-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log
path: k8s-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log.tar.gz
- name: Check valgrind result
run: |
if [ "x$DEBUG_WRAPPER" != "xvalgrind" ]; then
exit
fi
kubectl -n kube-system rollout restart ds ovs-ovn
kubectl -n kube-system rollout status ds ovs-ovn
sleep 10
kubectl -n kube-system rollout restart deploy ovn-central
kubectl -n kube-system rollout status deploy ovn-central
while true; do
if [ $(kubectl -n kube-system get pod -l app=ovs -o name | wc -l) -eq $(kubectl get node -o name | wc -l) ]; then
break
fi
sleep 1
done
kubectl ko log ovn
kubectl ko log ovs
for daemon in ovsdb-nb ovsdb-sb ovn-northd ovn-controller ovsdb-server ovs-vswitchd; do
echo "Checking if valgrind log file for $daemon exists..."
find kubectl-ko-log -type f -name "$daemon.valgrind.log.[[:digit:]]*" -exec false {} + && exit 1
done
find kubectl-ko-log -type f -name '*.valgrind.log.*' | while read f; do
if grep -qw 'definitely lost' "$f"; then
echo "Memory leak detected in $(basename $f | awk -F. '{print $1}')."
echo $f
cat "$f"
exit 1
fi;
done
cyclonus-netpol-e2e:
name: Cyclonus Network Policy E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'cyclonus-netpol-e2e')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
np-enforcement:
- standard
- lax
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
env:
NP_ENFORCEMENT: "${{ matrix.np-enforcement }}"
id: install
run: make kind-install-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
run: make cyclonus-netpol-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > cyclonus-netpol-e2e-${{ matrix.ip-family }}-events.yaml
tar zcf cyclonus-netpol-e2e-${{ matrix.ip-family }}-events.tar.gz cyclonus-netpol-e2e-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: cyclonus-netpol-e2e-${{ matrix.ip-family }}-events
path: cyclonus-netpol-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf cyclonus-netpol-e2e-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: cyclonus-netpol-e2e-${{ matrix.ip-family }}-audit-log
path: cyclonus-netpol-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz cyclonus-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: cyclonus-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log
path: cyclonus-netpol-e2e-${{ matrix.ip-family }}-${{ matrix.np-enforcement }}-ko-log.tar.gz
- name: Check valgrind result
run: |
if [ "x$DEBUG_WRAPPER" != "xvalgrind" ]; then
exit
fi
kubectl -n kube-system rollout restart ds ovs-ovn
kubectl -n kube-system rollout status ds ovs-ovn
sleep 10
kubectl -n kube-system rollout restart deploy ovn-central
kubectl -n kube-system rollout status deploy ovn-central
while true; do
if [ $(kubectl -n kube-system get pod -l app=ovs -o name | wc -l) -eq $(kubectl get node -o name | wc -l) ]; then
break
fi
sleep 1
done
kubectl ko log ovn
kubectl ko log ovs
for daemon in ovsdb-nb ovsdb-sb ovn-northd ovn-controller ovsdb-server ovs-vswitchd; do
echo "Checking if valgrind log file for $daemon exists..."
find kubectl-ko-log -type f -name "$daemon.valgrind.log.[[:digit:]]*" -exec false {} + && exit 1
done
find kubectl-ko-log -type f -name '*.valgrind.log.*' | while read f; do
if grep -qw 'definitely lost' "$f"; then
echo "Memory leak detected in $(basename $f | awk -F. '{print $1}')."
echo $f
cat "$f"
exit 1
fi;
done
kube-ovn-conformance-e2e:
name: Kube-OVN Conformance E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 50
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.e2e-selection.outputs.kubeOvnConformanceMatrix) }}
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.mode }}-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: ${{ matrix.mode }}
run: |
make kube-ovn-conformance-e2e
make kind-install-multus
make kind-install-kubevirt
make kube-ovn-kubevirt-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
tar zcf kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events
path: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log
path: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log
path: kube-ovn-conformance-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: Check valgrind result
run: |
if [ "x$DEBUG_WRAPPER" != "xvalgrind" ]; then
exit
fi
kubectl -n kube-system rollout restart ds ovs-ovn
kubectl -n kube-system rollout status ds ovs-ovn
sleep 10
kubectl -n kube-system rollout restart deploy ovn-central
kubectl -n kube-system rollout status deploy ovn-central
while true; do
if [ $(kubectl -n kube-system get pod -l app=ovs -o name | wc -l) -eq $(kubectl get node -o name | wc -l) ]; then
break
fi
sleep 1
done
kubectl ko log ovn
kubectl ko log ovs
for daemon in ovsdb-nb ovsdb-sb ovn-northd ovn-controller ovsdb-server ovs-vswitchd; do
echo "Checking if valgrind log file for $daemon exists..."
find kubectl-ko-log -type f -name "$daemon.valgrind.log.[[:digit:]]*" -exec false {} + && exit 1
done
find kubectl-ko-log -type f -name '*.valgrind.log.*' | while read f; do
if grep -qw 'definitely lost' "$f"; then
echo "Memory leak detected in $(basename $f | awk -F. '{print $1}')."
echo $f
cat "$f"
exit 1
fi;
done
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
kube-ovn-ic-conformance-e2e:
name: Kube-OVN IC Conformance E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-ic-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-ovn-ic-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-ovn-ic-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
run: make kube-ovn-ic-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
for cluster in `kind get clusters`; do
kubectl config use-context kind-$cluster
kubectl get events -A -o yaml > kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-$cluster-events.yaml
done
tar zcf kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-events.tar.gz \
`kind get clusters | xargs -I {} echo kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-{}-events.yaml`
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-events
path: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
for cluster in `kind get clusters`; do
docker cp $cluster-control-plane:/var/log/kubernetes/kube-apiserver-audit.log \
./kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-$cluster-kube-apiserver-audit.log
done
tar zcvf kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-audit-log.tar.gz \
`kind get clusters | xargs -I {} echo kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-{}-kube-apiserver-audit.log`
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-audit-log
path: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
for cluster in `kind get clusters`; do
kubectl config use-context kind-$cluster
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-$cluster-ko-log.tar.gz
done
tar zcvf kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-ko-log.tar.gz \
`kind get clusters | xargs -I {} echo kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-{}-ko-log.tar.gz`
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-ko-log
path: kube-ovn-ic-conformance-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
multus-conformance-e2e:
name: Multus Conformance E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'multus-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.ip-family }}
- name: Install Multus
run: make kind-install-multus
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
run: make kube-ovn-multus-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > multus-conformance-e2e-${{ matrix.ip-family }}-events.yaml
tar zcf multus-conformance-e2e-${{ matrix.ip-family }}-events.tar.gz multus-conformance-e2e-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: multus-conformance-e2e-${{ matrix.ip-family }}-events
path: multus-conformance-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf multus-conformance-e2e-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: multus-conformance-e2e-${{ matrix.ip-family }}-audit-log
path: multus-conformance-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz multus-conformance-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: multus-conformance-e2e-${{ matrix.ip-family }}-ko-log
path: multus-conformance-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
non-primary-cni-e2e:
name: Non-Primary CNI E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'non-primary-cni-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Remove DNS search domain
run: |
sudo sed -i '/^search/d' /etc/resolv.conf
sudo systemctl restart docker
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Download vpc-nat-gateway image
uses: actions/download-artifact@v8
with:
name: vpc-nat-gateway
- name: Load image
run: |
docker load --input kube-ovn.tar
docker load --input vpc-nat-gateway.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Load vpc-nat-gateway image into kind cluster
run: make kind-load-image-vpc-nat-gateway
- name: Install Mults-CNI, Cilium, and Kube-OVN
id: install
run: make kind-install-multus-cilium-kubeovn-non-primary-${{ matrix.ip-family }}
- name: Run non-primary CNI e2e
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: overlay
KUBE_OVN_PRIMARY_CNI: "false"
run: make kube-ovn-non-primary-cni-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > non-primary-cni-e2e-${{ matrix.ip-family }}-events.yaml
tar zcf non-primary-cni-e2e-${{ matrix.ip-family }}-events.tar.gz non-primary-cni-e2e-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: non-primary-cni-e2e-${{ matrix.ip-family }}-events
path: non-primary-cni-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf non-primary-cni-e2e-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: non-primary-cni-e2e-${{ matrix.ip-family }}-audit-log
path: non-primary-cni-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz non-primary-cni-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: non-primary-cni-e2e-${{ matrix.ip-family }}-ko-log
path: non-primary-cni-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
bgp-speaker-e2e:
name: BGP Speaker E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'bgp-speaker-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load kube-ovn image
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create BGP kind and containerlab topology
id: setup
run: |
pipx install jinjanator
make kind-init-bgp
- name: Install Kube-OVN and BGP speakers
id: install
run: make kind-install-bgp
- name: Run BGP speaker E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ipv4
E2E_NETWORK_MODE: overlay
run: make kube-ovn-bgp-speaker-e2e
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: Collect BGP diagnostics
if: failure() && (steps.setup.conclusion == 'failure' || steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
mkdir -p bgp-speaker-e2e-diagnostics
docker exec clab-bgp-router vtysh -c "show bgp ipv4 unicast summary json" > bgp-speaker-e2e-diagnostics/frr-summary.json || true
docker exec clab-bgp-router vtysh -c "show bgp ipv4 unicast json" > bgp-speaker-e2e-diagnostics/frr-routes.json || true
kubectl -n kube-system get ds kube-ovn-speaker -o yaml > bgp-speaker-e2e-diagnostics/speaker-daemonset.yaml || true
kubectl -n kube-system get pods -l app=kube-ovn-speaker -o wide > bgp-speaker-e2e-diagnostics/speaker-pods.txt || true
kubectl -n kube-system logs -l app=kube-ovn-speaker --all-containers --prefix > bgp-speaker-e2e-diagnostics/speaker.log || true
kubectl get events -A -o yaml > bgp-speaker-e2e-diagnostics/events.yaml || true
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log bgp-speaker-e2e-diagnostics/ || true
tar zcf bgp-speaker-e2e-diagnostics.tar.gz bgp-speaker-e2e-diagnostics
- name: Upload BGP diagnostics
uses: actions/upload-artifact@v7
if: failure() && (steps.setup.conclusion == 'failure' || steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: bgp-speaker-e2e-diagnostics
path: bgp-speaker-e2e-diagnostics.tar.gz
- name: kubectl ko log
if: failure() && (steps.setup.conclusion == 'failure' || steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
if make kubectl-ko-log && test -f kubectl-ko-log.tar.gz; then
mv kubectl-ko-log.tar.gz bgp-speaker-e2e-ko-log.tar.gz
else
echo "kubectl ko log was unavailable because the BGP test cluster did not become usable." > bgp-speaker-e2e-ko-log-unavailable.txt
tar zcf bgp-speaker-e2e-ko-log.tar.gz bgp-speaker-e2e-ko-log-unavailable.txt
fi
- name: Upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.setup.conclusion == 'failure' || steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: bgp-speaker-e2e-ko-log
path: bgp-speaker-e2e-ko-log.tar.gz
- name: Clean BGP topology
if: always()
run: make kind-clean-bgp
kube-ovn-hosted-ovn-central-e2e:
name: Kube-OVN Hosted OVN Central E2E (${{ matrix.ip-family }}, ${{ matrix.tenant-control-plane }} control-plane)
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-hosted-ovn-central-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- ip-family: ipv4
tenant-control-plane: single
tenant-control-plane-replicas: 1
- ip-family: ipv6
tenant-control-plane: single
tenant-control-plane-replicas: 1
- ip-family: dual
tenant-control-plane: single
tenant-control-plane-replicas: 1
- ip-family: ipv4
tenant-control-plane: ha
tenant-control-plane-replicas: 3
- ip-family: ipv6
tenant-control-plane: ha
tenant-control-plane-replicas: 3
- ip-family: dual
tenant-control-plane: ha
tenant-control-plane-replicas: 3
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Remove DNS search domain
run: |
sudo sed -i '/^search/d' /etc/resolv.conf
sudo systemctl restart docker
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: |
docker load --input kube-ovn.tar
docker tag "kubeovn/kube-ovn:$(cat VERSION)" kubeovn/kube-ovn:dev
- name: Verify hosted OVN central values
run: bash hack/kamaji-e2e-test.sh
- name: Create hosted OVN central environment
id: install
env:
E2E_IP_FAMILY: ${{ matrix.ip-family }}
TENANT_CONTROL_PLANE_REPLICAS: ${{ matrix.tenant-control-plane-replicas }}
run: make kind-install-kamaji
- name: Run hosted OVN central E2E
id: e2e
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: overlay
run: make kube-ovn-kamaji-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl --context kind-mgmt get events -A -o yaml > hcp-e2e-mgmt-events.yaml || true
tenant_kubeconfig="$(./hack/kamaji-e2e.sh kubeconfig)"
if [ -s "$tenant_kubeconfig" ]; then
KUBECONFIG="$tenant_kubeconfig" kubectl get events -A -o yaml > hcp-e2e-tenant-events.yaml || true
fi
tar zcf hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-events.tar.gz hcp-e2e-*-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-events
path: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-events.tar.gz
- name: Collect hosted OVN central diagnostics
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
job_dir="${JOB_DIR:-/tmp/kamaji-e2e}"
if [ -d "$job_dir/diagnostics" ]; then
tar -C "$job_dir" -zcf hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-diagnostics.tar.gz diagnostics
fi
- name: Upload hosted OVN central diagnostics
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-diagnostics
path: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-diagnostics.tar.gz
if-no-files-found: ignore
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
tenant_kubeconfig="$(./hack/kamaji-e2e.sh kubeconfig)"
if [ -s "$tenant_kubeconfig" ]; then
KUBECONFIG="$tenant_kubeconfig" make kubectl-ko-log
mv kubectl-ko-log.tar.gz hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-ko-log.tar.gz
fi
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-ko-log
path: hcp-e2e-${{ matrix.ip-family }}-${{ matrix.tenant-control-plane }}-ko-log.tar.gz
if-no-files-found: ignore
- name: Clean hosted OVN central environment
if: always()
run: make kind-clean-kamaji
chart-test:
name: Chart Installation/Uninstallation Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'chart-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
ssl:
- "true"
- "false"
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
env:
ENABLE_SSL: "${{ matrix.ssl }}"
run: make kind-install-chart
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz chart-test-${{ matrix.ssl }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: chart-test-${{ matrix.ssl }}-ko-log
path: chart-test-${{ matrix.ssl }}-ko-log.tar.gz
- name: Uninstall Kube-OVN
run: make uninstall-chart
underlay-logical-gateway-installation-test:
name: Underlay Logical Gateway Installation Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'underlay-logical-gateway-installation-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-dual
- name: Install Kube-OVN
id: install
run: make kind-install-underlay-logical-gateway-dual
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz underlay-logical-gateway-installation-test-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: underlay-logical-gateway-installation-test-ko-log
path: underlay-logical-gateway-installation-test-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
no-ovn-lb-test:
name: Disable OVN LB Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'no-ovn-lb-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN without LoadBalancer
id: install
env:
ENABLE_LB: "false"
run: make kind-install
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz no-ovn-lb-test-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: no-ovn-lb-test-ko-log
path: no-ovn-lb-test-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
no-np-test:
name: Disable Network Policy Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'no-np-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
env:
ENABLE_NP: "false"
run: make kind-install
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz no-np-test-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: no-np-test-ko-log
path: no-np-test-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
lb-svc-e2e:
name: LB Service E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'lb-svc-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-vpc-nat-gateway
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Download vpc-nat-gateway image
uses: actions/download-artifact@v8
with:
name: vpc-nat-gateway
- name: Load images
run: |
docker load -i kube-ovn.tar
docker load -i vpc-nat-gateway.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Multus and Kube-OVN
id: install
run: make kind-install-lb-svc
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-lb-svc-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > lb-svc-e2e-events.yaml
tar zcf lb-svc-e2e-events.tar.gz lb-svc-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: lb-svc-e2e-events
path: lb-svc-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf lb-svc-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: lb-svc-e2e-audit-log
path: lb-svc-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz lb-svc-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: lb-svc-e2e-ko-log
path: lb-svc-e2e-ko-log.tar.gz
webhook-e2e:
name: Webhook E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'webhook-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: |
docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN with webhook
id: install
run: make kind-install-webhook
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-webhook-e2e
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz webhook-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: webhook-e2e-ko-log
path: webhook-e2e-ko-log.tar.gz
installation-compatibility-test:
name: Installation Compatibility Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'installation-compatibility-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
k8s-version:
- v1.29.14
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.29.14
- name: Load private Kind node image
run: docker load --input kind-node-v1.29.14.tar
- name: Create kind cluster
env:
K8S_VERSION: ${{ matrix.k8s-version }}
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz installation-compatibility-test-${{ matrix.k8s-version }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: installation-compatibility-test-${{ matrix.k8s-version }}-ko-log
path: installation-compatibility-test-${{ matrix.k8s-version }}-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
talos-installation-test:
name: Talos Installation Test
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'talos-installation-test')
needs:
- e2e-selection
- build-kube-ovn
runs-on: larger-runner
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
mode:
- overlay
- underlay
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Install talosctl
run: |
curl -sLo install-talosctl.sh https://talos.dev/install
sed -i "s|/latest/download/|/download/${{ env.TALOS_VERSION }}/|g" install-talosctl.sh
sed -i "s|/latest/|/${{ env.TALOS_VERSION }}/|g" install-talosctl.sh
sh install-talosctl.sh
- name: Install KVM and libvirt
run: |
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Create Talos cluster
run: |
pipx install jinjanator
make talos-init-${{ matrix.ip-family }}
kubectl describe node
- name: Install Kube-OVN
id: install
run: |
make talos-install-${{ matrix.mode }}-${{ matrix.ip-family }}
kubectl -n kube-system rollout status ds/kube-ovn-pinger
kubectl -n kube-system rollout restart deploy/coredns
kubectl -n kube-system rollout status deploy/coredns
kubectl get pod -o wide -A
kubectl get endpointslice -A
kubectl get subnet -o wide
if [ "${{ matrix.mode }}" = "underlay" ]; then
kubectl get provider-network -o wide
kubectl get vlan -o wide
fi
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && steps.install.conclusion == 'failure') }}
run: make check-kube-ovn-pod-restarts || make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz talos-installation-test-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: talos-installation-test-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log
path: talos-installation-test-${{ matrix.ip-family }}-${{ matrix.mode }}-ko-log.tar.gz
kube-ovn-cnp-domain-e2e:
name: Kube-OVN CNP Domain E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-cnp-domain-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
mode:
- overlay
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Clone DNSNameResolver repository
run: |
git clone https://github.com/kubeovn/dnsnameresolver.git
cd dnsnameresolver
make build
docker save kubeovn/dnsnameresolver:dev -o dnsnameresolver.tar
docker load --input dnsnameresolver.tar
make install
- name: Install Kube-OVN
id: install
run: make kind-install-anp-dns-resolver
- name: Run CNP Domain E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: ${{ matrix.mode }}
run: make kube-ovn-cnp-domain-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
tar zcf kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events
path: kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log
path: kube-ovn-cnp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
kube-ovn-anp-domain-e2e:
name: Kube-OVN ANP Domain E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-anp-domain-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
mode:
- overlay
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Set environment variables
run: |
if [ $(($RANDOM%2)) -ne 0 ]; then
# run as root and use valgrind to debug memory leak
echo "VERSION=$(cat VERSION)-debug" >> "$GITHUB_ENV"
echo "DEBUG_WRAPPER=valgrind" >> "$GITHUB_ENV"
fi
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-${{ matrix.ip-family }}
- name: Clone DNSNameResolver repository
run: |
git clone https://github.com/kubeovn/dnsnameresolver.git
cd dnsnameresolver
make build
docker save kubeovn/dnsnameresolver:dev -o dnsnameresolver.tar
docker load --input dnsnameresolver.tar
make install
- name: Install Kube-OVN
id: install
run: make kind-install-anp-dns-resolver
- name: Run ANP Domain E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: ${{ matrix.mode }}
run: make kube-ovn-anp-domain-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
tar zcf kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events
path: kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log
path: kube-ovn-anp-domain-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
cilium-chaining-e2e:
name: Cilium Chaining E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'cilium-chaining-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
# - ipv6
# - dual
mode:
- overlay
- underlay
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- uses: azure/setup-helm@v5.0.1
with:
version: '${{ env.HELM_VERSION }}'
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Configure docker
run: |
# enable addition of ip6tables rules
sudo sh -c "echo '{\"experimental\": true, \"ip6tables\": true}' > /etc/docker/daemon.json"
# remove DNS search domain
sudo sed -i '/^search/d' /etc/resolv.conf
# restart docker
sudo systemctl restart docker
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-cilium-chaining-${{ matrix.ip-family }}
- name: Install Kube-OVN with Cilium chaining
id: install
run: make kind-install-cilium-chaining-${{ matrix.mode }}-${{ matrix.ip-family }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_CILIUM_CHAINING: "true"
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
E2E_NETWORK_MODE: ${{ matrix.mode }}
run: make k8s-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
tar zcf cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events
path: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log
path: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log
path: cilium-chaining-e2e-${{ matrix.mode }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
kube-ovn-ha-e2e:
name: Kube-OVN HA E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-ha-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ssl:
- "true"
- "false"
bind-local:
- "true"
- "false"
ip-family:
- ipv4
- ipv6
- dual
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-ha-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
env:
NET_STACK: "${{ matrix.ip-family }}"
ENABLE_SSL: "${{ matrix.ssl }}"
ENABLE_BIND_LOCAL_IP: "${{ matrix.bind-local }}"
TLS_MIN_VERSION: "${{ matrix.ssl == 'true' && 'TLS12' || '' }}"
TLS_MAX_VERSION: "${{ matrix.ssl == 'true' && 'TLS13' || '' }}"
TLS_CIPHER_SUITES: "${{ matrix.ssl == 'true' && 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_AES_256_GCM_SHA384' || '' }}"
run: make kind-install-chart
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
run: |
make kube-ovn-security-e2e
make kube-ovn-ha-e2e
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-ha-e2e-${{ matrix.ssl }}-${{ matrix.bind-local }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-ha-e2e-${{ matrix.ssl }}-${{ matrix.bind-local }}-${{ matrix.ip-family }}-ko-log
path: kube-ovn-ha-e2e-${{ matrix.ssl }}-${{ matrix.bind-local }}-${{ matrix.ip-family }}-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
kube-ovn-submariner-conformance-e2e:
name: Kube-OVN Submariner Conformance E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-submariner-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Install submariner subctl
env:
VERSION: v${{ env.SUBMARINER_VERSION }}
DESTDIR: /usr/local/bin
run: curl -Ls https://get.submariner.io | bash
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init-ovn-submariner
- name: Install Kube-OVN and Submariner
id: install
run: make kind-install-ovn-submariner
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
run: make kube-ovn-submariner-conformance-e2e
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-submariner-conformance-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-submariner-conformance-e2e-ko-log
path: kube-ovn-submariner-conformance-e2e-ko-log.tar.gz
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
vpc-egress-gateway-e2e:
name: VPC Egress Gateway E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'vpc-egress-gateway-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load image
run: docker load --input kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
n_worker=2 make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
env:
UNTAINT_CONTROL_PLANE: "false"
run: make kind-install-debug-valgrind-${{ matrix.ip-family }}
- name: Install Multus
run: make kind-install-multus
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
run: make vpc-egress-gateway-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > vpc-egress-gateway-e2e-${{ matrix.ip-family }}-events.yaml
tar zcf vpc-egress-gateway-e2e-${{ matrix.ip-family }}-events.tar.gz vpc-egress-gateway-e2e-${{ matrix.ip-family }}-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-events
path: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf vpc-egress-gateway-e2e-${{ matrix.ip-family }}-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-audit-log
path: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz vpc-egress-gateway-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-ko-log
path: vpc-egress-gateway-e2e-${{ matrix.ip-family }}-ko-log.tar.gz
- name: Check valgrind result
run: |
kubectl -n kube-system rollout restart ds ovs-ovn
kubectl -n kube-system rollout status ds ovs-ovn
sleep 10
kubectl -n kube-system rollout restart deploy ovn-central
kubectl -n kube-system rollout status deploy ovn-central
while true; do
if [ $(kubectl -n kube-system get pod -l app=ovs -o name | wc -l) -eq $(kubectl get node -o name | wc -l) ]; then
break
fi
sleep 1
done
kubectl ko log ovn
kubectl ko log ovs
for daemon in ovsdb-nb ovsdb-sb ovn-northd ovn-controller ovsdb-server ovs-vswitchd; do
echo "Checking if valgrind log file for $daemon exists..."
find kubectl-ko-log -type f -name "$daemon.valgrind.log.[[:digit:]]*" -exec false {} + && exit 1
done
find kubectl-ko-log -type f -name '*.valgrind.log.*' | while read f; do
if grep -qw 'definitely lost' "$f"; then
echo "Memory leak detected in $(basename $f | awk -F. '{print $1}')."
echo $f
cat "$f"
exit 1
fi;
done
- name: Cleanup
run: timeout -k 10 180 sh -x dist/images/cleanup.sh
iptables-vpc-nat-gw-conformance-e2e:
name: Iptables VPC NAT Gateway E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'iptables-vpc-nat-gw-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-vpc-nat-gateway
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Download vpc-nat-gateway image
uses: actions/download-artifact@v8
with:
name: vpc-nat-gateway
- name: Load images
run: |
docker load -i kube-ovn.tar
docker load -i vpc-nat-gateway.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN with VPC NAT gateway enabled
id: install
run: make kind-install-vpc-nat-gw
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make iptables-vpc-nat-gw-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > iptables-vpc-nat-gw-conformance-e2e-events.yaml
tar zcf iptables-vpc-nat-gw-conformance-e2e-events.tar.gz iptables-vpc-nat-gw-conformance-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: iptables-vpc-nat-gw-conformance-e2e-events
path: iptables-vpc-nat-gw-conformance-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf iptables-vpc-nat-gw-conformance-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: iptables-vpc-nat-gw-conformance-e2e-audit-log
path: iptables-vpc-nat-gw-conformance-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz iptables-vpc-nat-gw-conformance-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: iptables-vpc-nat-gw-conformance-e2e-ko-log
path: iptables-vpc-nat-gw-conformance-e2e-ko-log.tar.gz
ovn-vpc-nat-gw-conformance-e2e:
name: OVN VPC NAT Gateway E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'ovn-vpc-nat-gw-conformance-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install
- name: Run Vip E2E
id: vip-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make vip-conformance-e2e
- name: Run Ovn VPC NAT GW E2E
id: vpc-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make ovn-vpc-nat-gw-conformance-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > ovn-vpc-nat-gw-conformance-e2e-events.yaml
tar zcf ovn-vpc-nat-gw-conformance-e2e-events.tar.gz ovn-vpc-nat-gw-conformance-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure')
with:
name: ovn-vpc-nat-gw-conformance-e2e-events
path: ovn-vpc-nat-gw-conformance-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf ovn-vpc-nat-gw-conformance-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure')
with:
name: ovn-vpc-nat-gw-conformance-e2e-audit-log
path: ovn-vpc-nat-gw-conformance-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz ovn-vpc-nat-gw-conformance-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.vip-e2e.conclusion == 'failure' || steps.vpc-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: ovn-vpc-nat-gw-conformance-e2e-ko-log
path: ovn-vpc-nat-gw-conformance-e2e-ko-log.tar.gz
kube-ovn-ipsec-e2e:
name: OVN IPSEC E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-ipsec-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install-ovn-ipsec
- name: Run Ovn IPSEC E2E
id: kube-ovn-ipsec-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-ipsec-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-ipsec-e2e-events.yaml
tar zcf kube-ovn-ipsec-e2e-events.tar.gz kube-ovn-ipsec-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')
with:
name: kube-ovn-ipsec-e2e-events
path: kube-ovn-ipsec-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf kube-ovn-ipsec-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')
with:
name: kube-ovn-ipsec-e2e-audit-log
path: kube-ovn-ipsec-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')) }}
env:
IGNORABLE_PODS: app=kube-ovn-pinger
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-ipsec-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-ipsec-e2e-ko-log
path: kube-ovn-ipsec-e2e-ko-log.tar.gz
kube-ovn-ipsec-cert-mgr-e2e:
name: OVN IPSEC E2E CERT MANAGER
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-ipsec-cert-mgr-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install-ovn-ipsec-cert-manager
- name: Run Ovn IPSEC cert-manager E2E
id: kube-ovn-ipsec-cert-mgr-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-ipsec-cert-mgr-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-ipsec-cert-mgr-e2e-events.yaml
tar zcf kube-ovn-ipsec-cert-mgr-e2e-events.tar.gz kube-ovn-ipsec-cert-mgr-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure')
with:
name: kube-ovn-ipsec-cert-mgr-e2e-events
path: kube-ovn-ipsec-cert-mgr-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf kube-ovn-ipsec-cert-mgr-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure')
with:
name: kube-ovn-ipsec-cert-mgr-e2e-audit-log
path: kube-ovn-ipsec-cert-mgr-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-ipsec-cert-mgr-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-cert-mgr-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-ipsec-cert-mgr-e2e-ko-log
path: kube-ovn-ipsec-cert-mgr-e2e-ko-log.tar.gz
kube-ovn-connectivity-test:
name: Kube-OVN Connectivity E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-connectivity-test')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
mode:
- overlay
- underlay
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.mode }}
- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-connectivity-e2e
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.e2e.conclusion == 'failure')
with:
name: kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log
path: kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log.tar.gz
kube-ovn-underlay-metallb-e2e:
name: OVN METALLB E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'kube-ovn-underlay-metallb-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
ip-family:
- ipv4
- ipv6
- dual
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
n_worker=2 make kind-init-${{ matrix.ip-family }}
- name: Install Kube-OVN
id: install
run: make kind-install-metallb-pool-from-underlay-${{ matrix.ip-family }}
- name: Run Ovn Metallb and Kube-OVN Combine E2E
id: kube-ovn-underlay-metallb-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
E2E_IP_FAMILY: ${{ matrix.ip-family }}
run: make kube-ovn-underlay-metallb-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-events.yaml
tar zcf kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-events.tar.gz kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure')
with:
name: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-events
path: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure')
with:
name: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-audit-log
path: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-underlay-metallb-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-ko-log
path: kube-ovn-underlay-metallb-${{ matrix.ip-family }}-e2e-ko-log.tar.gz
router-lb-rule-e2e:
name: Router LB Rule E2E
if: contains(fromJSON(needs.e2e-selection.outputs.executionJobIds), 'router-lb-rule-e2e')
needs:
- e2e-selection
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source
- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
fetch-depth: 1
path: test/e2e/source
- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v7
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false
- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"
- name: Go cache
uses: actions/cache/restore@v6
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: |
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.ref_name }}-
${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ github.base_ref }}-
- name: Install kind
uses: helm/kind-action@v1.14.0
with:
version: ${{ env.KIND_VERSION }}
install_only: true
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Load images
run: docker load -i kube-ovn.tar
- name: Download private Kind node image
uses: actions/download-artifact@v8
with:
name: kind-node-v1.36.1
- name: Load private Kind node image
run: docker load --input kind-node-v1.36.1.tar
- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install
- name: Run Router LB Rule E2E
id: rlr-e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-rlr-e2e
- name: Collect k8s events
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure')
run: |
kubectl get events -A -o yaml > router-lb-rule-e2e-events.yaml
tar zcf router-lb-rule-e2e-events.tar.gz router-lb-rule-e2e-events.yaml
- name: Upload k8s events
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure')
with:
name: router-lb-rule-e2e-events
path: router-lb-rule-e2e-events.tar.gz
- name: Collect apiserver audit logs
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure')
run: |
docker cp kube-ovn-control-plane:/var/log/kubernetes/kube-apiserver-audit.log .
tar zcf router-lb-rule-e2e-audit-log.tar.gz kube-apiserver-audit.log
- name: Upload apiserver audit logs
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure')
with:
name: router-lb-rule-e2e-audit-log
path: router-lb-rule-e2e-audit-log.tar.gz
- name: Check kube ovn pod restarts
id: check-restarts
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts
- name: kubectl ko log
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz router-lb-rule-e2e-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v7
if: failure() && (steps.install.conclusion == 'failure' || steps.rlr-e2e.conclusion == 'failure' || steps.check-restarts.conclusion == 'failure')
with:
name: router-lb-rule-e2e-ko-log
path: router-lb-rule-e2e-ko-log.tar.gz
e2e-executor-result:
name: x86 E2E Selected Result
if: always() && github.event_name != 'pull_request'
permissions: {}
needs:
- e2e-selection
- e2e-control-validation
- bgp-speaker-e2e
- chart-test
- cilium-chaining-e2e
- cyclonus-netpol-e2e
- installation-compatibility-test
- iptables-vpc-nat-gw-conformance-e2e
- k8s-conformance-e2e
- k8s-netpol-e2e
- kube-ovn-anp-domain-e2e
- kube-ovn-cnp-domain-e2e
- kube-ovn-conformance-e2e
- kube-ovn-connectivity-test
- kube-ovn-ha-e2e
- kube-ovn-hosted-ovn-central-e2e
- kube-ovn-ic-conformance-e2e
- kube-ovn-ipsec-cert-mgr-e2e
- kube-ovn-ipsec-e2e
- kube-ovn-submariner-conformance-e2e
- kube-ovn-underlay-metallb-e2e
- lb-svc-e2e
- multus-conformance-e2e
- no-np-test
- no-ovn-lb-test
- non-primary-cni-e2e
- ovn-vpc-nat-gw-conformance-e2e
- router-lb-rule-e2e
- talos-installation-test
- underlay-logical-gateway-installation-test
- vpc-egress-gateway-e2e
- webhook-e2e
runs-on: ubuntu-24.04
env:
NEEDS_JSON: ${{ toJSON(needs) }}
SELECTED_JOB_IDS: ${{ needs.e2e-selection.outputs.executionJobIds }}
steps:
- name: Verify every selected test Job succeeded
run: |
python3 - <<'PY'
import json
import os
needs = json.loads(os.environ["NEEDS_JSON"])
selectedJobIds = json.loads(os.environ["SELECTED_JOB_IDS"])
requiredJobIds = ["e2e-selection", "e2e-control-validation"] + selectedJobIds
incomplete = {
jobId: needs.get(jobId, {}).get("result", "missing")
for jobId in requiredJobIds
if needs.get(jobId, {}).get("result") != "success"
}
if incomplete:
raise SystemExit(f"required x86 E2E Jobs did not succeed: {incomplete}")
print(f"Verified {len(requiredJobIds)} required x86 E2E Jobs.")
PY
push:
name: Push Images
needs:
- e2e-executor-result
if: github.event_name == 'push' && needs.e2e-executor-result.result == 'success'
runs-on: ubuntu-24.04
steps:
- uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false
- uses: actions/checkout@v7
with:
ref: ${{ env.EXECUTION_SHA }}
persist-credentials: false
- name: Download kube-ovn image
uses: actions/download-artifact@v8
with:
name: kube-ovn
- name: Download kube-ovn-dpdk image
uses: actions/download-artifact@v8
if: github.event_name != 'pull_request'
with:
name: kube-ovn-dpdk
- name: Download vpc-nat-gateway image
uses: actions/download-artifact@v8
with:
name: vpc-nat-gateway
- name: Load image
run: |
docker load --input kube-ovn.tar
docker load --input vpc-nat-gateway.tar
if [ '${{ github.event_name }}' != 'pull_request' ]; then
docker load --input kube-ovn-dpdk.tar
fi
- name: Security Scan
env:
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
run: |
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
make scan
- name: Push
if: github.ref_name == github.event.repository.default_branch || startsWith(github.ref_name, 'release-')
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
COMMIT: ${{ github.sha }}
run: |
cat VERSION
TAG=$(cat VERSION)
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker tag kubeovn/kube-ovn:$TAG kubeovn/kube-ovn-dev:$COMMIT-x86
docker tag kubeovn/kube-ovn:$TAG kubeovn/kube-ovn:$TAG-x86
docker tag kubeovn/kube-ovn:$TAG-debug kubeovn/kube-ovn:$TAG-debug-x86
docker tag kubeovn/kube-ovn:$TAG-dpdk kubeovn/kube-ovn:$TAG-dpdk-x86
docker tag kubeovn/vpc-nat-gateway:$TAG kubeovn/vpc-nat-gateway-dev:$COMMIT-x86
docker tag kubeovn/vpc-nat-gateway:$TAG kubeovn/vpc-nat-gateway:$TAG-x86
docker images
docker push kubeovn/kube-ovn:$TAG-x86
docker push kubeovn/kube-ovn:$TAG-amd64-legacy
docker push kubeovn/kube-ovn-dev:$COMMIT-x86
docker push kubeovn/kube-ovn:$TAG-debug-x86
docker push kubeovn/kube-ovn:$TAG-dpdk-x86
docker push kubeovn/vpc-nat-gateway:$TAG-x86
docker push kubeovn/vpc-nat-gateway-dev:$COMMIT-x86