Skip to content

Commit

Permalink
Add yarp.ingress.kubernetes.io/route-queryparameters to allow ingress…
Browse files Browse the repository at this point in the history
… forking based on query parameters (dotnet#2436)

* Add QueryParameters routing for Kubernetes.Ingress

* Update documentation to be plural

* retrigger checks

* Fix validation file

* Update docs

---------

Co-authored-by: Jeff Sedlak <jsedlak@gmail.com>
Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
  • Loading branch information
3 people authored Mar 14, 2024
1 parent e678db4 commit 1483fb7
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 4 deletions.
32 changes: 32 additions & 0 deletions samples/KubernetesIngress.Sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ metadata:
- another-header-value
Mode: Contains
IsCaseSensitive: false
yarp.ingress.kubernetes.io/route-queryparameters: |
- Name: the-queryparameters-key
Values:
- the-queryparameters-value
Mode: Contains
IsCaseSensitive: false
- Name: another-queryparameters-key
Values:
- another-queryparameters-value
Mode: Contains
IsCaseSensitive: false
spec:
rules:
- http:
Expand Down Expand Up @@ -86,6 +97,7 @@ The table below lists the available annotations.
|yarp.ingress.kubernetes.io/session-affinity|[SessionAffinityConfig](https://microsoft.github.io/reverse-proxy/api/Yarp.ReverseProxy.Configuration.SessionAffinityConfig.html)|
|yarp.ingress.kubernetes.io/transforms|List<Dictionary<string, string>>|
|yarp.ingress.kubernetes.io/route-headers|List<[RouteHeader](https://microsoft.github.io/reverse-proxy/api/Yarp.ReverseProxy.Configuration.RouteHeader.html)>|
|yarp.ingress.kubernetes.io/route-queryparameters|List<[RouteQueryParameter](https://microsoft.github.io/reverse-proxy/api/Yarp.ReverseProxy.Configuration.RouteQueryParameter.html)>|
|yarp.ingress.kubernetes.io/route-order|int|

#### Authorization Policy
Expand Down Expand Up @@ -213,6 +225,26 @@ yarp.ingress.kubernetes.io/route-headers: |
IsCaseSensitive: false
```

#### Route QueryParameters

`route-queryparameters` are the YAML representation of YARP [Parameter Based Routing](https://microsoft.github.io/reverse-proxy/articles/queryparameter-routing.html).

See https://microsoft.github.io/reverse-proxy/api/Yarp.ReverseProxy.Configuration.RouteQueryParameter.html.

```
yarp.ingress.kubernetes.io/route-queryparameters: |
- Name: the-queryparameter-name
Values:
- the-queryparameter-value
Mode: Contains
IsCaseSensitive: false
- Name: another-queryparameter-name
Values:
- another-queryparameter-value
Mode: Contains
IsCaseSensitive: false
```

#### Route Order

See https://microsoft.github.io/reverse-proxy/api/Yarp.ReverseProxy.Configuration.RouteConfig.html#Yarp_ReverseProxy_Configuration_RouteConfig_Order.
Expand Down
22 changes: 21 additions & 1 deletion src/Kubernetes.Controller/Converters/YarpIngressOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ internal sealed class YarpIngressOptions
public HealthCheckConfig HealthCheck { get; set; }
public Dictionary<string, string> RouteMetadata { get; set; }
public List<RouteHeader> RouteHeaders { get; set; }
public List<RouteQueryParameter> RouteQueryParameters { get; set; }
public int? RouteOrder { get; set; }
}

internal sealed class RouteHeaderWapper
internal sealed class RouteHeaderWrapper
{
public string Name { get; init; }
public List<string> Values { get; init; }
Expand All @@ -46,3 +47,22 @@ public RouteHeader ToRouteHeader()
};
}
}

internal sealed class RouteQueryParameterWrapper
{
public string Name { get; init; }
public List<string> Values { get; init; }
public QueryParameterMatchMode Mode { get; init; }
public bool IsCaseSensitive { get; init; }

public RouteQueryParameter ToRouteQueryParameter()
{
return new RouteQueryParameter
{
Name = Name,
Values = Values,
Mode = Mode,
IsCaseSensitive = IsCaseSensitive
};
}
}
12 changes: 9 additions & 3 deletions src/Kubernetes.Controller/Converters/YarpParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ private static RouteConfig CreateRoute(YarpIngressContext ingressContext, V1HTTP
{
Hosts = host is not null ? new[] { host } : Array.Empty<string>(),
Path = pathMatch,
Headers = ingressContext.Options.RouteHeaders
Headers = ingressContext.Options.RouteHeaders,
QueryParameters = ingressContext.Options.RouteQueryParameters
},
ClusterId = cluster.ClusterId,
RouteId = $"{ingressContext.Ingress.Metadata.Name}.{ingressContext.Ingress.Metadata.NamespaceProperty}:{host}{path.Path}",
Expand Down Expand Up @@ -276,8 +277,13 @@ private static YarpIngressOptions HandleAnnotations(YarpIngressContext context,
}
if (annotations.TryGetValue("yarp.ingress.kubernetes.io/route-headers", out var routeHeaders))
{
// YamlDeserializer does not support IReadOnlyList<string> in RouteHeader for now, so we use RouteHeaderWapper to solve this problem.
options.RouteHeaders = YamlDeserializer.Deserialize<List<RouteHeaderWapper>>(routeHeaders).Select(p => p.ToRouteHeader()).ToList();
// YamlDeserializer does not support IReadOnlyList<string> in RouteHeader for now, so we use RouteHeaderWrapper to solve this problem.
options.RouteHeaders = YamlDeserializer.Deserialize<List<RouteHeaderWrapper>>(routeHeaders).Select(p => p.ToRouteHeader()).ToList();
}
if (annotations.TryGetValue("yarp.ingress.kubernetes.io/route-queryparameters", out var routeQueryParameters))
{
// YamlDeserializer does not support IReadOnlyList<string> in RouteParameters for now, so we use RouterQueryParameterWrapper to solve this problem.
options.RouteQueryParameters = YamlDeserializer.Deserialize<List<RouteQueryParameterWrapper>>(routeQueryParameters).Select(p => p.ToRouteQueryParameter()).ToList();
}
if (annotations.TryGetValue("yarp.ingress.kubernetes.io/route-order", out var routeOrder))
{
Expand Down
1 change: 1 addition & 0 deletions test/Kubernetes.Tests/IngressConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public IngressConversionTests()
[InlineData("multiple-ingresses-one-svc")]
[InlineData("multiple-namespaces")]
[InlineData("route-metadata")]
[InlineData("route-queryparameters")]
[InlineData("route-headers")]
[InlineData("route-order")]
[InlineData("missing-svc")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"ClusterId": "frontend.default:80",
"LoadBalancingPolicy": null,
"SessionAffinity": null,
"HealthCheck": null,
"HttpClient": null,
"HttpRequest": null,
"Destinations": {
"http://10.244.2.38:80": {
"Address": "http://10.244.2.38:80",
"Health": null,
"Metadata": null
}
},
"Metadata": null
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
namespace: default
annotations:
yarp.ingress.kubernetes.io/route-metadata: |
foo: bar
another-key: another-value
yarp.ingress.kubernetes.io/route-queryparameters: |
- Name: the-queryparameter-key
Values:
- the-queryparameter-value
Mode: Contains
IsCaseSensitive: false
spec:
rules:
- http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: default
spec:
selector:
app: frontend
ports:
- name: https
port: 80
targetPort: 80
type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
name: frontend
namespace: default
subsets:
- addresses:
- ip: 10.244.2.38
ports:
- name: https
port: 80
protocol: TCP
29 changes: 29 additions & 0 deletions test/Kubernetes.Tests/testassets/route-queryparameters/routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"RouteId": "minimal-ingress.default:/foo",
"Match": {
"Methods": null,
"Hosts": [],
"Path": "/foo/{**catch-all}",
"Headers": null,
"QueryParameters": [
{
"Name": "the-queryparameter-key",
"Values": [ "the-queryparameter-value" ],
"Mode": "Contains",
"IsCaseSensitive": false
}
]
},
"Order": null,
"ClusterId": "frontend.default:80",
"AuthorizationPolicy": null,
"RateLimiterPolicy": null,
"CorsPolicy": null,
"Metadata": {
"foo": "bar",
"another-key": "another-value"
},
"Transforms": null
}
]

0 comments on commit 1483fb7

Please sign in to comment.