Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ HELM_SCHEMA_VERSION = 0.18.1
PREFIX ?= nginx-gateway-fabric## The name of the NGF image. For example, nginx-gateway-fabric
NGINX_PREFIX ?= $(PREFIX)/nginx## The name of the nginx image. For example: nginx-gateway-fabric/nginx
NGINX_PLUS_PREFIX ?= $(PREFIX)/nginx-plus## The name of the nginx plus image. For example: nginx-gateway-fabric/nginx-plus
NGINX_SERVICE_TYPE ?= NodePort## The type of the nginx service. Possible values: NodePort, LoadBalancer, ClusterIP
PULL_POLICY ?= Never## The pull policy of the images. Possible values: Always, IfNotPresent, Never
TAG ?= $(VERSION:v%=%)## The tag of the image. For example, 1.1.0
TARGET ?= local## The target of the build. Possible values: local and container
OUT_DIR ?= build/out## The folder where the binary will be stored
Expand Down Expand Up @@ -226,13 +228,13 @@ install-ngf-local-build-with-plus: check-for-plus-usage-endpoint build-images-wi

.PHONY: helm-install-local
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.
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)
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)

.PHONY: helm-install-local-with-plus
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.
kubectl create namespace nginx-gateway || true
kubectl -n nginx-gateway create secret generic nplus-license --from-file $(PLUS_LICENSE_FILE) || true
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)
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)

.PHONY: check-for-plus-usage-endpoint
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+.
Expand Down
1 change: 1 addition & 0 deletions docs/developer/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ 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. An example of running this script for release 2.1.0 would look like this: `make ipv6-test TAG=release-2.1-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
5 changes: 5 additions & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,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 TAG=release-X.Y-rc
./ipv6/run-ipv6-test.sh $(TAG)


.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"
104 changes: 104 additions & 0 deletions tests/ipv6/run-ipv6-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env bash

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

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
REPO_DIR=$(dirname $(dirname "$SCRIPT_DIR"))

TAG=$1

if [[ -z $TAG ]]; then
echo "Usage: $0 <TAG> [RELEASE_NAME] [NAMESPACE] [CLUSTER_NAME]"
echo "Error: TAG is a required parameter. Example usage: $(make ipv6-test TAG=release-X.Y-rc)"
exit 1
fi

RELEASE_NAME=${2:-nginx-gateway}
NAMESPACE=${3:-nginx-gateway}
CLUSTER_NAME=${4:-ipv6-only-${TAG}}
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 "== Installing NGINX Gateway Fabric..."
echo "== Using NGF from ${RELEASE_REPO}:${TAG}..."
echo "== Using NGINX from ${RELEASE_REPO}/nginx:${TAG}..."

HELM_PARAMETERS="--set nginx.config.ipFamily=ipv6"
make helm-install-local HELM_PARAMETERS="${HELM_PARAMETERS}" \
PREFIX="${RELEASE_REPO}" \
TAG="${TAG}" \
SELF_DIR="${REPO_DIR}/" \
NGINX_SERVICE_TYPE="ClusterIP" \
PULL_POLICY="Always"

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=${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