Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/developer/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ To create a new release, follow these steps:
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`).
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.
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).
3. Run the IPv6 tests using the `make ipv6-tests` target. This must be run from within the `tests` directory. This script requires two arguments. The release version (e.g. `vX.Y.Z`) and the release image tag (e.g. `release-X.X-rc`).
For example, when running this script for release 2.1.0, it would look like this: `make ipv6-test RELEASE=vX.Y.Z RELEASE_IMAGE=release-X.X-rc`
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:
1. Update the [README](/README.md) to include information about the release.
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.
Expand Down
7 changes: 7 additions & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ SUPPORTED_EXTENDED_FEATURES = HTTPRouteQueryParamMatching,HTTPRouteMethodMatchin
STANDARD_CONFORMANCE_PROFILES = GATEWAY-HTTP,GATEWAY-GRPC
EXPERIMENTAL_CONFORMANCE_PROFILES = GATEWAY-TLS
CONFORMANCE_PROFILES = $(STANDARD_CONFORMANCE_PROFILES) # by default we use the standard conformance profiles. If experimental is enabled we override this and add the experimental profiles.
RELEASE ?= main # e.g. v2.1.0
RELEASE_IMAGE ?= latest # e.g. release-2.1.0-rc
SKIP_TESTS =
CEL_TEST_TARGET =

Expand Down Expand Up @@ -118,6 +120,11 @@ start-longevity-test: nfr-test ## Start the longevity test to run for 4 days in
stop-longevity-test: export STOP_LONGEVITY=true
stop-longevity-test: nfr-test ## Stop the longevity test and collects results

.PHONY: ipv6-tests
ipv6-tests: GOARCH=amd64
ipv6-tests: ## Example usage: make ipv6-tests RELEASE=vX.Y.Z RELEASE_IMAGE=release-X.Y-rc
./ipv6/run-ipv6-test.sh $(RELEASE) $(RELEASE_IMAGE)


.PHONY: .vm-nfr-test
.vm-nfr-test: ## Runs the NFR tests on the GCP VM (called by `nfr-test`)
Expand Down
8 changes: 8 additions & 0 deletions tests/ipv6/config/kind-ipv6-only.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
ipFamily: ipv6 # Explicitly set the cluster to use IPv6
apiServerAddress: "::1"
disableDefaultCNI: false # Use Kind's default CNI
nodes:
- role: control-plane
11 changes: 11 additions & 0 deletions tests/ipv6/manifests/gateway.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP
hostname: "*.example.com"
62 changes: 62 additions & 0 deletions tests/ipv6/manifests/ipv6-test-app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-ipv6
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app-ipv6
template:
metadata:
labels:
app: test-app-ipv6
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
resources:
limits:
cpu: "100m"
memory: "128Mi"
requests:
cpu: "50m"
memory: "64Mi"
---
apiVersion: v1
kind: Service
metadata:
name: test-app-ipv6-service
namespace: default
spec:
selector:
app: test-app-ipv6
ports:
- port: 80
targetPort: 80
ipFamilies: [IPv6]
ipFamilyPolicy: SingleStack
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: test-route-ipv6
namespace: default
spec:
parentRefs:
- name: gateway
sectionName: http
namespace: default
hostnames:
- "ipv6-test.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: test-app-ipv6-service
port: 80
33 changes: 33 additions & 0 deletions tests/ipv6/manifests/ipv6-test-client.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: v1
kind: Pod
metadata:
name: ipv6-test-client
namespace: default
labels:
app: ipv6-test-client
spec:
restartPolicy: Never
containers:
- name: test-client
image: curlimages/curl:8.11.1
imagePullPolicy: IfNotPresent
command: ["sleep", "3600"] # Keep pod alive for exec commands
resources:
limits:
cpu: "100m"
memory: "128Mi"
requests:
cpu: "50m"
memory: "64Mi"
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 65534
capabilities:
drop:
- ALL
dnsConfig:
options:
- name: single-request-reopen
- name: ndots
value: "2"
112 changes: 112 additions & 0 deletions tests/ipv6/run-ipv6-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env bash

set -e # Exit immediately if a command exits with a non-zero status

RELEASE=$1
RELEASE_IMAGE=$2

if [[ -z $RELEASE || -z $RELEASE_IMAGE ]]; then
echo "Usage: $0 <RELEASE> <RELEASE_IMAGE> [HELM_RELEASE_NAME] [NAMESPACE] [CLUSTER_NAME]"
echo "Error: RELEASE and RELEASE_IMAGE are required parameters. Example usage $(make ipv6-test RELEASE=vX.Y.Z RELEASE_IMAGE=release-X.Y-rc)"
exit 1
fi

HELM_RELEASE_NAME=${3:-ngf}
NAMESPACE=${4:-nginx-gateway}
CLUSTER_NAME=${5:-ipv6-only-${RELEASE}}
RELEASE_REPO=ghcr.io/nginx/nginx-gateway-fabric

cleanup() {
echo "Cleaning up resources..."
kubectl delete -f ipv6/manifests/ipv6-test-app.yaml || true
kubectl delete -f ipv6/manifests/ipv6-test-client.yaml || true
kubectl delete -f ipv6/manifests/gateway.yaml || true
helm uninstall ${HELM_RELEASE_NAME} -n ${NAMESPACE} || true
kind delete cluster --name ${CLUSTER_NAME} || true
}

trap cleanup EXIT

kind create cluster --name ${CLUSTER_NAME} --config ipv6/config/kind-ipv6-only.yaml

echo "Applying Gateway API CRDs"
kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=${RELEASE}" | kubectl apply -f -

docker pull ${RELEASE_REPO}:${RELEASE_IMAGE}

docker save ${RELEASE_REPO}:${RELEASE_IMAGE} | docker exec -i ${CLUSTER_NAME}-control-plane ctr --namespace=k8s.io images import -

helm upgrade --install ${HELM_RELEASE_NAME} oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
--create-namespace -n ${NAMESPACE} \
--set nginx.config.ipFamily=ipv6 \
--set nginx.service.type=ClusterIP \
--set nginxGateway.image.repository=${RELEASE_REPO} \
--set nginxGateway.image.tag=${RELEASE_IMAGE}

echo "Deploying Gateway..."
kubectl apply -f ipv6/manifests/gateway.yaml

echo "Waiting for NGINX Gateway to be ready..."
kubectl wait --for=condition=accepted --timeout=300s gateway/gateway
POD_NAME=$(kubectl get pods -l app.kubernetes.io/instance=${HELM_RELEASE_NAME} -o jsonpath='{.items[0].metadata.name}')
kubectl wait --for=condition=ready --timeout=300s pod/${POD_NAME}

echo "Deploying IPv6 test application"
kubectl apply -f ipv6/manifests/ipv6-test-app.yaml

echo "Waiting for NGF to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/${HELM_RELEASE_NAME}-nginx-gateway-fabric -n ${NAMESPACE}

echo "Waiting for test applications to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/test-app-ipv6

echo "Deploying IPv6 test client"
kubectl apply -f ipv6/manifests/ipv6-test-client.yaml
kubectl wait --for=condition=ready --timeout=300s pod/ipv6-test-client

echo "Getting NGF service IPv6 address"
NGF_IPV6=$(kubectl get service gateway-nginx -o jsonpath='{.spec.clusterIP}')
echo "NGF IPv6 Address: $NGF_IPV6"

echo "=== Running IPv6-Only Tests ==="

echo "== Test 1: Basic IPv6 connectivity =="
kubectl exec ipv6-test-client -- curl --version
kubectl exec ipv6-test-client -- nslookup gateway-nginx.default.svc.cluster.local || echo "Test 1: Basic IPv6 connectivity failed"
test1_status=$?

if [[ $test1_status -eq 0 ]]; then
echo "✅ Test 1: Basic IPv6 connectivity succeeded"
fi

echo "== Test 2: NGF Service IPv6 connectivity =="
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
-H "Host: ipv6-test.example.com" \
"http://[${NGF_IPV6}]:80/" || echo "Test 2: NGF Service IPv6 connectivity failed"
test2_status=$?

if [[ $test2_status -eq 0 ]]; then
echo "✅ Test 2: NGF Service IPv6 connectivity succeeded"
fi

echo "== Test 3: Service DNS IPv6 connectivity =="
kubectl exec ipv6-test-client -- curl -6 --connect-timeout 30 --max-time 60 -v \
-H "Host: ipv6-test.example.com" \
"http://gateway-nginx.default.svc.cluster.local:80/" || echo "Test 3: Service DNS IPv6 connectivity failed"
test3_status=$?

if [[ $test3_status -eq 0 ]]; then
echo "✅ Test 3: Service DNS IPv6 connectivity succeeded"
fi

echo "=== Displaying IPv6-Only Configuration ==="
echo "NGF Pod IPv6 addresses:"
kubectl get pods -n nginx-gateway -o wide || true
echo "NGF Service configuration:"
kubectl get service ${HELM_RELEASE_NAME}-nginx-gateway-fabric -n nginx-gateway -o yaml || true

if [[ $test1_status -eq 0 && $test2_status -eq 0 && $test3_status -eq 0 ]]; then
echo -e "✅ All tests passed!"
else
echo -e "❌ One or more tests failed. Check the output above to help debug any issues."
fi
32 changes: 16 additions & 16 deletions tests/suite/manifests/snippets-filter/invalid-duplicate-sf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ metadata:
name: tea
spec:
parentRefs:
- name: gateway
sectionName: http
- name: gateway
sectionName: http
hostnames:
- "cafe.example.com"
- "cafe.example.com"
rules:
- matches:
- path:
type: Exact
value: /tea
filters:
- type: ExtensionRef
extensionRef:
group: gateway.nginx.org
kind: SnippetsFilter
name: duplicate-directive
backendRefs:
- name: tea
port: 80
- matches:
- path:
type: Exact
value: /tea
filters:
- type: ExtensionRef
extensionRef:
group: gateway.nginx.org
kind: SnippetsFilter
name: duplicate-directive
backendRefs:
- name: tea
port: 80