Skip to content

Commit 3cd897a

Browse files
author
Kate Osborn
committed
Support multiple routes per path
* Adds new boolean field "any" to internal httpMatch object. An httpMatch with any=true represents a path-only match. Any request sent to the path will satisfy this match. * Changes algorithm for sorting routes to match the rules defined by the spec. * Adds local development instructions for njs module as well as test coverage output. * Updates advanced-routing example to demonstrate new capabilities.
1 parent e6bccad commit 3cd897a

File tree

20 files changed

+3570
-585
lines changed

20 files changed

+3570
-585
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
uses: rutajdash/[email protected]
8181
with:
8282
config_path: ${{ github.workspace }}/internal/nginx/modules/.prettierrc
83-
file_pattern: ${{ github.workspace }}/internal/nginx/modules/*.js
83+
file_pattern: ${{ github.workspace }}/internal/nginx/modules/**/*.js
8484
prettier_version: 2.6.2
8585
- name: Prettier Output
8686
if: ${{ failure() }}
@@ -119,9 +119,9 @@ jobs:
119119
- name: Setup Node.js Environment
120120
uses: actions/setup-node@v3
121121
with:
122-
node_version: 18
122+
node-version: 18
123123
- run: npm install mocha@^8.2 esm chai
124-
- run: npx mocha -r esm ${{ github.workspace }}/internal/nginx/modules/httpmatches_test.js
124+
- run: npx mocha -r esm ${{ github.workspace }}/internal/nginx/modules/test/httpmatches.test.js
125125

126126
binary:
127127
name: Build Binary

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ cover.html
2525

2626
# Binary and Artifacts
2727
build/.out
28+
29+
# Node modules
30+
internal/nginx/modules/node_modules
31+
32+
# JS test coverage
33+
internal/nginx/modules/coverage

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ fmt: ## Run go fmt against code.
6767

6868
.PHONY: njs-fmt
6969
njs-fmt: ## Run prettier against the njs httpmatches module.
70-
docker run --rm \
71-
-v $(PWD)/internal/nginx/modules/:/njs-modules/ \
70+
docker run --rm -w /modules \
71+
-v $(PWD)/internal/nginx/modules/:/modules/ \
7272
node:18 \
73-
npx [email protected] --write njs-modules/ --config=njs-modules/.prettierrc
73+
/bin/bash -c "npm install && npm run format"
7474

7575
.PHONY: vet
7676
vet: ## Run go vet against code.
@@ -86,10 +86,10 @@ unit-test: ## Run unit tests for the go code
8686
go tool cover -html=cover.out -o cover.html
8787

8888
njs-unit-test: ## Run unit tests for the njs httpmatches module.
89-
docker run --rm -w /src \
90-
-v $(PWD)/internal/nginx/modules/:/src/njs-modules/ \
89+
docker run --rm -w /modules \
90+
-v $(PWD)/internal/nginx/modules:/modules/ \
9191
node:18 \
92-
/bin/bash -c "npm install mocha@^8.2 esm chai && npx mocha -r esm njs-modules/httpmatches_test.js"
92+
/bin/bash -c "npm install && npm test && npm run clean"
9393

9494
.PHONY: dev-all
9595
dev-all: deps fmt njs-fmt vet lint unit-test njs-unit-test

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ You can deploy NGINX Kubernetes Gateway on an existing Kubernetes 1.16+ cluster.
7171
1. Create the njs-modules configmap:
7272
7373
```
74-
kubectl create configmap njs-modules --from-file=internal/nginx/modules/httpmatches.js -n nginx-gateway
74+
kubectl create configmap njs-modules --from-file=internal/nginx/modules/src/httpmatches.js -n nginx-gateway
7575
```
7676
7777
1. Deploy the NGINX Kubernetes Gateway:

examples/advanced-routing/README.md

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
In this example we will deploy NGINX Kubernetes Gateway and configure advanced routing rules for a simple cafe application.
44
We will use `HTTPRoute` resources to route traffic to the cafe application based on a combination of the request method, headers, and query parameters.
55

6+
The cafe application consists of four services: `coffee-v1-svc`, `coffee-v2-svc`, `tea-svc`, and `tea-post-svc`. In the next section we will create the following routing rules for the cafe application:
7+
- For the path `/coffee` route requests with the header `version` set to `v2` or with the query param `TEST` set to `v2` to `coffee-v2-svc`, and all other requests to `coffee-v1-svc`.
8+
- For the path `/tea` route POST requests to `tea-post-svc`, and all other requests, such as `GET` requests, to `tea-svc`.
9+
610
## Running the Example
711

