Skip to content

Commit ddb3ae3

Browse files
committed
make epp tls configurable, update conformance workflow
1 parent 346779c commit ddb3ae3

File tree

10 files changed

+165
-19
lines changed

10 files changed

+165
-19
lines changed

.github/workflows/conformance.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,26 @@ jobs:
198198
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
199199
run: gh release upload ${{ github.ref_name }} conformance-profile.yaml --clobber
200200
working-directory: ./tests
201+
202+
# The same setup works for inference conformance tests
203+
# and inference extension flag is enabled
204+
- name: Run inference conformance tests
205+
run: |
206+
make run-inference-conformance-tests CONFORMANCE_TAG=${{ github.sha }} NGF_VERSION=${{ github.ref_name }} CLUSTER_NAME=${{ github.run_id }}
207+
core_result=$(cat conformance-inference-profile.yaml | yq '.profiles[0].core.result')
208+
if [ "${core_result}" == "failure" ] ]; then echo "Inference Conformance test failed, see above for details." && exit 2; fi
209+
working-directory: ./tests
210+
211+
- name: Upload profile to GitHub
212+
if: ${{ inputs.enable-inference-extension }}
213+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
214+
with:
215+
name: conformance-profile-inference-${{ inputs.image }}-${{ inputs.k8s-version }}-${{ steps.ngf-meta.outputs.version }}
216+
path: ./tests/conformance-profile-inference.yaml
217+
218+
- name: Upload profile to release
219+
if: ${{ inputs.production-release && inputs.enable-inference-extension }}
220+
env:
221+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
222+
run: gh release upload ${{ github.ref_name }} conformance-profile-inference.yaml --clobber
223+
working-directory: ./tests

.github/workflows/lint.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ jobs:
125125
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0
126126
with:
127127
version: 3.14.0 # renovate: datasource=github-tags depName=helm/chart-testing
128+
# v6.0.0 resolved the compatibility issue with Python > 3.13. may be removed after the action itself is updated
129+
yamale_version: "6.0.0"
128130

129131
- name: Run chart-testing
130132
run: ct lint --print-config --config .ct.yaml

cmd/gateway/commands.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,15 +758,37 @@ func createSleepCommand() *cobra.Command {
758758
}
759759

760760
func createEndpointPickerCommand() *cobra.Command {
761+
var (
762+
endpointPickerEnableTLSFlag = "endpoint-picker-enable-tls"
763+
endpointPickerInsecureSkipVerifyFlag = "endpoint-picker-insecure-skip-verify"
764+
endpointPickerEnableTLS, endpointPickerInsecureSkipVerify bool
765+
)
766+
761767
cmd := &cobra.Command{
762768
Use: "endpoint-picker",
763769
Short: "Shim server for communication between NGINX and the Gateway API Inference Extension Endpoint Picker",
764770
RunE: func(_ *cobra.Command, _ []string) error {
765771
logger := ctlrZap.New().WithName("endpoint-picker-shim")
766-
handler := createEndpointPickerHandler(realExtProcClientFactory(), logger)
772+
handler := createEndpointPickerHandler(
773+
realExtProcClientFactory(endpointPickerEnableTLS, endpointPickerInsecureSkipVerify),
774+
logger,
775+
)
767776
return endpointPickerServer(handler)
768777
},
769778
}
779+
cmd.Flags().BoolVar(
780+
&endpointPickerEnableTLS,
781+
endpointPickerEnableTLSFlag,
782+
false,
783+
"Enable TLS for gRPC connections to the EndpointPicker extension.",
784+
)
785+
786+
cmd.Flags().BoolVar(
787+
&endpointPickerInsecureSkipVerify,
788+
endpointPickerInsecureSkipVerifyFlag,
789+
true,
790+
"Disable client verification of the EndpointPicker extension's server certificate.",
791+
)
770792

771793
return cmd
772794
}

