Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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 ?= edge # 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: nginxdemos/nginx-hello:plain-text
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.16.0
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"
106 changes: 106 additions & 0 deletions tests/ipv6/run-ipv6-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/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..."
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 -

echo "== Installing NGINX Gateway Fabric..."
echo "== Using NGF from ${RELEASE_REPO}:${RELEASE_IMAGE}..."
echo "== Using NGINX from ${RELEASE_REPO}/nginx:${RELEASE_IMAGE}..."

helm install ${HELM_RELEASE_NAME} --wait 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} \
--set nginx.image.repository=${RELEASE_REPO}/nginx \
--set nginx.image.tag=${RELEASE_IMAGE}

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

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 test applications to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/test-app-ipv6

echo " ==Getting NGF service IPv6 address from gateway status"
NGF_IPV6=$(kubectl get gateway -o jsonpath='{.items[0].status.addresses[0].value}')
echo "NGF IPv6 Address: $NGF_IPV6"

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

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

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
Loading