812
## 1. Deploy NGINX Kubernetes Gateway
@@ -33,9 +37,11 @@ We will use `HTTPRoute` resources to route traffic to the cafe application based
3337

3438
```
3539
kubectl -n default get pods
36-
NAME READY STATUS RESTARTS AGE
37-
coffee-6f4b79b975-2sb28 1/1 Running 0 12s
38-
tea-6fb46d899f-fm7zr 1/1 Running 0 12s
40+
NAME READY STATUS RESTARTS AGE
41+
coffee-v1-75869cf7ff-vlfpq 1/1 Running 0 17m
42+
coffee-v2-67499ff985-2k6cc 1/1 Running 0 17m
43+
tea-6fb46d899f-hjzwr 1/1 Running 0 17m
44+
tea-post-648dfcdd6c-2rlqb 1/1 Running 0 17m
3945
```
4046

4147
## 3. Configure Routing
@@ -48,51 +54,53 @@ We will use `HTTPRoute` resources to route traffic to the cafe application based
4854

4955
## 4. Test the Application
5056

51-
We will use `curl` to send requests to the `coffee` and `tea` services.
57+
We will use `curl` to send requests to the `/coffee` and `/tea` endpoints of the cafe application.
5258

5359
### 4.1 Access coffee
5460

55-
Send a `POST` request to the path `/coffee` with the headers `X-Demo-Header:Demo-X1` and `version:v1`:
61+
Send a request with the header `version:v2` and confirm that the response comes from `coffee-v2-svc`:
5662

57-
```
58-
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -X POST -H "X-Demo-Header:Demo-X1" -H "version:v1"
59-
Server address: 10.12.0.18:80
60-
Server name: coffee-7586895968-r26zn
63+
```bash
64+
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -H "version:v2"
65+
Server address: 10.116.2.67:8080
66+
Server name: coffee-v2-67499ff985-gw6vt
67+
...
6168
```
6269

63-
Header keys are case-insensitive, so we can also access coffee with the following request:
70+
Send a request with the query parameter `TEST=v2` and confirm that the response comes from `coffee-v2-svc`:
6471

65-
```
66-
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -X POST -H "X-DEMO-HEADER:Demo-X1" -H "Version:v1"
67-
Server address: 10.12.0.18:80
68-
Server name: coffee-7586895968-r26zn
72+
```bash
73+
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee?TEST=v2
74+
Server address: 10.116.2.67:8080
75+
Server name: coffee-v2-67499ff985-gw6vt
76+
...
6977
```
7078

71-
Only `POST` requests to the path `/coffee` with the headers `X-Demo-Header:Demo-X1` and `version:v1` will be able to access coffee.
72-
For example, try sending the following `GET` request:
73-
```
74-
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -H "X-Demo-Header:Demo-X1" -H "version:v1"
75-
```
79+
Send a request without the header or the query parameter and confirm the response comes from `coffee-v1-svc`:
7680

77-
NGINX Kubernetes Gateway returns a 405 since the request method does not match the method defined in the routing rule for `/coffee`.
81+
```bash
82+
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee
83+
Server address: 10.116.2.70:8080
84+
Server name: coffee-v1-75869cf7ff-vlfpq
85+
...
86+
```
7887

7988
### 4.2 Access tea
8089

81-
Send a request to the path `/tea` with the query parameter `Great=Example`:
90+
Send a POST request and confirm that the response comes from `tea-post-svc`:
8291

