Skip to content

Commit 976d61c

Browse files
committed
Adding Helm Parameter CI Tests
1 parent 9370fc4 commit 976d61c

File tree

5 files changed

+1304
-7
lines changed

5 files changed

+1304
-7
lines changed

Makefile

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,23 @@ cluster/uninstall: bin/helm bin/aws
128128
## E2E targets
129129
# Targets to run e2e tests
130130

131+
## e2e/parameters and e2e/parameters-all are Parameter-specific e2e tests
132+
# Usage: make e2e/parameters PARAM_SET=<name> or make e2e/paramaters-all
133+
# See hack/e2e/param-sets.sh for available sets and their definitions.
134+
135+
.PHONY: e2e/parameters
136+
e2e/parameters: bin/helm bin/ginkgo
137+
./hack/e2e/param-sets.sh run $(PARAM_SET)
138+
139+
.PHONY: e2e/parameters-all
140+
e2e/parameters-all: bin/helm bin/ginkgo
141+
./hack/e2e/param-sets.sh run-all
142+
143+
# THIS WILL BE REVERSED BEFORE MERGING. Only here because these tests do not
144+
# yet have their own testgrid but reviewers need to see how JUnit output is after tests run for this PR.
131145
.PHONY: e2e/single-az
132146
e2e/single-az: bin/helm bin/ginkgo
133-
AWS_AVAILABILITY_ZONES=us-west-2a \
134-
TEST_PATH=./tests/e2e/... \
135-
GINKGO_FOCUS="\[ebs-csi-e2e\] \[single-az\]" \
136-
GINKGO_PARALLEL=5 \
137-
HELM_EXTRA_FLAGS="--set=controller.volumeModificationFeature.enabled=true,sidecars.provisioner.additionalArgs[0]='--feature-gates=VolumeAttributesClass=true',sidecars.resizer.additionalArgs[0]='--feature-gates=VolumeAttributesClass=true',node.enableMetrics=true" \
138-
./hack/e2e/run.sh
147+
./hack/e2e/param-sets.sh run-all
139148

140149
.PHONY: e2e/multi-az
141150
e2e/multi-az: bin/helm bin/ginkgo