cmd/gateway/commands_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,3 +924,51 @@ func TestUsageReportConfig(t *testing.T) {
924924
})
925925
}
926926
}
927+
928+
func TestEndpointPickerCommand(t *testing.T) {
929+
t.Parallel()
930+
tests := []flagTestCase{
931+
{
932+
name: "valid flags",
933+
args: []string{
934+
"--endpoint-picker-enable-tls=false",
935+
"--endpoint-picker-insecure-skip-verify=true",
936+
},
937+
wantErr: false,
938+
},
939+
{
940+
name: "flags have updated values",
941+
args: []string{
942+
"--endpoint-picker-enable-tls=true",
943+
"--endpoint-picker-insecure-skip-verify=false",
944+
},
945+
wantErr: false,
946+
},
947+
{
948+
name: "invalid flag values",
949+
args: []string{
950+
"--endpoint-picker-enable-tls=non-bool-value",
951+
},
952+
wantErr: true,
953+
expectedErrPrefix: `invalid argument "non-bool-value" for "--endpoint-picker-enable-tls" flag:` +
954+
` strconv.ParseBool: parsing "non-bool-value": invalid syntax`,
955+
},
956+
{
957+
name: "invalid flag values",
958+
args: []string{
959+
"--endpoint-picker-insecure-skip-verify=non-bool-value",
960+
},
961+
wantErr: true,
962+
expectedErrPrefix: `invalid argument "non-bool-value" for "--endpoint-picker-insecure-skip-verify" flag:` +
963+
` strconv.ParseBool: parsing "non-bool-value": invalid syntax`,
964+
},
965+
}
966+
967+
for _, test := range tests {
968+
t.Run(test.name, func(t *testing.T) {
969+
t.Parallel()
970+
cmd := createEndpointPickerCommand()
971+
testFlag(t, cmd, test)
972+
})
973+
}
974+
}

cmd/gateway/endpoint_picker.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/go-logr/logr"
1616
"google.golang.org/grpc"
1717
"google.golang.org/grpc/credentials"
18+
"google.golang.org/grpc/credentials/insecure"
1819
eppMetadata "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/metadata"
1920

2021
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/types"
@@ -34,13 +35,19 @@ func endpointPickerServer(handler http.Handler) error {
3435
}
3536

