Skip to content

Commit 1e7854c

Browse files
authored
Add IPv6 testing script for use in release process (#3931)
1 parent 8241478 commit 1e7854c

File tree

9 files changed

+244
-18
lines changed

9 files changed

+244
-18
lines changed

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ HELM_SCHEMA_VERSION = 0.18.1
4343
PREFIX ?= nginx-gateway-fabric## The name of the NGF image. For example, nginx-gateway-fabric
4444
NGINX_PREFIX ?= $(PREFIX)/nginx## The name of the nginx image. For example: nginx-gateway-fabric/nginx
4545
NGINX_PLUS_PREFIX ?= $(PREFIX)/nginx-plus## The name of the nginx plus image. For example: nginx-gateway-fabric/nginx-plus
46+
NGINX_SERVICE_TYPE ?= NodePort## The type of the nginx service. Possible values: NodePort, LoadBalancer, ClusterIP
47+
PULL_POLICY ?= Never## The pull policy of the images. Possible values: Always, IfNotPresent, Never
4648
TAG ?= $(VERSION:v%=%)## The tag of the image. For example, 1.1.0
4749
TARGET ?= local## The target of the build. Possible values: local and container
4850
OUT_DIR ?= build/out## The folder where the binary will be stored
@@ -226,13 +228,13 @@ install-ngf-local-build-with-plus: check-for-plus-usage-endpoint build-images-wi
226228

227229
.PHONY: helm-install-local
228230
helm-install-local: install-gateway-crds ## Helm install NGF on configured kind cluster with local images. To build, load, and install with helm run make install-ngf-local-build.
229-
helm install nginx-gateway $(CHART_DIR) --set nginx.image.repository=$(NGINX_PREFIX) --create-namespace --wait --set nginxGateway.image.pullPolicy=Never --set nginx.service.type=NodePort --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=Never --set nginxGateway.gwAPIExperimentalFeatures.enable=$(ENABLE_EXPERIMENTAL) -n nginx-gateway $(HELM_PARAMETERS)
231+
helm install nginx-gateway $(CHART_DIR) --set nginx.image.repository=$(NGINX_PREFIX) --create-namespace --wait --set nginxGateway.image.pullPolicy=$(PULL_POLICY) --set nginx.service.type=$(NGINX_SERVICE_TYPE) --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=$(PULL_POLICY) --set nginxGateway.gwAPIExperimentalFeatures.enable=$(ENABLE_EXPERIMENTAL) -n nginx-gateway $(HELM_PARAMETERS)
230232

231233
.PHONY: helm-install-local-with-plus
232234
helm-install-local-with-plus: check-for-plus-usage-endpoint install-gateway-crds ## Helm install NGF with NGINX Plus on configured kind cluster with local images. To build, load, and install with helm run make install-ngf-local-build-with-plus.
233235
kubectl create namespace nginx-gateway || true
234236
kubectl -n nginx-gateway create secret generic nplus-license --from-file $(PLUS_LICENSE_FILE) || true
235-
helm install nginx-gateway $(CHART_DIR) --set nginx.image.repository=$(NGINX_PLUS_PREFIX) --wait --set nginxGateway.image.pullPolicy=Never --set nginx.service.type=NodePort --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=Never --set nginxGateway.gwAPIExperimentalFeatures.enable=$(ENABLE_EXPERIMENTAL) -n nginx-gateway --set nginx.plus=true --set nginx.usage.endpoint=$(PLUS_USAGE_ENDPOINT) $(HELM_PARAMETERS)
237+
helm install nginx-gateway $(CHART_DIR) --set nginx.image.repository=$(NGINX_PLUS_PREFIX) --wait --set nginxGateway.image.pullPolicy=$(PULL_POLICY) --set nginx.service.type=$(NGINX_SERVICE_TYPE) --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=$(PULL_POLICY) --set nginxGateway.gwAPIExperimentalFeatures.enable=$(ENABLE_EXPERIMENTAL) -n nginx-gateway --set nginx.plus=true --set nginx.usage.endpoint=$(PLUS_USAGE_ENDPOINT) $(HELM_PARAMETERS)
236238

237239
.PHONY: check-for-plus-usage-endpoint
238240
check-for-plus-usage-endpoint: ## Checks that the PLUS_USAGE_ENDPOINT is set in the environment. This env var is required when deploying or testing with N+.

docs/developer/release-process.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ To create a new release, follow these steps:
4444
4. Once the release branch pipeline completes, run tests using the `release-X.X-rc` images that are pushed to Github (for example, `release-1.3-rc`).
4545
1. Kick off the [longevity tests](https://github.com/nginx/nginx-gateway-fabric/blob/main/tests/README.md#longevity-testing) for both OSS and Plus. You'll need to create two clusters and VMs for this. Before running, update your `vars.env` file with the proper image tag and prefixes. NGF and nginx images will be available from `ghcr.io`, and nginx plus will be available in GCP (`us-docker.pkg.dev/<GCP_PROJECT_ID>/nginx-gateway-fabric/nginx-plus`). These tests need to run for 4 days before releasing. The results should be committed to the main branch and then cherry-picked to the release branch.
4646
2. Kick off the [NFR workflow](https://github.com/nginx/nginx-gateway-fabric/actions/workflows/nfr.yml) in the browser. For `image_tag`, use `release-X.X-rc`, and for `version`, use the upcoming `X.Y.Z` NGF version. Run the workflow on the new release branch. This will run all of the NFR tests which are automated and open a PR with the results files when it is complete. Review this PR and make any necessary changes before merging. Once merged, be sure to cherry-pick the commit to the main branch as well (the original PR targets the release branch).
47+
3. Run the IPv6 tests using the `make ipv6-tests` target. This must be run from within the `tests` directory. An example of running this script for release 2.1.0 would look like this: `make ipv6-test TAG=release-2.1-rc`
4748
5. Run the [Release PR](https://github.com/nginx/nginx-gateway-fabric/actions/workflows/release-pr.yml) workflow to update the repo files for the release. Then there are a few manual steps to complete:
4849
1. Update the [README](/README.md) to include information about the release.
4950
2. Update the [changelog](/CHANGELOG.md). There is going to be a new blank section generated by the automation that needs to be adjusted accordingly.

tests/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ start-longevity-test: nfr-test ## Start the longevity test to run for 4 days in
118118
stop-longevity-test: export STOP_LONGEVITY=true
119119
stop-longevity-test: nfr-test ## Stop the longevity test and collects results
120120

121+
.PHONY: ipv6-tests
122+
ipv6-tests: GOARCH=amd64
123+
ipv6-tests: ## Example usage: make ipv6-tests TAG=release-X.Y-rc
124+
./ipv6/run-ipv6-test.sh $(TAG)
125+
121126

122127
.PHONY: .vm-nfr-test
123128
.vm-nfr-test: ## Runs the NFR tests on the GCP VM (called by `nfr-test`)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: Cluster
2+
apiVersion: kind.x-k8s.io/v1alpha4
3+
networking:
4+
ipFamily: ipv6 # Explicitly set the cluster to use IPv6
5+
apiServerAddress: "::1"
6+
disableDefaultCNI: false # Use Kind's default CNI
7+
nodes:
8+
- role: control-plane

tests/ipv6/manifests/gateway.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: Gateway
3+
metadata:
4+
name: gateway
5+
spec:
6+
gatewayClassName: nginx
7+
listeners:
8+
- name: http
9+
port: 80
10+
protocol: HTTP
11+
hostname: "*.example.com"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: test-app-ipv6
5+
namespace: default
6+
spec:
7+
replicas: 1
8+
selector:
9+
matchLabels:
10+
app: test-app-ipv6
11+
template:
12+
metadata:
13+
labels:
14+
app: test-app-ipv6
15+
spec:
16+
containers:
17+
- name: nginx
18+
image: nginxdemos/nginx-hello:plain-text
19+
ports:
20+
- containerPort: 80
21+
resources:
22+
limits:
23+
cpu: "100m"
24+
memory: "128Mi"
25+
requests:
26+
cpu: "50m"
27+
memory: "64Mi"
28+
---
29+
apiVersion: v1
30+
kind: Service
31+
metadata:
32+
name: test-app-ipv6-service
33+
namespace: default
34+
spec:
35+
selector:
36+
app: test-app-ipv6
37+
ports:
38+
- port: 80
39+
targetPort: 80
40+
ipFamilies: [IPv6]
41+
ipFamilyPolicy: SingleStack
42+
---
43+
apiVersion: gateway.networking.k8s.io/v1
44+
kind: HTTPRoute
45+
metadata:
46+
name: test-route-ipv6
47+
namespace: default
48+
spec:
49+
parentRefs:
50+
- name: gateway
51+
sectionName: http
52+
namespace: default
53+
hostnames:
54+
- "ipv6-test.example.com"
55+
rules:
56+
- matches:
57+
- path:
58+
type: PathPrefix
59+
value: /
60+
backendRefs:
61+
- name: test-app-ipv6-service
62+
port: 80
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: ipv6-test-client
5+
namespace: default
6+
labels:
7+
app: ipv6-test-client
8+
spec:
9+
restartPolicy: Never
10+
containers:
11+
- name: test-client
12+
image: curlimages/curl:8.16.0
13+
imagePullPolicy: IfNotPresent
14+
command: ["sleep", "3600"] # Keep pod alive for exec commands
15+
resources:
16+
limits:
17+
cpu: "100m"
18+
memory: "128Mi"
19+
requests:
20+
cpu: "50m"
21+
memory: "64Mi"
22+
securityContext:
23+
allowPrivilegeEscalation: false
24+
runAsNonRoot: true
25+
runAsUser: 65534
26+
capabilities:
27+
drop:
28+
- ALL
29+
dnsConfig:
30+
options:
31+
- name: single-request-reopen
32+
- name: ndots
33+
value: "2"

tests/ipv6/run-ipv6-test.sh

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env bash
2+
3+
set -e # Exit immediately if a command exits with a non-zero status
4+
5+
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
6+
REPO_DIR=$(dirname $(dirname "$SCRIPT_DIR"))
7+
8+
TAG=$1
9+
10+
if [[ -z $TAG ]]; then
11+
echo "Usage: $0 <TAG> [RELEASE_NAME] [NAMESPACE] [CLUSTER_NAME]"
12+
echo "Error: TAG is a required parameter. Example usage: $(make ipv6-test TAG=release-X.Y-rc)"
13+
exit 1
14+
fi
15+
16+
RELEASE_NAME=${2:-nginx-gateway}
17+
NAMESPACE=${3:-nginx-gateway}
18+
CLUSTER_NAME=${4:-ipv6-only-${TAG}}
19+
RELEASE_REPO=ghcr.io/nginx/nginx-gateway-fabric
20+
21+
cleanup() {
22+
echo "Cleaning up resources..."
23+
kind delete cluster --name ${CLUSTER_NAME} || true
24+
}
25+
26+
trap cleanup EXIT
27+
28+
kind create cluster --name ${CLUSTER_NAME} --config ipv6/config/kind-ipv6-only.yaml
29+
30+
echo "== Installing NGINX Gateway Fabric..."
31+
echo "== Using NGF from ${RELEASE_REPO}:${TAG}..."
32+
echo "== Using NGINX from ${RELEASE_REPO}/nginx:${TAG}..."
33+
34+
HELM_PARAMETERS="--set nginx.config.ipFamily=ipv6"
35+
make helm-install-local HELM_PARAMETERS="${HELM_PARAMETERS}" \
36+
PREFIX="${RELEASE_REPO}" \
37+
TAG="${TAG}" \
38+
SELF_DIR="${REPO_DIR}/" \
39+
NGINX_SERVICE_TYPE="ClusterIP" \
40+
PULL_POLICY="Always"
41+
42+
echo "== Deploying Gateway..."
43+
kubectl apply -f ipv6/manifests/gateway.yaml
44+
45+
kubectl wait --for=condition=accepted --timeout=300s gateway/gateway
46+
POD_NAME=$(kubectl get pods -l app.kubernetes.io/instance=${RELEASE_NAME} -o jsonpath='{.items[0].metadata.name}')
47+
kubectl wait --for=condition=ready --timeout=300s pod/${POD_NAME}
48+
49+
echo "== Deploying IPv6 test application"
50+
kubectl apply -f ipv6/manifests/ipv6-test-app.yaml
51+
52+
echo "== Waiting for test applications to be ready..."
53+
kubectl wait --for=condition=available --timeout=300s deployment/test-app-ipv6
54+
55+
echo "== Getting NGF service IPv6 address from gateway status"
56+
NGF_IPV6=$(kubectl get gateway -o jsonpath='{.items[0].status.addresses[0].value}')
57+
echo "NGF IPv6 Address: $NGF_IPV6"
58+
59+
echo "=== Running IPv6-Only Tests ==="
60+
61+
echo "== Starting IPv6 test client"
62+
kubectl apply -f ipv6/manifests/ipv6-test-client.yaml
63+
kubectl wait --for=condition=ready --timeout=300s pod/ipv6-test-client
64+
65+
echo "== Test 1: Basic IPv6 connectivity =="
66+
kubectl exec ipv6-test-client -- curl --version
67+
kubectl exec ipv6-test-client -- nslookup gateway-nginx.default.svc.cluster.local || echo "Test 1: Basic IPv6 connectivity failed"
68+
test1_status=$?
69+
70+
if [[ $test1_status -eq 0 ]]; then
71+
echo "✅ Test 1: Basic IPv6 connectivity succeeded"
72+
fi
73+
74+
echo "== Test 2: NGF Service IPv6 connectivity =="
75+
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
76+
-H "Host: ipv6-test.example.com" \
77+
"http://[${NGF_IPV6}]:80/" || echo "Test 2: NGF Service IPv6 connectivity failed"
78+
test2_status=$?
79+
80+
if [[ $test2_status -eq 0 ]]; then
81+
echo "✅ Test 2: NGF Service IPv6 connectivity succeeded"
82+
fi
83+
84+
echo "== Test 3: Service DNS IPv6 connectivity =="
85+
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
86+
-H "Host: ipv6-test.example.com" \
87+
"http://gateway-nginx.default.svc.cluster.local:80/" || echo "Test 3: Service DNS IPv6 connectivity failed"
88+
test3_status=$?
89+
90+
if [[ $test3_status -eq 0 ]]; then
91+
echo "✅ Test 3: Service DNS IPv6 connectivity succeeded"
92+
fi
93+
94+
echo "=== Displaying IPv6-Only Configuration ==="
95+
echo "NGF Pod IPv6 addresses:"
96+
kubectl get pods -n nginx-gateway -o wide || true
97+
echo "NGF Service configuration:"
98+
kubectl get service ${HELM_RELEASE_NAME}-nginx-gateway-fabric -n nginx-gateway -o yaml || true
99+
100+
if [[ $test1_status -eq 0 && $test2_status -eq 0 && $test3_status -eq 0 ]]; then
101+
echo -e "✅ All tests passed!"
102+
else
103+
echo -e "❌ One or more tests failed. Check the output above to help debug any issues."
104+
fi

tests/suite/manifests/snippets-filter/invalid-duplicate-sf.yaml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ metadata:
1919
name: tea
2020
spec:
2121
parentRefs:
22-
- name: gateway
23-
sectionName: http
22+
- name: gateway
23+
sectionName: http
2424
hostnames:
25-
- "cafe.example.com"
25+
- "cafe.example.com"
2626
rules:
27-
- matches:
28-
- path:
29-
type: Exact
30-
value: /tea
31-
filters:
32-
- type: ExtensionRef
33-
extensionRef:
34-
group: gateway.nginx.org
35-
kind: SnippetsFilter
36-
name: duplicate-directive
37-
backendRefs:
38-
- name: tea
39-
port: 80
27+
- matches:
28+
- path:
29+
type: Exact
30+
value: /tea
31+
filters:
32+
- type: ExtensionRef
33+
extensionRef:
34+
group: gateway.nginx.org
35+
kind: SnippetsFilter
36+
name: duplicate-directive
37+
backendRefs:
38+
- name: tea
39+
port: 80

0 commit comments

Comments
 (0)