hack/e2e/param-sets.sh

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/bin/bash
2+
3+
# Copyright 2025 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Parameter set definitions for e2e parameter tests.
18+
# Each set defines GINKGO_FOCUS, HELM_EXTRA_FLAGS, and optionally other env vars.
19+
#
20+
# Sets in PARAM_SETS_ALL (no "special" cluster config needed):
21+
# standard - Behavioral params (tagging, metrics, logging, storage classes, etc.)
22+
# other - Volume modification, volume attach limit, and metadata labeler
23+
# debug - debugLogs=true overrides individual logLevel settings
24+
# infra - Infrastructure/deployment params (resources, security, strategy, etc.)
25+
# fips - Builds FIPS image then validates it is deployed
26+
#
27+
# Not in PARAM_SETS_ALL:
28+
# legacy-compat - Legacy CSIDriver + XFS behavior
29+
# selinux - Needs SELinux-enabled nodes
30+
31+
set -euo pipefail
32+
33+
PARAM_SETS_ALL="standard other debug infra fips"
34+
35+
param_set_standard() {
36+
GINKGO_FOCUS="\[param:(extraCreateMetadata|k8sTagClusterId|extraVolumeTags|controllerMetrics|nodeMetrics|batching|defaultFsType|controllerLoggingFormat|nodeLoggingFormat|controllerLogLevel|nodeLogLevel|provisionerLogLevel|attacherLogLevel|snapshotterLogLevel|resizerLogLevel|nodeDriverRegistrarLogLevel|storageClasses|volumeSnapshotClasses|defaultStorageClass|snapshotterForceEnable|controllerUserAgentExtra|controllerEnablePrometheusAnnotations|nodeEnablePrometheusAnnotations|nodeKubeletPath|nodeTolerateAllTaints|controllerPodDisruptionBudget|provisionerLeaderElection|attacherLeaderElection|resizerLeaderElection|reservedVolumeAttachments|hostNetwork|nodeDisableMutation|nodeTerminationGracePeriod)\]"
37+
HELM_EXTRA_FLAGS="--set=controller.extraCreateMetadata=true,controller.k8sTagClusterId=e2e-param-test,controller.extraVolumeTags.TestKey=TestValue,controller.enableMetrics=true,node.enableMetrics=true,controller.batching=true,controller.defaultFsType=xfs,controller.loggingFormat=json,node.loggingFormat=json,controller.logLevel=5,node.logLevel=5,sidecars.provisioner.logLevel=5,sidecars.attacher.logLevel=5,sidecars.snapshotter.logLevel=5,sidecars.resizer.logLevel=5,sidecars.nodeDriverRegistrar.logLevel=5,defaultStorageClass.enabled=true,storageClasses[0].name=test-sc,storageClasses[0].parameters.type=gp3,volumeSnapshotClasses[0].name=test-vsc,volumeSnapshotClasses[0].deletionPolicy=Delete,sidecars.snapshotter.forceEnable=true,controller.userAgentExtra=e2e-test,controller.enablePrometheusAnnotations=true,node.enablePrometheusAnnotations=true,node.kubeletPath=/var/lib/kubelet,node.tolerateAllTaints=true,controller.podDisruptionBudget.enabled=true,sidecars.provisioner.leaderElection.enabled=true,sidecars.attacher.leaderElection.enabled=true,sidecars.resizer.leaderElection.enabled=true,node.reservedVolumeAttachments=2,node.hostNetwork=true,node.serviceAccount.disableMutation=true,node.terminationGracePeriodSeconds=60"
38+
}
39+
40+
# other combines volume-modification, volume-attach-limit, and metadata-labeler (no conflicting Helm values)
41+
param_set_other() {
42+
GINKGO_FOCUS="\[param:(volumeModification|volumemodifierLogLevel|volumemodifierLeaderElection|volumeAttachLimit|metadataLabeler|metadataLabelerLogLevel)\]"
43+
HELM_EXTRA_FLAGS="--set=controller.volumeModificationFeature.enabled=true,sidecars.provisioner.additionalArgs[0]='--feature-gates=VolumeAttributesClass=true',sidecars.resizer.additionalArgs[0]='--feature-gates=VolumeAttributesClass=true',sidecars.volumemodifier.logLevel=5,sidecars.volumemodifier.leaderElection.enabled=false,node.volumeAttachLimit=25,sidecars.metadataLabeler.enabled=true,node.metadataSources='metadata-labeler',sidecars.metadataLabeler.logLevel=5"
44+
}
45+
46+
# debugLogs=true overrides individual logLevel settings, so this must be separate from standard
47+
param_set_debug() {
48+
GINKGO_FOCUS="\[param:(debugLogs|sdkDebugLog)\]"
49+
HELM_EXTRA_FLAGS="--set=debugLogs=true,controller.sdkDebugLog=true"
50+
}
51+
52+
param_set_infra() {
53+
GINKGO_FOCUS="\[param:(controllerReplicaCount|controllerPriorityClassName|controllerResources|controllerPodAnnotations|controllerPodLabels|controllerDeploymentAnnotations|controllerRevisionHistoryLimit|nodePriorityClassName|nodeResources|nodePodAnnotations|nodeDaemonSetAnnotations|nodeRevisionHistoryLimit|provisionerResources|attacherResources|snapshotterResources|resizerResources|nodeDriverRegistrarResources|livenessProbeResources|customLabels|controllerEnv|nodeEnv|controllerTopologySpreadConstraints|controllerSecurityContext|nodeSecurityContext|controllerContainerSecurityContext|controllerVolumes|controllerVolumeMounts|nodeVolumes|nodeVolumeMounts|controllerDnsConfig|nodeDnsConfig|controllerInitContainers|nodeInitContainers|imagePullPolicy|controllerUpdateStrategy|nodeUpdateStrategy)\]"
54+
HELM_EXTRA_FLAGS="--set=controller.replicaCount=3,controller.priorityClassName=system-node-critical,controller.resources.requests.cpu=100m,controller.resources.limits.memory=256Mi,controller.podAnnotations.test-annotation=test-value,controller.podLabels.test-label=test-value,controller.deploymentAnnotations.deploy-annotation=deploy-value,controller.revisionHistoryLimit=5,node.priorityClassName=system-node-critical,node.resources.requests.cpu=50m,node.resources.limits.memory=128Mi,node.podAnnotations.node-annotation=node-value,node.daemonSetAnnotations.ds-annotation=ds-value,node.revisionHistoryLimit=3,sidecars.provisioner.resources.requests.cpu=20m,sidecars.attacher.resources.requests.cpu=15m,sidecars.snapshotter.resources.requests.cpu=15m,sidecars.resizer.resources.requests.cpu=15m,sidecars.nodeDriverRegistrar.resources.requests.cpu=10m,sidecars.livenessProbe.resources.requests.cpu=5m,customLabels.custom-label=custom-value,controller.env[0].name=TEST_ENV,controller.env[0].value=test-value,node.env[0].name=NODE_ENV,node.env[0].value=node-value,controller.topologySpreadConstraints[0].maxSkew=1,controller.topologySpreadConstraints[0].topologyKey=topology.kubernetes.io/zone,controller.topologySpreadConstraints[0].whenUnsatisfiable=ScheduleAnyway,controller.securityContext.runAsNonRoot=true,controller.containerSecurityContext.readOnlyRootFilesystem=true,controller.volumes[0].name=extra-volume,controller.volumes[0].configMap.name=kube-root-ca.crt,controller.volumeMounts[0].name=extra-volume,controller.volumeMounts[0].mountPath=/extra,node.volumes[0].name=node-extra-volume,node.volumes[0].configMap.name=kube-root-ca.crt,node.volumeMounts[0].name=node-extra-volume,node.volumeMounts[0].mountPath=/node-extra,controller.dnsConfig.nameservers[0]=8.8.8.8,node.dnsConfig.nameservers[0]=8.8.4.4,controller.initContainers[0].name=init-container,controller.initContainers[0].image=busybox,controller.initContainers[0].command[0]=echo,controller.initContainers[0].command[1]=init,node.initContainers[0].name=node-init-container,node.initContainers[0].image=busybox,node.initContainers[0].command[0]=echo,node.initContainers[0].command[1]=node-init,image.pullPolicy=Always,controller.updateStrategy.type=Recreate,controller.updateStrategy.rollingUpdate=null,node.updateStrategy.type=OnDelete"
55+
}
56+
57+
param_set_legacy-compat() {
58+
GINKGO_FOCUS="\[param:(useOldCSIDriver|legacyXFS)\]"
59+
HELM_EXTRA_FLAGS="--set=useOldCSIDriver=true,node.legacyXFS=true"
60+
}
61+
62+
param_set_selinux() {
63+
GINKGO_FOCUS="\[param:selinux\]"
64+
HELM_EXTRA_FLAGS="--set=node.selinux=true"
65+
}
66+
67+
param_set_fips() {
68+
GINKGO_FOCUS="\[param:fips\]"
69+
HELM_EXTRA_FLAGS="--set=fips=true"
70+
FIPS_TEST=true make cluster/image
71+
}
72+
73+
# Load a parameter set by name, exporting GINKGO_FOCUS and HELM_EXTRA_FLAGS
74+
load_param_set() {
75+
local name="$1"
76+
local func="param_set_${name}"
77+
if ! declare -f "$func" >/dev/null 2>&1; then
78+
echo "Unknown parameter set: ${name}" >&2
79+
echo "Available sets: standard, other, debug, infra, legacy-compat, selinux, fips" >&2
80+
exit 1
81+
fi
82+
"$func"
83+
export GINKGO_FOCUS HELM_EXTRA_FLAGS
84+
export GINKGO_PARALLEL="${GINKGO_PARALLEL:-5}"
85+
export AWS_AVAILABILITY_ZONES="${AWS_AVAILABILITY_ZONES:-us-west-2a}"
86+
export TEST_PATH="${TEST_PATH:-./tests/e2e/...}"
87+
export JUNIT_REPORT="${REPORT_DIR:-/logs/artifacts}/junit-params-${name}.xml"
88+
# Export optional vars if set by the param set function
89+
if [[ -n "${EBS_INSTALL_SNAPSHOT+x}" ]]; then export EBS_INSTALL_SNAPSHOT; fi
90+
if [[ -n "${FIPS_TEST+x}" ]]; then export FIPS_TEST; fi
91+
}
92+
93+
# Run a single parameter set
94+
run_param_set() {
95+
load_param_set "$1"
96+
echo "### Running parameter set: $1"
97+
./hack/e2e/run.sh
98+
}
99+
100+
# Merge per-set JUnit XMLs into a single file with duplicate skipped tests removed.
101+
# Each Ginkgo run reports ALL specs (most as skipped), so the same skipped test appears
102+
# in every per-set file. This merges all results into one file, keeping non-skipped results
103+
# (passed/failed) over skipped duplicates, and emitting each skipped test only once.
104+
merge_junit_results() {
105+
local report_dir="${REPORT_DIR:-/logs/artifacts}"
106+
local output="${report_dir}/junit-params.xml"
107+
108+
python3 - "$report_dir" "$output" <<'PYEOF'
109+
import glob, sys, xml.etree.ElementTree as ET
110+
111+
report_dir, output = sys.argv[1], sys.argv[2]
112+
merged = {}
113+
time_total = 0.0
114+
115+
def priority(tc):
116+
if tc.find("failure") is not None or tc.find("error") is not None:
117+
return 2 # failed/errored
118+
if tc.find("skipped") is not None:
119+
return 0 # skipped
120+
return 1 # passed
121+
122+
for path in sorted(glob.glob(f"{report_dir}/junit-params-*.xml")):
123+
tree = ET.parse(path)
124+
time_total += float(tree.getroot().get("time", "0"))
125+
for tc in tree.iter("testcase"):
126+
name = tc.get("name", "")
127+
if name not in merged or priority(tc) > priority(merged[name]):
128+
merged[name] = tc
129+
130+
tests = list(merged.values())
131+
skipped = sum(1 for tc in tests if tc.find("skipped") is not None)
132+
failed = sum(1 for tc in tests if tc.find("failure") is not None)
133+
errored = sum(1 for tc in tests if tc.find("error") is not None)
134+
135+
root = ET.Element("testsuites", tests=str(len(tests)), disabled=str(skipped),
136+
errors=str(errored), failures=str(failed), time=str(time_total))
137+
suite = ET.SubElement(root, "testsuite", name="AWS EBS CSI Driver Parameter Tests",
138+
tests=str(len(tests)), skipped=str(skipped),
139+
errors=str(errored), failures=str(failed), time=str(time_total))
140+
for tc in tests:
141+
suite.append(tc)
142+
143+
ET.ElementTree(root).write(output, xml_declaration=True, encoding="UTF-8")
144+
PYEOF
145+
146+
# Remove per-set files only if merge succeeded, so CI only sees the merged result
147+
if [[ $? -eq 0 && -f "$output" ]]; then
148+
rm -f "${report_dir}"/junit-params-*.xml
149+
echo "Merged JUnit results into ${output}"
150+
else
151+
echo "WARNING: JUnit merge failed, keeping per-set files" >&2
152+
fi
153+
}
154+
155+
# Run all standard parameter sets sequentially
156+
run_all_param_sets() {
157+
echo "Running all parameter sets sequentially..."
158+
local failed=0
159+
for set in $PARAM_SETS_ALL; do
160+
run_param_set "$set" || failed=1
161+
done
162+
merge_junit_results
163+
if [[ $failed -ne 0 ]]; then
164+
echo "One or more parameter sets failed!"
165+
return 1
166+
fi
167+
echo "All parameter sets completed successfully!"
168+
}
169+
170+
# Allow direct invocation: ./hack/e2e/param-sets.sh run <name> or ./hack/e2e/param-sets.sh run-all
171+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
172+
case "${1:-}" in
173+
run)
174+
[[ -z "${2:-}" ]] && {
175+
echo "Usage: $0 run <param-set-name>" >&2
176+
exit 1
177+
}
178+
run_param_set "$2"
179+
merge_junit_results
180+
;;
181+
run-all)
182+
run_all_param_sets
183+
;;
184+
*)
185+
echo "Usage: $0 {run <param-set-name>|run-all}" >&2
186+
exit 1
187+
;;
188+
esac
189+
fi

hack/e2e/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ else
157157
"${BIN}/ginkgo" -p -nodes="${GINKGO_PARALLEL}" \
158158
--focus="${GINKGO_FOCUS}" \
159159
--skip="${GINKGO_SKIP}" \
160-
--junit-report="${REPORT_DIR}/junit.xml" \
160+
--junit-report="${JUNIT_REPORT:-${REPORT_DIR}/junit.xml}" \
161161
"${TEST_PATH}" \
162162
-- \
163163
-kubeconfig="${KUBECONFIG}" \

hack/prow-e2e.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ test-helm-chart)
7878
TEST="helm-ct"
7979
export INSTANCE_TYPE="c5.2xlarge"
8080
;;
81+
test-e2e-parameters)
82+
TEST="parameters-all"
83+
;;
8184
*)
8285
echo "Unknown e2e test ${1}" >&2
8386
exit 1

0 commit comments

Comments
 (0)