3637
// realExtProcClientFactory returns a factory that creates a new gRPC connection and client per request.
37-
func realExtProcClientFactory() extProcClientFactory {
38+
func realExtProcClientFactory(endpointPickerEnableTLS, endpointPickerInsecureSkipVerify bool) extProcClientFactory {
3839
return func(target string) (extprocv3.ExternalProcessorClient, func() error, error) {
39-
creds := credentials.NewTLS(&tls.Config{
40-
// add RootCAs or, if you have a self-signed server cert:
41-
InsecureSkipVerify: true, //nolint:gosec
42-
})
43-
conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(creds))
40+
var opts []grpc.DialOption
41+
42+
if !endpointPickerEnableTLS {
43+
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
44+
} else {
45+
creds := credentials.NewTLS(&tls.Config{
46+
InsecureSkipVerify: endpointPickerInsecureSkipVerify, //nolint:gosec
47+
})
48+
opts = append(opts, grpc.WithTransportCredentials(creds))
49+
}
50+
conn, err := grpc.NewClient(target, opts...)
4451
if err != nil {
4552
return nil, nil, err
4653
}

internal/controller/nginx/conf/nginx-plus.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ events {
1212
http {
1313
include /etc/nginx/conf.d/*.conf;
1414
include /etc/nginx/mime.types;
15-
js_import /usr/lib/nginx/modules/njs/httpmatches.js;
16-
js_import /usr/lib/nginx/modules/njs/epp.js;
15+
js_import modules/njs/httpmatches.js;
16+
js_import modules/njs/epp.js;
1717

1818
default_type application/octet-stream;
1919

internal/controller/nginx/conf/nginx.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ events {
1212
http {
1313
include /etc/nginx/conf.d/*.conf;
1414
include /etc/nginx/mime.types;
15-
js_import /usr/lib/nginx/modules/njs/httpmatches.js;
16-
js_import /usr/lib/nginx/modules/njs/epp.js;
15+
js_import modules/njs/httpmatches.js;
16+
js_import modules/njs/epp.js;
1717

1818
default_type application/octet-stream;
1919

tests/Makefile

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
CI ?= false
22
CLUSTER_NAME ?= kind
33
CONFORMANCE_PREFIX = conformance-test-runner## Prefix for the conformance test runner image
4+
CONFORMANCE_INFERENCE_PREFIX = conformance-inference-test-runner## Prefix for the conformance test runner image
45
CONFORMANCE_TAG = latest## Tag for the conformance test runner image
56
GATEWAY_CLASS = nginx## Gateway class to use
67
GINKGO_FLAGS =
@@ -46,6 +47,10 @@ update-go-modules: ## Update the gateway-api go modules to latest main version
4647
build-test-runner-image: ## Build conformance test runner image
4748
docker build --platform $(GOOS)/$(GOARCH) -t $(CONFORMANCE_PREFIX):$(CONFORMANCE_TAG) -f conformance/Dockerfile .
4849

50+
.PHONY: build-test-runner-image-for-inference
51+
build-test-runner-image-for-inference: ## Build conformance test runner image for inference extension
52+
docker build --platform $(GOOS)/$(GOARCH) -t $(CONFORMANCE_INFERENCE_PREFIX):$(CONFORMANCE_TAG) -f conformance/Dockerfile .
53+
4954
.PHONY: build-crossplane-image
5055
build-crossplane-image: ## Build the crossplane image
5156
docker build --platform $(GOOS)/$(GOARCH) --build-arg NGINX_CONF_DIR=$(NGINX_CONF_DIR) -t nginx-crossplane:latest -f framework/crossplane/Dockerfile ..
@@ -60,7 +65,7 @@ run-conformance-tests: ## Run conformance tests
6065
--restart=Never -- sh -c "go test -v . -tags conformance,experimental -args --gateway-class=$(GATEWAY_CLASS) \
6166
--supported-features=$(SUPPORTED_EXTENDED_FEATURES) --version=$(NGF_VERSION) --skip-tests=$(SKIP_TESTS) --conformance-profiles=$(CONFORMANCE_PROFILES) \
6267
--report-output=output.txt; cat output.txt" | tee output.txt
63-
./scripts/check-pod-exit-code.sh
68+
./scripts/check-pod-exit-code.sh conformance
6469
sed -e '1,/CONFORMANCE PROFILE/d' output.txt > conformance-profile.yaml
6570
grpc_core_result=`yq '.profiles[0].core.result' conformance-profile.yaml`; \
6671
http_core_result=`yq '.profiles[1].core.result' conformance-profile.yaml`; \
@@ -80,7 +85,7 @@ run-conformance-tests-openshift: ## Run conformance tests on OpenShift (skips te
8085
--restart=Never -- sh -c "go test -v . -tags conformance,experimental -args --gateway-class=$(GATEWAY_CLASS) \
8186
--supported-features=$(SUPPORTED_EXTENDED_FEATURES_OPENSHIFT) --version=$(NGF_VERSION) --skip-tests=$(SKIP_TESTS_OPENSHIFT) --conformance-profiles=$(CONFORMANCE_PROFILES) \
8287
--service-type=$(GW_SERVICE_TYPE) --report-output=output.txt; cat output.txt" | tee output.txt
83-
./scripts/check-pod-exit-code.sh
88+
./scripts/check-pod-exit-code.sh conformance
8489
sed -e '1,/CONFORMANCE PROFILE/d' output.txt > conformance-profile.yaml
8590
rm output.txt
8691
grpc_core_result=`yq '.profiles[0].core.result' conformance-profile.yaml`; \
@@ -94,18 +99,18 @@ run-conformance-tests-openshift: ## Run conformance tests on OpenShift (skips te
9499

95100
.PHONY: run-inference-conformance-tests
96101
run-inference-conformance-tests: ## Run inference conformance tests
97-
kind load docker-image $(CONFORMANCE_PREFIX):$(CONFORMANCE_TAG) --name $(CLUSTER_NAME)
102+
kind load docker-image $(CONFORMANCE_INFERENCE_PREFIX):$(CONFORMANCE_TAG) --name $(CLUSTER_NAME)
98103
kubectl apply -f conformance/conformance-rbac.yaml
99-
kubectl run -i conformance \
100-
--image=$(CONFORMANCE_PREFIX):$(CONFORMANCE_TAG) --image-pull-policy=Never \
104+
kubectl run -i conformance-inference \
105+
--image=$(CONFORMANCE_INFERENCE_PREFIX):$(CONFORMANCE_TAG) --image-pull-policy=Never \
101106
--overrides='{ "spec": { "serviceAccountName": "conformance" } }' \
102107
--restart=Never -- sh -c "go test -v . -tags conformance -args --gateway-class=$(GATEWAY_CLASS) \
103108
--version=$(NGF_VERSION) \
104109
--skip-tests=$(INFERENCE_SKIP_TESTS) \
105110
--supported-features=$(INFERENCE_SUPPORTED_FEATURES) \
106111
--report-output=output.txt; cat output.txt" | tee output.txt
107-
./scripts/check-pod-exit-code.sh
108-
sed -e '1,/CONFORMANCE PROFILE/d' output.txt > conformance-profile-inference.yaml
112+
./scripts/check-pod-exit-code.sh conformance-inference
113+
sed -e '1,/GatewayAPIInferenceExtensionVersion/d' output.txt > conformance-profile-inference.yaml
109114
rm output.txt
110115
core_result=`yq '.profiles[0].core.result' conformance-profile-inference.yaml`; \
111116
if [ "$$core_result" != "failure" ] ; then \
@@ -117,6 +122,12 @@ run-inference-conformance-tests: ## Run inference conformance tests
117122
.PHONY: cleanup-conformance-tests
118123
cleanup-conformance-tests: ## Clean up conformance tests fixtures
119124
kubectl delete pod conformance
125+
kubectl delete pod conformance-inference
126+
kubectl delete -f conformance/conformance-rbac.yaml
127+
128+
.PHONY: cleanup-conformance-inference-tests
129+
cleanup-conformance-inference-tests: ## Clean up conformance inference tests fixtures
130+
kubectl delete pod conformance-inference
120131
kubectl delete -f conformance/conformance-rbac.yaml
121132

122133
.PHONY: reset-go-modules
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
date: "2025-10-16T01:03:45Z"
3+
gatewayAPIChannel: experimental
4+
gatewayAPIVersion: v1.3.0
5+
implementation:
6+
contact:
7+
- https://github.com/nginx/nginx-gateway-fabric/discussions/new/choose
8+
organization: nginx
9+
project: nginx-gateway-fabric
10+
url: https://github.com/nginx/nginx-gateway-fabric
11+
version: edge
12+
kind: ConformanceReport
13+
mode: default
14+
profiles:
15+
- core:
16+
result: partial
17+
skippedTests:
18+
- InferencePoolResolvedRefsCondition
19+
statistics:
20+
Failed: 0
21+
Passed: 8
22+
Skipped: 1
23+
name: Gateway
24+
summary: Core tests partially succeeded with 1 test skips.

tests/scripts/check-pod-exit-code.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
22

33
set -eo pipefail
44

5-
CODE=$(kubectl get pod conformance -o jsonpath='{.status.containerStatuses[].state.terminated.exitCode}')
5+
# Check if a pod name is provided as an argument
6+
if [ "$#" -ne 1 ]; then
7+
echo "Provide pod name: $0"
8+
exit 1
9+
fi
10+
11+
POD_NAME=$1
12+
13+
# Get the exit code of the specified pod
14+
CODE=$(kubectl get pod "${POD_NAME}" -o jsonpath='{.status.containerStatuses[].state.terminated.exitCode}')
615
if [ "${CODE}" -ne 0 ]; then
716
exit 2
817
fi

0 commit comments

Comments
 (0)