92+
```bash
93+
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/tea -X POST
94+
Server address: 10.116.2.72:8080
95+
Server name: tea-post-648dfcdd6c-2rlqb
96+
...
8397
```
84-
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/tea?Great=Example
85-
Server address: 10.12.0.19:80
86-
Server name: tea-7cd44fcb4d-xfw2x
87-
```
88-
89-
Query parameters are case-sensitive, so the case must match what you specify in the `HTTPRoute` resource.
9098

91-
Only requests to the path `/tea` with the query parameter `Great=Example` will be able to access tea.
92-
For example, try sending the following request:
99+
Send a GET request and confirm that the response comes from `tea-svc`:
93100

94-
```
101+
```bash
95102
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/tea
103+
Server address: 10.116.3.30:8080
104+
Server name: tea-6fb46d899f-hjzwr
105+
...
96106
```
97-
98-
NGINX Kubernetes Gateway returns a 404 since the request does not satisfy the routing rule configured for `/tea`.
Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
apiVersion: gateway.networking.k8s.io/v1alpha2
22
kind: HTTPRoute
3-
metadata:
4-
name: cafe
5-
spec:
6-
hostnames:
7-
- "cafe.example.com"
8-
rules:
9-
- backendRefs:
10-
- name: main
11-
port: 80
12-
---
13-
apiVersion: gateway.networking.k8s.io/v1alpha2
14-
kind: HTTPRoute
153
metadata:
164
name: coffee
175
spec:
@@ -22,14 +10,24 @@ spec:
2210
- path:
2311
type: PathPrefix
2412
value: /coffee
25-
method: POST
13+
backendRefs:
14+
- name: coffee-v1-svc
15+
port: 80
16+
- matches:
17+
- path:
18+
type: PathPrefix
19+
value: /coffee
2620
headers:
27-
- name: X-Demo-Header # header names are case-insensitive
28-
value: Demo-X1 # header values are case-sensitive
2921
- name: version
30-
value: v1
22+
value: v2
23+
- path:
24+
type: PathPrefix
25+
value: /coffee
26+
queryParams:
27+
- name: TEST
28+
value: v2
3129
backendRefs:
32-
- name: coffee
30+
- name: coffee-v2-svc
3331
port: 80
3432
---
3533
apiVersion: gateway.networking.k8s.io/v1alpha2
@@ -44,9 +42,15 @@ spec:
4442
- path:
4543
type: PathPrefix
4644
value: /tea
47-
queryParams:
48-
- name: Great # query params and values are case-sensitive
49-
value: Example
45+
method: POST
46+
backendRefs:
47+
- name: tea-post-svc
48+
port: 80
49+
- matches:
50+
- path:
51+
type: PathPrefix
52+
value: /tea
53+
method: GET
5054
backendRefs:
51-
- name: tea
55+
- name: tea-svc
5256
port: 80

examples/advanced-routing/cafe.yaml

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,101 @@
11
apiVersion: apps/v1
22
kind: Deployment
33
metadata:
4-
name: coffee
4+
name: coffee-v1
55
spec:
66
replicas: 1
77
selector:
88
matchLabels:
9-
app: coffee
9+
app: coffee-v1
1010
template:
1111
metadata:
1212
labels:
13-
app: coffee
13+
app: coffee-v1
1414
spec:
1515
containers:
16-
- name: coffee
16+
- name: coffee-v1
1717
image: nginxdemos/nginx-hello:plain-text
1818
ports:
1919
- containerPort: 8080
2020
---
2121
apiVersion: v1
2222
kind: Service
2323
metadata:
24-
name: coffee
24+
name: coffee-v1-svc
2525
spec:
2626
ports:
2727
- port: 80
2828
targetPort: 8080
2929
protocol: TCP
3030
name: http
3131
selector:
32-
app: coffee
32+
app: coffee-v1
33+
---
34+
apiVersion: apps/v1
35+
kind: Deployment
36+
metadata:
37+
name: coffee-v2
38+
spec:
39+
replicas: 1
40+
selector:
41+
matchLabels:
42+
app: coffee-v2
43+
template:
44+
metadata:
45+
labels:
46+
app: coffee-v2
47+
spec:
48+
containers:
49+
- name: coffee-v2
50+
image: nginxdemos/nginx-hello:plain-text
51+
ports:
52+
- containerPort: 8080
53+
---
54+
apiVersion: v1
55+
kind: Service
56+
metadata:
57+
name: coffee-v2-svc
58+
spec:
59+
ports:
60+
- port: 80
61+
targetPort: 8080
62+
protocol: TCP
63+
name: http
64+
selector:
65+
app: coffee-v2
66+
---
67+
apiVersion: apps/v1
68+
kind: Deployment
69+
metadata:
70+
name: tea-post
71+
spec:
72+
replicas: 1
73+
selector:
74+
matchLabels:
75+
app: tea-post
76+
template:
77+
metadata:
78+
labels:
79+
app: tea-post
80+
spec:
81+
containers:
82+
- name: tea-post
83+
image: nginxdemos/nginx-hello:plain-text
84+
ports:
85+
- containerPort: 8080
86+
---
87+
apiVersion: v1
88+
kind: Service
89+
metadata:
90+
name: tea-post-svc
91+
spec:
92+
ports:
93+
- port: 80
94+
targetPort: 8080
95+
protocol: TCP
96+
name: http
97+
selector:
98+
app: tea-post
3399
---
34100
apiVersion: apps/v1
35101
kind: Deployment
@@ -54,7 +120,7 @@ spec:
54120
apiVersion: v1
55121
kind: Service
56122
metadata:
57-
name: tea
123+
name: tea-svc
58124
spec:
59125
ports:
60126
- port: 80

0 commit comments

Comments
 (0)