mirror of
https://github.com/fluxcd/flagger.git
synced 2026-04-15 06:57:34 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0d9825afa | ||
|
|
7509264d73 | ||
|
|
f08725d661 | ||
|
|
f2a9a8d645 | ||
|
|
e799030ae3 | ||
|
|
ec0657f436 | ||
|
|
fce46e26d4 | ||
|
|
e015a409fe | ||
|
|
82ff90ce26 | ||
|
|
63edc627ad | ||
|
|
c2b4287ce1 | ||
|
|
5b61f15f95 | ||
|
|
9c815f2252 | ||
|
|
d16c9696c3 | ||
|
|
14ccda5506 | ||
|
|
a496b99d6e | ||
|
|
882286dce7 | ||
|
|
8aa9ca92e3 | ||
|
|
52dd8f8c14 | ||
|
|
4d28b9074b |
46
CHANGELOG.md
46
CHANGELOG.md
@@ -2,6 +2,52 @@
|
||||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## 1.26.0
|
||||
|
||||
**Release date:** 2022-11-23
|
||||
|
||||
This release comes with support Kubernetes [Gateway API](https://gateway-api.sigs.k8s.io/) v1beta1.
|
||||
For more details see the [Gateway API Progressive Delivery tutorial](https://docs.flagger.app/tutorials/gatewayapi-progressive-delivery).
|
||||
|
||||
Please note that starting with this version, the Gateway API v1alpha2 is considered deprecated
|
||||
and will be removed from Flagger after 6 months.
|
||||
|
||||
#### Improvements:
|
||||
|
||||
- Updated Gateway API from v1alpha2 to v1beta1
|
||||
[#1319](https://github.com/fluxcd/flagger/pull/1319)
|
||||
- Updated Gateway API docs to v1beta1
|
||||
[#1321](https://github.com/fluxcd/flagger/pull/1321)
|
||||
- Update dependencies
|
||||
[#1322](https://github.com/fluxcd/flagger/pull/1322)
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- docs: Add `linkerd install --crds` to Linkerd tutorial
|
||||
[#1316](https://github.com/fluxcd/flagger/pull/1316)
|
||||
|
||||
## 1.25.0
|
||||
|
||||
**Release date:** 2022-11-16
|
||||
|
||||
This release introduces a new deployment strategy combining Canary releases with session affinity
|
||||
for Istio.
|
||||
|
||||
Furthermore, it contains a regression fix regarding metadata in alerts introduced in
|
||||
[#1275](https://github.com/fluxcd/flagger/pull/1275)
|
||||
|
||||
#### Improvements:
|
||||
|
||||
- Add support for session affinity during weighted routing with Istio
|
||||
[#1280](https://github.com/fluxcd/flagger/pull/1280)
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fix cluster name inclusion in alerts metadata
|
||||
[#1306](https://github.com/fluxcd/flagger/pull/1306)
|
||||
- fix(faq): Update FAQ about zero downtime with correct values
|
||||
[#1302](https://github.com/fluxcd/flagger/pull/1302)
|
||||
|
||||
## 1.24.1
|
||||
|
||||
**Release date:** 2022-10-26
|
||||
|
||||
41
README.md
41
README.md
@@ -5,6 +5,7 @@
|
||||
[](https://goreportcard.com/report/github.com/fluxcd/flagger)
|
||||
[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Ffluxcd%2Fflagger?ref=badge_shield)
|
||||
[](https://artifacthub.io/packages/search?repo=flagger)
|
||||
[](https://clomonitor.io/projects/cncf/flagger)
|
||||
|
||||
Flagger is a progressive delivery tool that automates the release process for applications running on Kubernetes.
|
||||
It reduces the risk of introducing a new software version in production
|
||||
@@ -20,29 +21,29 @@ and part of the [Flux](https://fluxcd.io) family of GitOps tools.
|
||||
|
||||
### Documentation
|
||||
|
||||
Flagger documentation can be found at [docs.flagger.app](https://docs.flagger.app).
|
||||
Flagger documentation can be found at [fluxcd.io/flagger](https://fluxcd.io/flagger/).
|
||||
|
||||
* Install
|
||||
* [Flagger install on Kubernetes](https://docs.flagger.app/install/flagger-install-on-kubernetes)
|
||||
* [Flagger install on Kubernetes](https://fluxcd.io/flagger/install/flagger-install-on-kubernetes)
|
||||
* Usage
|
||||
* [How it works](https://docs.flagger.app/usage/how-it-works)
|
||||
* [Deployment strategies](https://docs.flagger.app/usage/deployment-strategies)
|
||||
* [Metrics analysis](https://docs.flagger.app/usage/metrics)
|
||||
* [Webhooks](https://docs.flagger.app/usage/webhooks)
|
||||
* [Alerting](https://docs.flagger.app/usage/alerting)
|
||||
* [Monitoring](https://docs.flagger.app/usage/monitoring)
|
||||
* [How it works](https://fluxcd.io/flagger/usage/how-it-works)
|
||||
* [Deployment strategies](https://fluxcd.io/flagger/usage/deployment-strategies)
|
||||
* [Metrics analysis](https://fluxcd.io/flagger/usage/metrics)
|
||||
* [Webhooks](https://fluxcd.io/flagger/usage/webhooks)
|
||||
* [Alerting](https://fluxcd.io/flagger/usage/alerting)
|
||||
* [Monitoring](https://fluxcd.io/flagger/usage/monitoring)
|
||||
* Tutorials
|
||||
* [App Mesh](https://docs.flagger.app/tutorials/appmesh-progressive-delivery)
|
||||
* [Istio](https://docs.flagger.app/tutorials/istio-progressive-delivery)
|
||||
* [Linkerd](https://docs.flagger.app/tutorials/linkerd-progressive-delivery)
|
||||
* [Open Service Mesh (OSM)](https://docs.flagger.app/tutorials/osm-progressive-delivery)
|
||||
* [Kuma Service Mesh](https://docs.flagger.app/tutorials/kuma-progressive-delivery)
|
||||
* [Contour](https://docs.flagger.app/tutorials/contour-progressive-delivery)
|
||||
* [Gloo](https://docs.flagger.app/tutorials/gloo-progressive-delivery)
|
||||
* [NGINX Ingress](https://docs.flagger.app/tutorials/nginx-progressive-delivery)
|
||||
* [Skipper](https://docs.flagger.app/tutorials/skipper-progressive-delivery)
|
||||
* [Traefik](https://docs.flagger.app/tutorials/traefik-progressive-delivery)
|
||||
* [Kubernetes Blue/Green](https://docs.flagger.app/tutorials/kubernetes-blue-green)
|
||||
* [App Mesh](https://fluxcd.io/flagger/tutorials/appmesh-progressive-delivery)
|
||||
* [Istio](https://fluxcd.io/flagger/tutorials/istio-progressive-delivery)
|
||||
* [Linkerd](https://fluxcd.io/flagger/tutorials/linkerd-progressive-delivery)
|
||||
* [Open Service Mesh (OSM)](https://dfluxcd.io/flagger/tutorials/osm-progressive-delivery)
|
||||
* [Kuma Service Mesh](https://fluxcd.io/flagger/tutorials/kuma-progressive-delivery)
|
||||
* [Contour](https://fluxcd.io/flagger/tutorials/contour-progressive-delivery)
|
||||
* [Gloo](https://fluxcd.io/flagger/tutorials/gloo-progressive-delivery)
|
||||
* [NGINX Ingress](https://fluxcd.io/flagger/tutorials/nginx-progressive-delivery)
|
||||
* [Skipper](https://fluxcd.io/flagger/tutorials/skipper-progressive-delivery)
|
||||
* [Traefik](https://fluxcd.io/flagger/tutorials/traefik-progressive-delivery)
|
||||
* [Kubernetes Blue/Green](https://fluxcd.io/flagger/tutorials/kubernetes-blue-green)
|
||||
|
||||
### Adopters
|
||||
|
||||
@@ -176,7 +177,7 @@ spec:
|
||||
name: on-call-msteams
|
||||
```
|
||||
|
||||
For more details on how the canary analysis and promotion works please [read the docs](https://docs.flagger.app/usage/how-it-works).
|
||||
For more details on how the canary analysis and promotion works please [read the docs](https://fluxcd.io/flagger/usage/how-it-works).
|
||||
|
||||
### Features
|
||||
|
||||
|
||||
@@ -1020,6 +1020,18 @@ spec:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
sessionAffinity:
|
||||
description: SessionAffinity represents the session affinity settings for a canary run.
|
||||
type: object
|
||||
required: [ "cookieName" ]
|
||||
properties:
|
||||
cookieName:
|
||||
description: CookieName is the key that will be used for the session affinity cookie.
|
||||
type: string
|
||||
maxAge:
|
||||
description: MaxAge indicates the number of seconds until the session affinity cookie will expire.
|
||||
default: 86400
|
||||
type: number
|
||||
status:
|
||||
description: CanaryStatus defines the observed state of a canary.
|
||||
type: object
|
||||
@@ -1064,6 +1076,12 @@ spec:
|
||||
description: LastTransitionTime of this canary
|
||||
format: date-time
|
||||
type: string
|
||||
sessionAffinityCookie:
|
||||
description: Session affinity cookie of the current canary run
|
||||
type: string
|
||||
previousSessionAffinityCookie:
|
||||
description: Session affinity cookie of the previous canary run
|
||||
type: string
|
||||
conditions:
|
||||
description: Status conditions of this canary
|
||||
type: array
|
||||
|
||||
@@ -22,7 +22,7 @@ spec:
|
||||
serviceAccountName: flagger
|
||||
containers:
|
||||
- name: flagger
|
||||
image: ghcr.io/fluxcd/flagger:1.24.1
|
||||
image: ghcr.io/fluxcd/flagger:1.26.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v1
|
||||
name: flagger
|
||||
version: 1.24.1
|
||||
appVersion: 1.24.1
|
||||
version: 1.26.0
|
||||
appVersion: 1.26.0
|
||||
kubeVersion: ">=1.19.0-0"
|
||||
engine: gotpl
|
||||
description: Flagger is a progressive delivery operator for Kubernetes
|
||||
|
||||
@@ -1020,6 +1020,18 @@ spec:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
sessionAffinity:
|
||||
description: SessionAffinity represents the session affinity settings for a canary run.
|
||||
type: object
|
||||
required: [ "cookieName" ]
|
||||
properties:
|
||||
cookieName:
|
||||
description: CookieName is the key that will be used for the session affinity cookie.
|
||||
type: string
|
||||
maxAge:
|
||||
description: MaxAge indicates the number of seconds until the session affinity cookie will expire.
|
||||
default: 86400
|
||||
type: number
|
||||
status:
|
||||
description: CanaryStatus defines the observed state of a canary.
|
||||
type: object
|
||||
@@ -1064,6 +1076,12 @@ spec:
|
||||
description: LastTransitionTime of this canary
|
||||
format: date-time
|
||||
type: string
|
||||
sessionAffinityCookie:
|
||||
description: Session affinity cookie of the current canary run
|
||||
type: string
|
||||
previousSessionAffinityCookie:
|
||||
description: Session affinity cookie of the previous canary run
|
||||
type: string
|
||||
conditions:
|
||||
description: Status conditions of this canary
|
||||
type: array
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
image:
|
||||
repository: ghcr.io/fluxcd/flagger
|
||||
tag: 1.24.1
|
||||
tag: 1.26.0
|
||||
pullPolicy: IfNotPresent
|
||||
pullSecret:
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v1
|
||||
name: loadtester
|
||||
version: 0.26.0
|
||||
appVersion: 0.26.0
|
||||
version: 0.27.0
|
||||
appVersion: 0.27.0
|
||||
kubeVersion: ">=1.19.0-0"
|
||||
engine: gotpl
|
||||
description: Flagger's load testing services based on rakyll/hey and bojand/ghz that generates traffic during canary analysis when configured as a webhook.
|
||||
|
||||
@@ -2,7 +2,7 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/fluxcd/flagger-loadtester
|
||||
tag: 0.26.0
|
||||
tag: 0.27.0
|
||||
pullPolicy: IfNotPresent
|
||||
pullSecret:
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var VERSION = "0.26.0"
|
||||
var VERSION = "0.27.0"
|
||||
var (
|
||||
logLevel string
|
||||
port string
|
||||
|
||||
@@ -69,8 +69,8 @@ spec:
|
||||
#### Why is there a window of downtime during the canary initializing process when analysis is disabled?
|
||||
|
||||
A window of downtime is the intended behavior when the analysis is disabled. This allows instant rollback and also mimics the way
|
||||
a Kubernetes deployment initialization works. To avoid this, enable the analysis (`skipAnalysis: true`), wait for the initialization
|
||||
to finish, and disable it afterward (`skipAnalysis: false`).
|
||||
a Kubernetes deployment initialization works. To avoid this, enable the analysis (`skipAnalysis: false`), wait for the initialization
|
||||
to finish, and disable it afterward (`skipAnalysis: true`).
|
||||
|
||||
#### How to disable cross namespace references?
|
||||
|
||||
|
||||
@@ -6,18 +6,19 @@ This guide shows you how to use [Gateway API](https://gateway-api.sigs.k8s.io/)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Flagger requires a Kubernetes cluster **v1.16** or newer and any mesh/ingress that implements the `v1alpha2` of Gateway API. We'll be using Contour for the sake of this tutorial, but you can use any other implementation.
|
||||
Flagger requires a Kubernetes cluster **v1.19** or newer and any mesh/ingress that implements the `v1beta1` version of Gateway API. We'll be using Contour for the sake of this tutorial, but you can use any other implementation.
|
||||
|
||||
Install the GatewayAPI CRDs:
|
||||
> Note: Flagger supports `v1alpha2` version of Gateway API, but the alpha version has been deprecated and support will be dropped in a future release.
|
||||
|
||||
Install Contour, its Gateway provisioner and Gateway API CRDs in the `projectcontour` namespace:
|
||||
|
||||
```bash
|
||||
kubectl apply -k github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.4.1
|
||||
https://raw.githubusercontent.com/projectcontour/contour/release-1.23/examples/render/contour-gateway-provisioner.yaml
|
||||
```
|
||||
|
||||
Install a cluster-wide GatewayClass; a Gateway belonging to the GatewayClass and Contour components in the `projectcontour` namespace:
|
||||
|
||||
> Alternatively, you can also install the Gateway API CRDs from the upstream project:
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/projectcontour/contour/release-1.20/examples/render/contour-gateway.yaml
|
||||
kubectl apply -k github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.6.0
|
||||
```
|
||||
|
||||
Install Flagger in the `flagger-system` namespace:
|
||||
@@ -26,6 +27,36 @@ Install Flagger in the `flagger-system` namespace:
|
||||
kubectl apply -k github.com/fluxcd/flagger//kustomize/gatewayapi
|
||||
```
|
||||
|
||||
Create a `GatewayClass` that specifies information about the Gateway controller:
|
||||
|
||||
```yaml
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: contour
|
||||
spec:
|
||||
controllerName: projectcontour.io/gateway-controller
|
||||
```
|
||||
|
||||
Create a `Gateway` that configures load balancing, traffic ACL, etc:
|
||||
|
||||
```yaml
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: contour
|
||||
namespace: projectcontour
|
||||
spec:
|
||||
gatewayClassName: contour
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: All
|
||||
```
|
||||
|
||||
## Bootstrap
|
||||
|
||||
Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler \(HPA\), then creates a series of objects \(Kubernetes deployments, ClusterIP services, HTTPRoutes for the Gateway\). These objects expose the application inside the mesh and drive the canary analysis and promotion.
|
||||
|
||||
@@ -292,6 +292,118 @@ Events:
|
||||
Warning Synced 1m flagger Canary failed! Scaling down podinfo.test
|
||||
```
|
||||
|
||||
## Session Affinity
|
||||
|
||||
While Flagger can perform weighted routing and A/B testing individually, with Istio it can combine the two leading to a Canary
|
||||
release with session affinity. For more information you can read the [deployment strategies docs](../usage/deployment-strategies.md#canary-release-with-session-affinity).
|
||||
|
||||
Create a canary custom resource \(replace app.example.com with your own domain\):
|
||||
|
||||
```yaml
|
||||
apiVersion: flagger.app/v1beta1
|
||||
kind: Canary
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: test
|
||||
spec:
|
||||
# deployment reference
|
||||
targetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: podinfo
|
||||
# the maximum time in seconds for the canary deployment
|
||||
# to make progress before it is rollback (default 600s)
|
||||
progressDeadlineSeconds: 60
|
||||
# HPA reference (optional)
|
||||
autoscalerRef:
|
||||
apiVersion: autoscaling/v2beta2
|
||||
kind: HorizontalPodAutoscaler
|
||||
name: podinfo
|
||||
service:
|
||||
# service port number
|
||||
port: 9898
|
||||
# container port number or name (optional)
|
||||
targetPort: 9898
|
||||
# Istio gateways (optional)
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
# Istio virtual service host names (optional)
|
||||
hosts:
|
||||
- app.example.com
|
||||
# Istio traffic policy (optional)
|
||||
trafficPolicy:
|
||||
tls:
|
||||
# use ISTIO_MUTUAL when mTLS is enabled
|
||||
mode: DISABLE
|
||||
# Istio retry policy (optional)
|
||||
retries:
|
||||
attempts: 3
|
||||
perTryTimeout: 1s
|
||||
retryOn: "gateway-error,connect-failure,refused-stream"
|
||||
analysis:
|
||||
# schedule interval (default 60s)
|
||||
interval: 1m
|
||||
# max number of failed metric checks before rollback
|
||||
threshold: 5
|
||||
# max traffic percentage routed to canary
|
||||
# percentage (0-100)
|
||||
maxWeight: 50
|
||||
# canary increment step
|
||||
# percentage (0-100)
|
||||
stepWeight: 10
|
||||
# session affinity config
|
||||
sessionAffinity:
|
||||
# name of the cookie used
|
||||
cookieName: flagger-cookie
|
||||
# max age of the cookie (in seconds)
|
||||
# optional; defaults to 86400
|
||||
maxAge: 21600
|
||||
metrics:
|
||||
- name: request-success-rate
|
||||
# minimum req success rate (non 5xx responses)
|
||||
# percentage (0-100)
|
||||
thresholdRange:
|
||||
min: 99
|
||||
interval: 1m
|
||||
- name: request-duration
|
||||
# maximum req duration P99
|
||||
# milliseconds
|
||||
thresholdRange:
|
||||
max: 500
|
||||
interval: 30s
|
||||
# testing (optional)
|
||||
webhooks:
|
||||
- name: acceptance-test
|
||||
type: pre-rollout
|
||||
url: http://flagger-loadtester.test/
|
||||
timeout: 30s
|
||||
metadata:
|
||||
type: bash
|
||||
cmd: "curl -sd 'test' http://podinfo-canary:9898/token | grep token"
|
||||
- name: load-test
|
||||
url: http://flagger-loadtester.test/
|
||||
timeout: 5s
|
||||
metadata:
|
||||
cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"
|
||||
```
|
||||
|
||||
Save the above resource as podinfo-canary-session-affinity.yaml and then apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f ./podinfo-canary-session-affinity.yaml
|
||||
```
|
||||
|
||||
Trigger a canary deployment by updating the container image:
|
||||
|
||||
```bash
|
||||
kubectl -n test set image deployment/podinfo \
|
||||
podinfod=ghcr.io/stefanprodan/podinfo:6.0.1
|
||||
```
|
||||
|
||||
You can load `app.example.com` in your browser and refresh it until you see the requests being served by `podinfo:6.0.1`.
|
||||
All subsequent requests after that will be served by `podinfo:6.0.1` and not `podinfo:6.0.0` because of the session affinity
|
||||
configured by Flagger with Istio.
|
||||
|
||||
## Traffic mirroring
|
||||
|
||||

|
||||
|
||||
@@ -11,6 +11,7 @@ Flagger requires a Kubernetes cluster **v1.16** or newer and Linkerd **2.10** or
|
||||
Install Linkerd the Promethues (part of Linkerd Viz):
|
||||
|
||||
```bash
|
||||
linkerd install --crds | kubectl apply -f -
|
||||
linkerd install | kubectl apply -f -
|
||||
linkerd viz install | kubectl apply -f -
|
||||
```
|
||||
|
||||
@@ -10,6 +10,8 @@ Flagger can run automated application analysis, promotion and rollback for the f
|
||||
* Kubernetes CNI, Istio, Linkerd, App Mesh, NGINX, Contour, Gloo Edge, Open Service Mesh, Gateway API
|
||||
* **Blue/Green Mirroring** \(traffic shadowing\)
|
||||
* Istio
|
||||
* **Canary Release with Session Affinity** \(progressive traffic shifting combined with cookie based routing\)
|
||||
* Istio
|
||||
|
||||
For Canary releases and A/B testing you'll need a Layer 7 traffic management solution like
|
||||
a service mesh or an ingress controller. For Blue/Green deployments no service mesh or ingress controller is required.
|
||||
@@ -393,3 +395,59 @@ After the analysis finishes, the traffic is routed to the canary (green) before
|
||||
triggering the primary (blue) rolling update, this ensures a smooth transition
|
||||
to the new version avoiding dropping in-flight requests during the Kubernetes deployment rollout.
|
||||
|
||||
## Canary Release with Session Affinity
|
||||
|
||||
This deployment strategy mixes a Canary Release with A/B testing. A Canary Release is helpful when
|
||||
we're trying to expose new features to users progressively, but because of the very nature of its
|
||||
routing (weight based), users can land on the application's old version even after they have been
|
||||
routed to the new version previously. This can be annoying, or worse break how other services interact
|
||||
with our application. To address this issue, we borrow some things from A/B testing.
|
||||
|
||||
Since A/B testing is particularly helpful for applications that require session affinity, we integrate
|
||||
cookie based routing with regular weight based routing. This means once a user is exposed to the new
|
||||
version of our application (based on the traffic weights), they're always routed to that version, i.e.
|
||||
they're never routed back to the old version of our application.
|
||||
|
||||
You can enable this, by specifying `.spec.analsyis.sessionAffinity` in the Canary (only Istio is supported):
|
||||
|
||||
```yaml
|
||||
analysis:
|
||||
# schedule interval (default 60s)
|
||||
interval: 1m
|
||||
# max number of failed metric checks before rollback
|
||||
threshold: 10
|
||||
# max traffic percentage routed to canary
|
||||
# percentage (0-100)
|
||||
maxWeight: 50
|
||||
# canary increment step
|
||||
# percentage (0-100)
|
||||
stepWeight: 2
|
||||
# session affinity config
|
||||
sessionAffinity:
|
||||
# name of the cookie used
|
||||
cookieName: flagger-cookie
|
||||
# max age of the cookie (in seconds)
|
||||
# optional; defaults to 86400
|
||||
maxAge: 21600
|
||||
```
|
||||
|
||||
`.spec.analysis.sessionAffinity.cookieName` is the name of the Cookie that is stored. The value of the
|
||||
cookie is a randomly generated string of characters that act as a unique identifier. For the above
|
||||
config, the response header of a request routed to the canary deployment during a Canary run will look like:
|
||||
```
|
||||
Set-Cookie: flagger-cookie=LpsIaLdoNZ; Max-Age=21600
|
||||
```
|
||||
|
||||
After a Canary run is over and all traffic is shifted back to the primary deployment, all responses will
|
||||
have the following header:
|
||||
```
|
||||
Set-Cookie: flagger-cookie=LpsIaLdoNZ; Max-Age=-1
|
||||
```
|
||||
This tells the client to delete the cookie, making sure there are no junk cookies lying around in the user's
|
||||
system.
|
||||
|
||||
If a new Canary run is triggered, the response header will set a new cookie for all requests routed to
|
||||
the Canary deployment:
|
||||
```
|
||||
Set-Cookie: flagger-cookie=McxKdLQoIN; Max-Age=21600
|
||||
```
|
||||
|
||||
39
go.mod
39
go.mod
@@ -3,26 +3,26 @@ module github.com/fluxcd/flagger
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go/monitoring v1.6.0
|
||||
cloud.google.com/go/monitoring v1.9.0
|
||||
github.com/Masterminds/semver/v3 v3.1.1
|
||||
github.com/aws/aws-sdk-go v1.44.119
|
||||
github.com/aws/aws-sdk-go v1.44.144
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/go-logr/zapr v1.2.3
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/googleapis/gax-go/v2 v2.6.0
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.11.0
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/googleapis/gax-go/v2 v2.7.0
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
go.uber.org/zap v1.23.0
|
||||
google.golang.org/api v0.100.0
|
||||
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55
|
||||
google.golang.org/grpc v1.50.1
|
||||
google.golang.org/api v0.103.0
|
||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/h2non/gock.v1 v1.1.2
|
||||
k8s.io/api v0.25.3
|
||||
k8s.io/apimachinery v0.25.3
|
||||
k8s.io/client-go v0.25.3
|
||||
k8s.io/code-generator v0.25.3
|
||||
k8s.io/api v0.25.4
|
||||
k8s.io/apimachinery v0.25.4
|
||||
k8s.io/client-go v0.25.4
|
||||
k8s.io/code-generator v0.25.4
|
||||
k8s.io/klog/v2 v2.80.1
|
||||
)
|
||||
|
||||
@@ -30,7 +30,8 @@ require (
|
||||
replace golang.org/x/text => golang.org/x/text v0.4.0
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.10.0 // indirect
|
||||
cloud.google.com/go/compute v1.12.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
@@ -62,18 +63,18 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/term v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
|
||||
78
go.sum
78
go.sum
@@ -13,18 +13,22 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4=
|
||||
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
|
||||
cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
|
||||
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||
cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/monitoring v1.6.0 h1:+x5AA2mFkiHK/ySN6NWKbeKBV+Z/DN+h51kBzcW08zU=
|
||||
cloud.google.com/go/monitoring v1.6.0/go.mod h1:w+OY1TYCk4MtvY7WfEHlIp5mP8SV/gDSqOsvGhVa2KM=
|
||||
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
|
||||
cloud.google.com/go/monitoring v1.9.0 h1:O2A5HsrhvRMzD3OMUimPXF46vOzwc9vh6oGCGf9i/ws=
|
||||
cloud.google.com/go/monitoring v1.9.0/go.mod h1:/FsTS0gkEFUc4cgB16s6jYDnyjzRBkRJNRzBn5Zx+wA=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
@@ -48,8 +52,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/aws/aws-sdk-go v1.44.119 h1:TPkpDsanBMcZaF5wHwpKhjkapRV/b7d2qdC+a+IPbmY=
|
||||
github.com/aws/aws-sdk-go v1.44.119/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.144 h1:mMWdnYL8HZsobrQe1mwvQ18Xt8UbOVhWgipjuma5Mkg=
|
||||
github.com/aws/aws-sdk-go v1.44.144/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -183,8 +187,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbez
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
@@ -193,8 +197,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.11.0 h1:BrHYv38rWkAnp22gIaHFp5LpOCazOqRMRvVE1yW3ym8=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.11.0/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.0 h1:LGct9uIp36IT+8RAJdmJGQbNonGi26YfYYSpDIyq8fI=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.0/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU=
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
@@ -267,13 +271,14 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
@@ -298,6 +303,7 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -305,8 +311,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
@@ -320,8 +327,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
@@ -409,8 +416,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -477,12 +484,13 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -557,8 +565,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.100.0 h1:LGUYIrbW9pzYQQ8NWXlaIVkgnfubVBZbMFb9P8TK374=
|
||||
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
|
||||
google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
|
||||
google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -597,8 +605,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg=
|
||||
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck=
|
||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c=
|
||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -612,8 +620,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -659,14 +667,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.25.3 h1:Q1v5UFfYe87vi5H7NU0p4RXC26PPMT8KOpr1TLQbCMQ=
|
||||
k8s.io/api v0.25.3/go.mod h1:o42gKscFrEVjHdQnyRenACrMtbuJsVdP+WVjqejfzmI=
|
||||
k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc=
|
||||
k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
|
||||
k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0=
|
||||
k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA=
|
||||
k8s.io/code-generator v0.25.3 h1:BEH+wDi90bGyrYcY4abGtUqaOX7G94RRrEu8l+SvIeo=
|
||||
k8s.io/code-generator v0.25.3/go.mod h1:9F5fuVZOMWRme7MYj2YT3L9ropPWPokd9VRhVyD3+0w=
|
||||
k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
|
||||
k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
|
||||
k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
|
||||
k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
|
||||
k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8=
|
||||
k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
|
||||
k8s.io/code-generator v0.25.4 h1:tjQ7/+9eN7UOiU2DP+0v4ntTI4JZLi2c1N0WllpFhTc=
|
||||
k8s.io/code-generator v0.25.4/go.mod h1:9F5fuVZOMWRme7MYj2YT3L9ropPWPokd9VRhVyD3+0w=
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHzPMyB0t8BaFeBYI=
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
|
||||
@@ -30,7 +30,7 @@ chmod +x ${CODEGEN_PKG}/generate-groups.sh
|
||||
|
||||
${CODEGEN_PKG}/generate-groups.sh all \
|
||||
github.com/fluxcd/flagger/pkg/client github.com/fluxcd/flagger/pkg/apis \
|
||||
"flagger:v1beta1 appmesh:v1beta2 appmesh:v1beta1 istio:v1alpha3 smi:v1alpha1 smi:v1alpha2 smi:v1alpha3 gloo/gloo:v1 gloo/gateway:v1 projectcontour:v1 traefik:v1alpha1 kuma:v1alpha1 gatewayapi:v1alpha2 keda:v1alpha1" \
|
||||
"flagger:v1beta1 appmesh:v1beta2 appmesh:v1beta1 istio:v1alpha3 smi:v1alpha1 smi:v1alpha2 smi:v1alpha3 gloo/gloo:v1 gloo/gateway:v1 projectcontour:v1 traefik:v1alpha1 kuma:v1alpha1 gatewayapi:v1alpha2 gatewayapi:v1beta1 keda:v1alpha1" \
|
||||
--output-base "${TEMP_DIR}" \
|
||||
--go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt
|
||||
|
||||
|
||||
@@ -1020,6 +1020,18 @@ spec:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
sessionAffinity:
|
||||
description: SessionAffinity represents the session affinity settings for a canary run.
|
||||
type: object
|
||||
required: [ "cookieName" ]
|
||||
properties:
|
||||
cookieName:
|
||||
description: CookieName is the key that will be used for the session affinity cookie.
|
||||
type: string
|
||||
maxAge:
|
||||
description: MaxAge indicates the number of seconds until the session affinity cookie will expire.
|
||||
default: 86400
|
||||
type: number
|
||||
status:
|
||||
description: CanaryStatus defines the observed state of a canary.
|
||||
type: object
|
||||
@@ -1064,6 +1076,12 @@ spec:
|
||||
description: LastTransitionTime of this canary
|
||||
format: date-time
|
||||
type: string
|
||||
sessionAffinityCookie:
|
||||
description: Session affinity cookie of the current canary run
|
||||
type: string
|
||||
previousSessionAffinityCookie:
|
||||
description: Session affinity cookie of the previous canary run
|
||||
type: string
|
||||
conditions:
|
||||
description: Status conditions of this canary
|
||||
type: array
|
||||
|
||||
@@ -9,4 +9,4 @@ resources:
|
||||
images:
|
||||
- name: ghcr.io/fluxcd/flagger
|
||||
newName: ghcr.io/fluxcd/flagger
|
||||
newTag: 1.24.1
|
||||
newTag: 1.26.0
|
||||
|
||||
@@ -10,5 +10,5 @@ spec:
|
||||
args:
|
||||
- -log-level=info
|
||||
- -include-label-prefix=app.kubernetes.io
|
||||
- -mesh-provider=gatewayapi:v1alpha2
|
||||
- -mesh-provider=gatewayapi:v1beta1
|
||||
- -metrics-server=http://flagger-prometheus:9090
|
||||
|
||||
@@ -19,7 +19,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: loadtester
|
||||
image: ghcr.io/fluxcd/flagger-loadtester:0.26.0
|
||||
image: ghcr.io/fluxcd/flagger-loadtester:0.27.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
istiov1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
@@ -148,7 +148,7 @@ type CanaryService struct {
|
||||
// Gateways that the HTTPRoute needs to attach itself to.
|
||||
// Must be specified while using the Gateway API as a provider.
|
||||
// +optional
|
||||
GatewayRefs []v1alpha2.ParentReference `json:"gatewayRefs,omitempty"`
|
||||
GatewayRefs []v1beta1.ParentReference `json:"gatewayRefs,omitempty"`
|
||||
|
||||
// Hosts attached to the generated Istio virtual service or Gateway API HTTPRoute.
|
||||
// Defaults to the service name
|
||||
@@ -262,6 +262,20 @@ type CanaryAnalysis struct {
|
||||
// A/B testing HTTP header match conditions
|
||||
// +optional
|
||||
Match []istiov1alpha3.HTTPMatchRequest `json:"match,omitempty"`
|
||||
|
||||
// SessionAffinity represents the session affinity settings for a canary run.
|
||||
// +optional
|
||||
SessionAffinity *SessionAffinity `json:"sessionAffinity,omitempty"`
|
||||
}
|
||||
|
||||
type SessionAffinity struct {
|
||||
// CookieName is the key that will be used for the session affinity cookie.
|
||||
CookieName string `json:"cookieName,omitempty"`
|
||||
// MaxAge indicates the number of seconds until the session affinity cookie will expire.
|
||||
// ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
|
||||
// The default value is 86,400 seconds, i.e. a day.
|
||||
// +optional
|
||||
MaxAge int `json:"maxAge,omitempty"`
|
||||
}
|
||||
|
||||
// CanaryMetric holds the reference to metrics used for canary analysis
|
||||
@@ -437,6 +451,15 @@ type CustomMetadata struct {
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// GetMaxAge returns the max age of a cookie in seconds.
|
||||
func (s *SessionAffinity) GetMaxAge() int {
|
||||
if s.MaxAge == 0 {
|
||||
// 24 hours * 60 mins * 60 seconds
|
||||
return 86400
|
||||
}
|
||||
return s.MaxAge
|
||||
}
|
||||
|
||||
// GetServiceNames returns the apex, primary and canary Kubernetes service names
|
||||
func (c *Canary) GetServiceNames() (apexName, primaryName, canaryName string) {
|
||||
apexName = c.Spec.TargetRef.Name
|
||||
|
||||
@@ -74,6 +74,10 @@ type CanaryStatus struct {
|
||||
CanaryWeight int `json:"canaryWeight"`
|
||||
Iterations int `json:"iterations"`
|
||||
// +optional
|
||||
PreviousSessionAffinityCookie string `json:"previousSessionAffinityCookie,omitempty"`
|
||||
// +optional
|
||||
SessionAffinityCookie string `json:"sessionAffinityCookie,omitempty"`
|
||||
// +optional
|
||||
TrackedConfigs *map[string]string `json:"trackedConfigs,omitempty"`
|
||||
// +optional
|
||||
LastAppliedSpec string `json:"lastAppliedSpec,omitempty"`
|
||||
|
||||
@@ -22,7 +22,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1alpha2 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
v1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -263,6 +263,11 @@ func (in *CanaryAnalysis) DeepCopyInto(out *CanaryAnalysis) {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.SessionAffinity != nil {
|
||||
in, out := &in.SessionAffinity, &out.SessionAffinity
|
||||
*out = new(SessionAffinity)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -364,7 +369,7 @@ func (in *CanaryService) DeepCopyInto(out *CanaryService) {
|
||||
}
|
||||
if in.GatewayRefs != nil {
|
||||
in, out := &in.GatewayRefs, &out.GatewayRefs
|
||||
*out = make([]v1alpha2.ParentReference, len(*in))
|
||||
*out = make([]gatewayapiv1beta1.ParentReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
@@ -815,3 +820,19 @@ func (in *MetricTemplateStatus) DeepCopy() *MetricTemplateStatus {
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SessionAffinity) DeepCopyInto(out *SessionAffinity) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionAffinity.
|
||||
func (in *SessionAffinity) DeepCopy() *SessionAffinity {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SessionAffinity)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
4
pkg/apis/gatewayapi/v1beta1/doc.go
Normal file
4
pkg/apis/gatewayapi/v1beta1/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package v1alpha2 contains API Schema definitions for the
|
||||
// gateway.networking.k8s.io API group.
|
||||
|
||||
package v1beta1
|
||||
1021
pkg/apis/gatewayapi/v1beta1/httproute_types.go
Normal file
1021
pkg/apis/gatewayapi/v1beta1/httproute_types.go
Normal file
File diff suppressed because it is too large
Load Diff
130
pkg/apis/gatewayapi/v1beta1/object_reference_types.go
Normal file
130
pkg/apis/gatewayapi/v1beta1/object_reference_types.go
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
// LocalObjectReference identifies an API object within the namespace of the
|
||||
// referrer.
|
||||
// The API object must be valid in the cluster; the Group and Kind must
|
||||
// be registered in the cluster for this reference to be valid.
|
||||
//
|
||||
// References to objects with invalid Group and Kind are not valid, and must
|
||||
// be rejected by the implementation, with appropriate Conditions set
|
||||
// on the containing object.
|
||||
type LocalObjectReference struct {
|
||||
// Group is the group of the referent. For example, "gateway.networking.k8s.io".
|
||||
// When unspecified or empty string, core API group is inferred.
|
||||
Group Group `json:"group"`
|
||||
|
||||
// Kind is kind of the referent. For example "HTTPRoute" or "Service".
|
||||
Kind Kind `json:"kind"`
|
||||
|
||||
// Name is the name of the referent.
|
||||
Name ObjectName `json:"name"`
|
||||
}
|
||||
|
||||
// SecretObjectReference identifies an API object including its namespace,
|
||||
// defaulting to Secret.
|
||||
//
|
||||
// The API object must be valid in the cluster; the Group and Kind must
|
||||
// be registered in the cluster for this reference to be valid.
|
||||
//
|
||||
// References to objects with invalid Group and Kind are not valid, and must
|
||||
// be rejected by the implementation, with appropriate Conditions set
|
||||
// on the containing object.
|
||||
type SecretObjectReference struct {
|
||||
// Group is the group of the referent. For example, "gateway.networking.k8s.io".
|
||||
// When unspecified or empty string, core API group is inferred.
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:default=""
|
||||
Group *Group `json:"group"`
|
||||
|
||||
// Kind is kind of the referent. For example "HTTPRoute" or "Service".
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:default=Secret
|
||||
Kind *Kind `json:"kind"`
|
||||
|
||||
// Name is the name of the referent.
|
||||
Name ObjectName `json:"name"`
|
||||
|
||||
// Namespace is the namespace of the backend. When unspecified, the local
|
||||
// namespace is inferred.
|
||||
//
|
||||
// Note that when a namespace is specified, a ReferenceGrant object
|
||||
// is required in the referent namespace to allow that namespace's
|
||||
// owner to accept the reference. See the ReferenceGrant documentation
|
||||
// for details.
|
||||
//
|
||||
// Support: Core
|
||||
//
|
||||
// +optional
|
||||
Namespace *Namespace `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// BackendObjectReference defines how an ObjectReference that is
|
||||
// specific to BackendRef. It includes a few additional fields and features
|
||||
// than a regular ObjectReference.
|
||||
//
|
||||
// Note that when a namespace is specified, a ReferenceGrant object
|
||||
// is required in the referent namespace to allow that namespace's
|
||||
// owner to accept the reference. See the ReferenceGrant documentation
|
||||
// for details.
|
||||
//
|
||||
// The API object must be valid in the cluster; the Group and Kind must
|
||||
// be registered in the cluster for this reference to be valid.
|
||||
//
|
||||
// References to objects with invalid Group and Kind are not valid, and must
|
||||
// be rejected by the implementation, with appropriate Conditions set
|
||||
// on the containing object.
|
||||
type BackendObjectReference struct {
|
||||
// Group is the group of the referent. For example, "gateway.networking.k8s.io".
|
||||
// When unspecified or empty string, core API group is inferred.
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:default=""
|
||||
Group *Group `json:"group,omitempty"`
|
||||
|
||||
// Kind is kind of the referent. For example "HTTPRoute" or "Service".
|
||||
// Defaults to "Service" when not specified.
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:default=Service
|
||||
Kind *Kind `json:"kind,omitempty"`
|
||||
|
||||
// Name is the name of the referent.
|
||||
Name ObjectName `json:"name"`
|
||||
|
||||
// Namespace is the namespace of the backend. When unspecified, the local
|
||||
// namespace is inferred.
|
||||
//
|
||||
// Note that when a namespace is specified, a ReferenceGrant object
|
||||
// is required in the referent namespace to allow that namespace's
|
||||
// owner to accept the reference. See the ReferenceGrant documentation
|
||||
// for details.
|
||||
//
|
||||
// Support: Core
|
||||
//
|
||||
// +optional
|
||||
Namespace *Namespace `json:"namespace,omitempty"`
|
||||
|
||||
// Port specifies the destination port number to use for this resource.
|
||||
// Port is required when the referent is a Kubernetes Service. In this
|
||||
// case, the port number is the service port number, not the target port.
|
||||
// For other resources, destination port might be derived from the referent
|
||||
// resource or this field.
|
||||
//
|
||||
// +optional
|
||||
Port *PortNumber `json:"port,omitempty"`
|
||||
}
|
||||
39
pkg/apis/gatewayapi/v1beta1/register.go
Normal file
39
pkg/apis/gatewayapi/v1beta1/register.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is the identifier for the API which includes
|
||||
// the name of the group and the version of the API
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: gatewayapi.GroupName, Version: "v1beta1"}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
// SchemeBuilder collects functions that add things to a scheme. It's to allow
|
||||
// code to compile without explicitly referencing generated types. You should
|
||||
// declare one in each package that will have generated deep copy or conversion
|
||||
// functions.
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
|
||||
// AddToScheme applies all the stored functions to the scheme. A non-nil error
|
||||
// indicates that one function failed and the attempt was abandoned.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&HTTPRoute{},
|
||||
&HTTPRouteList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
563
pkg/apis/gatewayapi/v1beta1/shared_types.go
Normal file
563
pkg/apis/gatewayapi/v1beta1/shared_types.go
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ParentReference identifies an API object (usually a Gateway) that can be considered
|
||||
// a parent of this resource (usually a route). The only kind of parent resource
|
||||
// with "Core" support is Gateway. This API may be extended in the future to
|
||||
// support additional kinds of parent resources, such as HTTPRoute.
|
||||
//
|
||||
// The API object must be valid in the cluster; the Group and Kind must
|
||||
// be registered in the cluster for this reference to be valid.
|
||||
type ParentReference struct {
|
||||
// Group is the group of the referent.
|
||||
// When unspecified, "gateway.networking.k8s.io" is inferred.
|
||||
// To set the core API group (such as for a "Service" kind referent),
|
||||
// Group must be explicitly set to "" (empty string).
|
||||
//
|
||||
// Support: Core
|
||||
//
|
||||
// +kubebuilder:default=gateway.networking.k8s.io
|
||||
// +optional
|
||||
Group *Group `json:"group,omitempty"`
|
||||
|
||||
// Kind is kind of the referent.
|
||||
//
|
||||
// Support: Core (Gateway)
|
||||
//
|
||||
// Support: Implementation-specific (Other Resources)
|
||||
//
|
||||
// +kubebuilder:default=Gateway
|
||||
// +optional
|
||||
Kind *Kind `json:"kind,omitempty"`
|
||||
|
||||
// Namespace is the namespace of the referent. When unspecified, this refers
|
||||
// to the local namespace of the Route.
|
||||
//
|
||||
// Support: Core
|
||||
//
|
||||
// +optional
|
||||
Namespace *Namespace `json:"namespace,omitempty"`
|
||||
|
||||
// Name is the name of the referent.
|
||||
//
|
||||
// Support: Core
|
||||
Name ObjectName `json:"name"`
|
||||
|
||||
// SectionName is the name of a section within the target resource. In the
|
||||
// following resources, SectionName is interpreted as the following:
|
||||
//
|
||||
// * Gateway: Listener Name. When both Port (experimental) and SectionName
|
||||
// are specified, the name and port of the selected listener must match
|
||||
// both specified values.
|
||||
//
|
||||
// Implementations MAY choose to support attaching Routes to other resources.
|
||||
// If that is the case, they MUST clearly document how SectionName is
|
||||
// interpreted.
|
||||
//
|
||||
// When unspecified (empty string), this will reference the entire resource.
|
||||
// For the purpose of status, an attachment is considered successful if at
|
||||
// least one section in the parent resource accepts it. For example, Gateway
|
||||
// listeners can restrict which Routes can attach to them by Route kind,
|
||||
// namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from
|
||||
// the referencing Route, the Route MUST be considered successfully
|
||||
// attached. If no Gateway listeners accept attachment from this Route, the
|
||||
// Route MUST be considered detached from the Gateway.
|
||||
//
|
||||
// Support: Core
|
||||
//
|
||||
// +optional
|
||||
SectionName *SectionName `json:"sectionName,omitempty"`
|
||||
|
||||
// Port is the network port this Route targets. It can be interpreted
|
||||
// differently based on the type of parent resource.
|
||||
//
|
||||
// When the parent resource is a Gateway, this targets all listeners
|
||||
// listening on the specified port that also support this kind of Route(and
|
||||
// select this Route). It's not recommended to set `Port` unless the
|
||||
// networking behaviors specified in a Route must apply to a specific port
|
||||
// as opposed to a listener(s) whose port(s) may be changed. When both Port
|
||||
// and SectionName are specified, the name and port of the selected listener
|
||||
// must match both specified values.
|
||||
//
|
||||
// Implementations MAY choose to support other parent resources.
|
||||
// Implementations supporting other types of parent resources MUST clearly
|
||||
// document how/if Port is interpreted.
|
||||
//
|
||||
// For the purpose of status, an attachment is considered successful as
|
||||
// long as the parent resource accepts it partially. For example, Gateway
|
||||
// listeners can restrict which Routes can attach to them by Route kind,
|
||||
// namespace, or hostname. If 1 of 2 Gateway listeners accept attachment
|
||||
// from the referencing Route, the Route MUST be considered successfully
|
||||
// attached. If no Gateway listeners accept attachment from this Route,
|
||||
// the Route MUST be considered detached from the Gateway.
|
||||
//
|
||||
// Support: Extended
|
||||
//
|
||||
// +optional
|
||||
// <gateway:experimental>
|
||||
Port *PortNumber `json:"port,omitempty"`
|
||||
}
|
||||
|
||||
// CommonRouteSpec defines the common attributes that all Routes MUST include
|
||||
// within their spec.
|
||||
type CommonRouteSpec struct {
|
||||
// ParentRefs references the resources (usually Gateways) that a Route wants
|
||||
// to be attached to. Note that the referenced parent resource needs to
|
||||
// allow this for the attachment to be complete. For Gateways, that means
|
||||
// the Gateway needs to allow attachment from Routes of this kind and
|
||||
// namespace.
|
||||
//
|
||||
// The only kind of parent resource with "Core" support is Gateway. This API
|
||||
// may be extended in the future to support additional kinds of parent
|
||||
// resources such as one of the route kinds.
|
||||
//
|
||||
// It is invalid to reference an identical parent more than once. It is
|
||||
// valid to reference multiple distinct sections within the same parent
|
||||
// resource, such as 2 Listeners within a Gateway.
|
||||
//
|
||||
// It is possible to separately reference multiple distinct objects that may
|
||||
// be collapsed by an implementation. For example, some implementations may
|
||||
// choose to merge compatible Gateway Listeners together. If that is the
|
||||
// case, the list of routes attached to those resources should also be
|
||||
// merged.
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:validation:MaxItems=32
|
||||
ParentRefs []ParentReference `json:"parentRefs,omitempty"`
|
||||
}
|
||||
|
||||
// PortNumber defines a network port.
|
||||
//
|
||||
// +kubebuilder:validation:Minimum=1
|
||||
// +kubebuilder:validation:Maximum=65535
|
||||
type PortNumber int32
|
||||
|
||||
// BackendRef defines how a Route should forward a request to a Kubernetes
|
||||
// resource.
|
||||
//
|
||||
// Note that when a namespace is specified, a ReferenceGrant object
|
||||
// is required in the referent namespace to allow that namespace's
|
||||
// owner to accept the reference. See the ReferenceGrant documentation
|
||||
// for details.
|
||||
type BackendRef struct {
|
||||
// BackendObjectReference references a Kubernetes object.
|
||||
BackendObjectReference `json:",inline"`
|
||||
|
||||
// Weight specifies the proportion of requests forwarded to the referenced
|
||||
// backend. This is computed as weight/(sum of all weights in this
|
||||
// BackendRefs list). For non-zero values, there may be some epsilon from
|
||||
// the exact proportion defined here depending on the precision an
|
||||
// implementation supports. Weight is not a percentage and the sum of
|
||||
// weights does not need to equal 100.
|
||||
//
|
||||
// If only one backend is specified and it has a weight greater than 0, 100%
|
||||
// of the traffic is forwarded to that backend. If weight is set to 0, no
|
||||
// traffic should be forwarded for this entry. If unspecified, weight
|
||||
// defaults to 1.
|
||||
//
|
||||
// Support for this field varies based on the context where used.
|
||||
//
|
||||
// +optional
|
||||
// +kubebuilder:default=1
|
||||
// +kubebuilder:validation:Minimum=0
|
||||
// +kubebuilder:validation:Maximum=1000000
|
||||
Weight *int32 `json:"weight,omitempty"`
|
||||
}
|
||||
|
||||
// RouteConditionType is a type of condition for a route.
|
||||
type RouteConditionType string
|
||||
|
||||
// RouteConditionReason is a reason for a route condition.
|
||||
type RouteConditionReason string
|
||||
|
||||
const (
|
||||
// This condition indicates whether the route has been accepted or rejected
|
||||
// by a Gateway, and why.
|
||||
//
|
||||
// Possible reasons for this condition to be true are:
|
||||
//
|
||||
// * "Accepted"
|
||||
//
|
||||
// Possible reasons for this condition to be False are:
|
||||
//
|
||||
// * "NotAllowedByListeners"
|
||||
// * "NoMatchingListenerHostname"
|
||||
// * "UnsupportedValue"
|
||||
//
|
||||
// Possible reasons for this condition to be Unknown are:
|
||||
//
|
||||
// * "Pending"
|
||||
//
|
||||
// Controllers may raise this condition with other reasons,
|
||||
// but should prefer to use the reasons listed above to improve
|
||||
// interoperability.
|
||||
RouteConditionAccepted RouteConditionType = "Accepted"
|
||||
|
||||
// This reason is used with the "Accepted" condition when the Route has been
|
||||
// accepted by the Gateway.
|
||||
RouteReasonAccepted RouteConditionReason = "Accepted"
|
||||
|
||||
// This reason is used with the "Accepted" condition when the route has not
|
||||
// been accepted by a Gateway because the Gateway has no Listener whose
|
||||
// allowedRoutes criteria permit the route
|
||||
RouteReasonNotAllowedByListeners RouteConditionReason = "NotAllowedByListeners"
|
||||
|
||||
// This reason is used with the "Accepted" condition when the Gateway has no
|
||||
// compatible Listeners whose Hostname matches the route
|
||||
RouteReasonNoMatchingListenerHostname RouteConditionReason = "NoMatchingListenerHostname"
|
||||
|
||||
// This reason is used with the "Accepted" condition when there are
|
||||
// no matching Parents. In the case of Gateways, this can occur when
|
||||
// a Route ParentRef specifies a Port and/or SectionName that does not
|
||||
// match any Listeners in the Gateway.
|
||||
RouteReasonNoMatchingParent RouteConditionReason = "NoMatchingParent"
|
||||
|
||||
// This reason is used with the "Accepted" condition when a value for an Enum
|
||||
// is not recognized.
|
||||
RouteReasonUnsupportedValue RouteConditionReason = "UnsupportedValue"
|
||||
|
||||
// This reason is used with the "Accepted" when a controller has not yet
|
||||
// reconciled the route.
|
||||
RouteReasonPending RouteConditionReason = "Pending"
|
||||
|
||||
// This condition indicates whether the controller was able to resolve all
|
||||
// the object references for the Route.
|
||||
//
|
||||
// Possible reasons for this condition to be true are:
|
||||
//
|
||||
// * "ResolvedRefs"
|
||||
//
|
||||
// Possible reasons for this condition to be false are:
|
||||
//
|
||||
// * "RefNotPermitted"
|
||||
// * "InvalidKind"
|
||||
// * "BackendNotFound"
|
||||
//
|
||||
// Controllers may raise this condition with other reasons,
|
||||
// but should prefer to use the reasons listed above to improve
|
||||
// interoperability.
|
||||
RouteConditionResolvedRefs RouteConditionType = "ResolvedRefs"
|
||||
|
||||
// This reason is used with the "ResolvedRefs" condition when the condition
|
||||
// is true.
|
||||
RouteReasonResolvedRefs RouteConditionReason = "ResolvedRefs"
|
||||
|
||||
// This reason is used with the "ResolvedRefs" condition when
|
||||
// one of the Listener's Routes has a BackendRef to an object in
|
||||
// another namespace, where the object in the other namespace does
|
||||
// not have a ReferenceGrant explicitly allowing the reference.
|
||||
RouteReasonRefNotPermitted RouteConditionReason = "RefNotPermitted"
|
||||
|
||||
// This reason is used with the "ResolvedRefs" condition when
|
||||
// one of the Route's rules has a reference to an unknown or unsupported
|
||||
// Group and/or Kind.
|
||||
RouteReasonInvalidKind RouteConditionReason = "InvalidKind"
|
||||
|
||||
// This reason is used with the "ResolvedRefs" condition when one of the
|
||||
// Route's rules has a reference to a resource that does not exist.
|
||||
RouteReasonBackendNotFound RouteConditionReason = "BackendNotFound"
|
||||
)
|
||||
|
||||
// RouteParentStatus describes the status of a route with respect to an
|
||||
// associated Parent.
|
||||
type RouteParentStatus struct {
|
||||
// ParentRef corresponds with a ParentRef in the spec that this
|
||||
// RouteParentStatus struct describes the status of.
|
||||
ParentRef ParentReference `json:"parentRef"`
|
||||
|
||||
// ControllerName is a domain/path string that indicates the name of the
|
||||
// controller that wrote this status. This corresponds with the
|
||||
// controllerName field on GatewayClass.
|
||||
//
|
||||
// Example: "example.net/gateway-controller".
|
||||
//
|
||||
// The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are
|
||||
// valid Kubernetes names
|
||||
// (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names).
|
||||
//
|
||||
// Controllers MUST populate this field when writing status. Controllers should ensure that
|
||||
// entries to status populated with their ControllerName are cleaned up when they are no
|
||||
// longer necessary.
|
||||
ControllerName GatewayController `json:"controllerName"`
|
||||
|
||||
// Conditions describes the status of the route with respect to the Gateway.
|
||||
// Note that the route's availability is also subject to the Gateway's own
|
||||
// status conditions and listener status.
|
||||
//
|
||||
// If the Route's ParentRef specifies an existing Gateway that supports
|
||||
// Routes of this kind AND that Gateway's controller has sufficient access,
|
||||
// then that Gateway's controller MUST set the "Accepted" condition on the
|
||||
// Route, to indicate whether the route has been accepted or rejected by the
|
||||
// Gateway, and why.
|
||||
//
|
||||
// A Route MUST be considered "Accepted" if at least one of the Route's
|
||||
// rules is implemented by the Gateway.
|
||||
//
|
||||
// There are a number of cases where the "Accepted" condition may not be set
|
||||
// due to lack of controller visibility, that includes when:
|
||||
//
|
||||
// * The Route refers to a non-existent parent.
|
||||
// * The Route is of a type that the controller does not support.
|
||||
// * The Route is in a namespace the controller does not have access to.
|
||||
//
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
// +kubebuilder:validation:MinItems=1
|
||||
// +kubebuilder:validation:MaxItems=8
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// RouteStatus defines the common attributes that all Routes MUST include within
|
||||
// their status.
|
||||
type RouteStatus struct {
|
||||
// Parents is a list of parent resources (usually Gateways) that are
|
||||
// associated with the route, and the status of the route with respect to
|
||||
// each parent. When this route attaches to a parent, the controller that
|
||||
// manages the parent must add an entry to this list when the controller
|
||||
// first sees the route and should update the entry as appropriate when the
|
||||
// route or gateway is modified.
|
||||
//
|
||||
// Note that parent references that cannot be resolved by an implementation
|
||||
// of this API will not be added to this list. Implementations of this API
|
||||
// can only populate Route status for the Gateways/parent resources they are
|
||||
// responsible for.
|
||||
//
|
||||
// A maximum of 32 Gateways will be represented in this list. An empty list
|
||||
// means the route has not been attached to any Gateway.
|
||||
//
|
||||
// +kubebuilder:validation:MaxItems=32
|
||||
Parents []RouteParentStatus `json:"parents"`
|
||||
}
|
||||
|
||||
// Hostname is the fully qualified domain name of a network host. This matches
|
||||
// the RFC 1123 definition of a hostname with 2 notable exceptions:
|
||||
//
|
||||
// 1. IPs are not allowed.
|
||||
// 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard
|
||||
// label must appear by itself as the first label.
|
||||
//
|
||||
// Hostname can be "precise" which is a domain name without the terminating
|
||||
// dot of a network host (e.g. "foo.example.com") or "wildcard", which is a
|
||||
// domain name prefixed with a single wildcard label (e.g. `*.example.com`).
|
||||
//
|
||||
// Note that as per RFC1035 and RFC1123, a *label* must consist of lower case
|
||||
// alphanumeric characters or '-', and must start and end with an alphanumeric
|
||||
// character. No other punctuation is allowed.
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
|
||||
type Hostname string
|
||||
|
||||
// PreciseHostname is the fully qualified domain name of a network host. This
|
||||
// matches the RFC 1123 definition of a hostname with 1 notable exception that
|
||||
// numeric IP addresses are not allowed.
|
||||
//
|
||||
// Note that as per RFC1035 and RFC1123, a *label* must consist of lower case
|
||||
// alphanumeric characters or '-', and must start and end with an alphanumeric
|
||||
// character. No other punctuation is allowed.
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
|
||||
type PreciseHostname string
|
||||
|
||||
// Group refers to a Kubernetes Group. It must either be an empty string or a
|
||||
// RFC 1123 subdomain.
|
||||
//
|
||||
// This validation is based off of the corresponding Kubernetes validation:
|
||||
// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * "" - empty string implies core Kubernetes API group
|
||||
// * "gateway.networking.k8s.io"
|
||||
// * "foo.example.com"
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * "example.com/bar" - "/" is an invalid character
|
||||
//
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
|
||||
type Group string
|
||||
|
||||
// Kind refers to a Kubernetes Kind.
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * "Service"
|
||||
// * "HTTPRoute"
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * "invalid/kind" - "/" is an invalid character
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=63
|
||||
// +kubebuilder:validation:Pattern=`^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$`
|
||||
type Kind string
|
||||
|
||||
// ObjectName refers to the name of a Kubernetes object.
|
||||
// Object names can have a variety of forms, including RFC1123 subdomains,
|
||||
// RFC 1123 labels, or RFC 1035 labels.
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
type ObjectName string
|
||||
|
||||
// Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label.
|
||||
//
|
||||
// This validation is based off of the corresponding Kubernetes validation:
|
||||
// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187
|
||||
//
|
||||
// This is used for Namespace name validation here:
|
||||
// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * "example"
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * "example.com" - "." is an invalid character
|
||||
//
|
||||
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=63
|
||||
type Namespace string
|
||||
|
||||
// SectionName is the name of a section in a Kubernetes resource.
|
||||
//
|
||||
// This validation is based off of the corresponding Kubernetes validation:
|
||||
// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * "example.com"
|
||||
// * "foo.example.com"
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * "example.com/bar" - "/" is an invalid character
|
||||
//
|
||||
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
type SectionName string
|
||||
|
||||
// GatewayController is the name of a Gateway API controller. It must be a
|
||||
// domain prefixed path.
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * "example.com/bar"
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * "example.com" - must include path
|
||||
// * "foo.example.com" - must include path
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$`
|
||||
type GatewayController string
|
||||
|
||||
// AnnotationKey is the key of an annotation in Gateway API. This is used for
|
||||
// validation of maps such as TLS options. This matches the Kubernetes
|
||||
// "qualified name" validation that is used for annotations and other common
|
||||
// values.
|
||||
//
|
||||
// Valid values include:
|
||||
//
|
||||
// * example
|
||||
// * example.com
|
||||
// * example.com/path
|
||||
// * example.com/path.html
|
||||
//
|
||||
// Invalid values include:
|
||||
//
|
||||
// * example~ - "~" is an invalid character
|
||||
// * example.com. - can not start or end with "."
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]/?)*$`
|
||||
type AnnotationKey string
|
||||
|
||||
// AnnotationValue is the value of an annotation in Gateway API. This is used
|
||||
// for validation of maps such as TLS options. This roughly matches Kubernetes
|
||||
// annotation validation, although the length validation in that case is based
|
||||
// on the entire size of the annotations struct.
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=0
|
||||
// +kubebuilder:validation:MaxLength=4096
|
||||
type AnnotationValue string
|
||||
|
||||
// AddressType defines how a network address is represented as a text string.
|
||||
// This may take two possible forms:
|
||||
//
|
||||
// * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`)
|
||||
// * A domain-prefixed string identifier (like `acme.io/CustomAddressType`)
|
||||
//
|
||||
// Values `IPAddress` and `Hostname` have Extended support.
|
||||
//
|
||||
// The `NamedAddress` value has been deprecated in favor of implementation
|
||||
// specific domain-prefixed strings.
|
||||
//
|
||||
// All other values, including domain-prefixed values have Implementation-specific support,
|
||||
// which are used in implementation-specific behaviors. Support for additional
|
||||
// predefined CamelCase identifiers may be added in future releases.
|
||||
//
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Pattern=`^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$`
|
||||
type AddressType string
|
||||
|
||||
const (
|
||||
// A textual representation of a numeric IP address. IPv4
|
||||
// addresses must be in dotted-decimal form. IPv6 addresses
|
||||
// must be in a standard IPv6 text representation
|
||||
// (see [RFC 5952](https://tools.ietf.org/html/rfc5952)).
|
||||
//
|
||||
// This type is intended for specific addresses. Address ranges are not
|
||||
// supported (e.g. you can not use a CIDR range like 127.0.0.0/24 as an
|
||||
// IPAddress).
|
||||
//
|
||||
// Support: Extended
|
||||
IPAddressType AddressType = "IPAddress"
|
||||
|
||||
// A Hostname represents a DNS based ingress point. This is similar to the
|
||||
// corresponding hostname field in Kubernetes load balancer status. For
|
||||
// example, this concept may be used for cloud load balancers where a DNS
|
||||
// name is used to expose a load balancer.
|
||||
//
|
||||
// Support: Extended
|
||||
HostnameAddressType AddressType = "Hostname"
|
||||
|
||||
// A NamedAddress provides a way to reference a specific IP address by name.
|
||||
// For example, this may be a name or other unique identifier that refers
|
||||
// to a resource on a cloud provider such as a static IP.
|
||||
//
|
||||
// The `NamedAddress` type has been deprecated in favor of implementation
|
||||
// specific domain-prefixed strings.
|
||||
//
|
||||
// Support: Implementation-specific
|
||||
NamedAddressType AddressType = "NamedAddress"
|
||||
)
|
||||
694
pkg/apis/gatewayapi/v1beta1/zz_generated.deepcopy.go
Normal file
694
pkg/apis/gatewayapi/v1beta1/zz_generated.deepcopy.go
Normal file
@@ -0,0 +1,694 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BackendObjectReference) DeepCopyInto(out *BackendObjectReference) {
|
||||
*out = *in
|
||||
if in.Group != nil {
|
||||
in, out := &in.Group, &out.Group
|
||||
*out = new(Group)
|
||||
**out = **in
|
||||
}
|
||||
if in.Kind != nil {
|
||||
in, out := &in.Kind, &out.Kind
|
||||
*out = new(Kind)
|
||||
**out = **in
|
||||
}
|
||||
if in.Namespace != nil {
|
||||
in, out := &in.Namespace, &out.Namespace
|
||||
*out = new(Namespace)
|
||||
**out = **in
|
||||
}
|
||||
if in.Port != nil {
|
||||
in, out := &in.Port, &out.Port
|
||||
*out = new(PortNumber)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendObjectReference.
|
||||
func (in *BackendObjectReference) DeepCopy() *BackendObjectReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BackendObjectReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BackendRef) DeepCopyInto(out *BackendRef) {
|
||||
*out = *in
|
||||
in.BackendObjectReference.DeepCopyInto(&out.BackendObjectReference)
|
||||
if in.Weight != nil {
|
||||
in, out := &in.Weight, &out.Weight
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendRef.
|
||||
func (in *BackendRef) DeepCopy() *BackendRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BackendRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CommonRouteSpec) DeepCopyInto(out *CommonRouteSpec) {
|
||||
*out = *in
|
||||
if in.ParentRefs != nil {
|
||||
in, out := &in.ParentRefs, &out.ParentRefs
|
||||
*out = make([]ParentReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonRouteSpec.
|
||||
func (in *CommonRouteSpec) DeepCopy() *CommonRouteSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CommonRouteSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPBackendRef) DeepCopyInto(out *HTTPBackendRef) {
|
||||
*out = *in
|
||||
in.BackendRef.DeepCopyInto(&out.BackendRef)
|
||||
if in.Filters != nil {
|
||||
in, out := &in.Filters, &out.Filters
|
||||
*out = make([]HTTPRouteFilter, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPBackendRef.
|
||||
func (in *HTTPBackendRef) DeepCopy() *HTTPBackendRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPBackendRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPHeader) DeepCopyInto(out *HTTPHeader) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeader.
|
||||
func (in *HTTPHeader) DeepCopy() *HTTPHeader {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPHeader)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPHeaderFilter) DeepCopyInto(out *HTTPHeaderFilter) {
|
||||
*out = *in
|
||||
if in.Set != nil {
|
||||
in, out := &in.Set, &out.Set
|
||||
*out = make([]HTTPHeader, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Add != nil {
|
||||
in, out := &in.Add, &out.Add
|
||||
*out = make([]HTTPHeader, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Remove != nil {
|
||||
in, out := &in.Remove, &out.Remove
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeaderFilter.
|
||||
func (in *HTTPHeaderFilter) DeepCopy() *HTTPHeaderFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPHeaderFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPHeaderMatch) DeepCopyInto(out *HTTPHeaderMatch) {
|
||||
*out = *in
|
||||
if in.Type != nil {
|
||||
in, out := &in.Type, &out.Type
|
||||
*out = new(HeaderMatchType)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeaderMatch.
|
||||
func (in *HTTPHeaderMatch) DeepCopy() *HTTPHeaderMatch {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPHeaderMatch)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPPathMatch) DeepCopyInto(out *HTTPPathMatch) {
|
||||
*out = *in
|
||||
if in.Type != nil {
|
||||
in, out := &in.Type, &out.Type
|
||||
*out = new(PathMatchType)
|
||||
**out = **in
|
||||
}
|
||||
if in.Value != nil {
|
||||
in, out := &in.Value, &out.Value
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPPathMatch.
|
||||
func (in *HTTPPathMatch) DeepCopy() *HTTPPathMatch {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPPathMatch)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPPathModifier) DeepCopyInto(out *HTTPPathModifier) {
|
||||
*out = *in
|
||||
if in.ReplaceFullPath != nil {
|
||||
in, out := &in.ReplaceFullPath, &out.ReplaceFullPath
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.ReplacePrefixMatch != nil {
|
||||
in, out := &in.ReplacePrefixMatch, &out.ReplacePrefixMatch
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPPathModifier.
|
||||
func (in *HTTPPathModifier) DeepCopy() *HTTPPathModifier {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPPathModifier)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPQueryParamMatch) DeepCopyInto(out *HTTPQueryParamMatch) {
|
||||
*out = *in
|
||||
if in.Type != nil {
|
||||
in, out := &in.Type, &out.Type
|
||||
*out = new(QueryParamMatchType)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPQueryParamMatch.
|
||||
func (in *HTTPQueryParamMatch) DeepCopy() *HTTPQueryParamMatch {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPQueryParamMatch)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRequestMirrorFilter) DeepCopyInto(out *HTTPRequestMirrorFilter) {
|
||||
*out = *in
|
||||
in.BackendRef.DeepCopyInto(&out.BackendRef)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRequestMirrorFilter.
|
||||
func (in *HTTPRequestMirrorFilter) DeepCopy() *HTTPRequestMirrorFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRequestMirrorFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRequestRedirectFilter) DeepCopyInto(out *HTTPRequestRedirectFilter) {
|
||||
*out = *in
|
||||
if in.Scheme != nil {
|
||||
in, out := &in.Scheme, &out.Scheme
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Hostname != nil {
|
||||
in, out := &in.Hostname, &out.Hostname
|
||||
*out = new(PreciseHostname)
|
||||
**out = **in
|
||||
}
|
||||
if in.Path != nil {
|
||||
in, out := &in.Path, &out.Path
|
||||
*out = new(HTTPPathModifier)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Port != nil {
|
||||
in, out := &in.Port, &out.Port
|
||||
*out = new(PortNumber)
|
||||
**out = **in
|
||||
}
|
||||
if in.StatusCode != nil {
|
||||
in, out := &in.StatusCode, &out.StatusCode
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRequestRedirectFilter.
|
||||
func (in *HTTPRequestRedirectFilter) DeepCopy() *HTTPRequestRedirectFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRequestRedirectFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRoute.
|
||||
func (in *HTTPRoute) DeepCopy() *HTTPRoute {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRoute)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *HTTPRoute) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteFilter) DeepCopyInto(out *HTTPRouteFilter) {
|
||||
*out = *in
|
||||
if in.RequestHeaderModifier != nil {
|
||||
in, out := &in.RequestHeaderModifier, &out.RequestHeaderModifier
|
||||
*out = new(HTTPHeaderFilter)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ResponseHeaderModifier != nil {
|
||||
in, out := &in.ResponseHeaderModifier, &out.ResponseHeaderModifier
|
||||
*out = new(HTTPHeaderFilter)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RequestMirror != nil {
|
||||
in, out := &in.RequestMirror, &out.RequestMirror
|
||||
*out = new(HTTPRequestMirrorFilter)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RequestRedirect != nil {
|
||||
in, out := &in.RequestRedirect, &out.RequestRedirect
|
||||
*out = new(HTTPRequestRedirectFilter)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.URLRewrite != nil {
|
||||
in, out := &in.URLRewrite, &out.URLRewrite
|
||||
*out = new(HTTPURLRewriteFilter)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ExtensionRef != nil {
|
||||
in, out := &in.ExtensionRef, &out.ExtensionRef
|
||||
*out = new(LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteFilter.
|
||||
func (in *HTTPRouteFilter) DeepCopy() *HTTPRouteFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteList) DeepCopyInto(out *HTTPRouteList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]HTTPRoute, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteList.
|
||||
func (in *HTTPRouteList) DeepCopy() *HTTPRouteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *HTTPRouteList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteMatch) DeepCopyInto(out *HTTPRouteMatch) {
|
||||
*out = *in
|
||||
if in.Path != nil {
|
||||
in, out := &in.Path, &out.Path
|
||||
*out = new(HTTPPathMatch)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = make([]HTTPHeaderMatch, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.QueryParams != nil {
|
||||
in, out := &in.QueryParams, &out.QueryParams
|
||||
*out = make([]HTTPQueryParamMatch, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Method != nil {
|
||||
in, out := &in.Method, &out.Method
|
||||
*out = new(HTTPMethod)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteMatch.
|
||||
func (in *HTTPRouteMatch) DeepCopy() *HTTPRouteMatch {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteMatch)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteRule) DeepCopyInto(out *HTTPRouteRule) {
|
||||
*out = *in
|
||||
if in.Matches != nil {
|
||||
in, out := &in.Matches, &out.Matches
|
||||
*out = make([]HTTPRouteMatch, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Filters != nil {
|
||||
in, out := &in.Filters, &out.Filters
|
||||
*out = make([]HTTPRouteFilter, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.BackendRefs != nil {
|
||||
in, out := &in.BackendRefs, &out.BackendRefs
|
||||
*out = make([]HTTPBackendRef, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteRule.
|
||||
func (in *HTTPRouteRule) DeepCopy() *HTTPRouteRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteSpec) DeepCopyInto(out *HTTPRouteSpec) {
|
||||
*out = *in
|
||||
in.CommonRouteSpec.DeepCopyInto(&out.CommonRouteSpec)
|
||||
if in.Hostnames != nil {
|
||||
in, out := &in.Hostnames, &out.Hostnames
|
||||
*out = make([]Hostname, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]HTTPRouteRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteSpec.
|
||||
func (in *HTTPRouteSpec) DeepCopy() *HTTPRouteSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteStatus) DeepCopyInto(out *HTTPRouteStatus) {
|
||||
*out = *in
|
||||
in.RouteStatus.DeepCopyInto(&out.RouteStatus)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteStatus.
|
||||
func (in *HTTPRouteStatus) DeepCopy() *HTTPRouteStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPURLRewriteFilter) DeepCopyInto(out *HTTPURLRewriteFilter) {
|
||||
*out = *in
|
||||
if in.Hostname != nil {
|
||||
in, out := &in.Hostname, &out.Hostname
|
||||
*out = new(PreciseHostname)
|
||||
**out = **in
|
||||
}
|
||||
if in.Path != nil {
|
||||
in, out := &in.Path, &out.Path
|
||||
*out = new(HTTPPathModifier)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPURLRewriteFilter.
|
||||
func (in *HTTPURLRewriteFilter) DeepCopy() *HTTPURLRewriteFilter {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPURLRewriteFilter)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LocalObjectReference) DeepCopyInto(out *LocalObjectReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalObjectReference.
|
||||
func (in *LocalObjectReference) DeepCopy() *LocalObjectReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LocalObjectReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ParentReference) DeepCopyInto(out *ParentReference) {
|
||||
*out = *in
|
||||
if in.Group != nil {
|
||||
in, out := &in.Group, &out.Group
|
||||
*out = new(Group)
|
||||
**out = **in
|
||||
}
|
||||
if in.Kind != nil {
|
||||
in, out := &in.Kind, &out.Kind
|
||||
*out = new(Kind)
|
||||
**out = **in
|
||||
}
|
||||
if in.Namespace != nil {
|
||||
in, out := &in.Namespace, &out.Namespace
|
||||
*out = new(Namespace)
|
||||
**out = **in
|
||||
}
|
||||
if in.SectionName != nil {
|
||||
in, out := &in.SectionName, &out.SectionName
|
||||
*out = new(SectionName)
|
||||
**out = **in
|
||||
}
|
||||
if in.Port != nil {
|
||||
in, out := &in.Port, &out.Port
|
||||
*out = new(PortNumber)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentReference.
|
||||
func (in *ParentReference) DeepCopy() *ParentReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ParentReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RouteParentStatus) DeepCopyInto(out *RouteParentStatus) {
|
||||
*out = *in
|
||||
in.ParentRef.DeepCopyInto(&out.ParentRef)
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteParentStatus.
|
||||
func (in *RouteParentStatus) DeepCopy() *RouteParentStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RouteParentStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RouteStatus) DeepCopyInto(out *RouteStatus) {
|
||||
*out = *in
|
||||
if in.Parents != nil {
|
||||
in, out := &in.Parents, &out.Parents
|
||||
*out = make([]RouteParentStatus, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteStatus.
|
||||
func (in *RouteStatus) DeepCopy() *RouteStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RouteStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SecretObjectReference) DeepCopyInto(out *SecretObjectReference) {
|
||||
*out = *in
|
||||
if in.Group != nil {
|
||||
in, out := &in.Group, &out.Group
|
||||
*out = new(Group)
|
||||
**out = **in
|
||||
}
|
||||
if in.Kind != nil {
|
||||
in, out := &in.Kind, &out.Kind
|
||||
*out = new(Kind)
|
||||
**out = **in
|
||||
}
|
||||
if in.Namespace != nil {
|
||||
in, out := &in.Namespace, &out.Namespace
|
||||
*out = new(Namespace)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretObjectReference.
|
||||
func (in *SecretObjectReference) DeepCopy() *SecretObjectReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SecretObjectReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
@@ -311,6 +311,10 @@ type Destination struct {
|
||||
// Describes match conditions and actions for routing HTTP/1.1, HTTP2, and
|
||||
// gRPC traffic. See VirtualService for usage examples.
|
||||
type HTTPRoute struct {
|
||||
// The name assigned to the route for debugging purposes. The route’s name will
|
||||
// be concatenated with the match’s name and will be logged in the access logs
|
||||
// for requests matching this route/match.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Match conditions to be satisfied for the rule to be
|
||||
// activated. All conditions inside a single match block have AND
|
||||
// semantics, while the list of match blocks have OR semantics. The rule
|
||||
@@ -321,7 +325,7 @@ type HTTPRoute struct {
|
||||
// forwarding target can be one of several versions of a service (see
|
||||
// glossary in beginning of document). Weights associated with the
|
||||
// service version determine the proportion of traffic it receives.
|
||||
Route []DestinationWeight `json:"route,omitempty"`
|
||||
Route []HTTPRouteDestination `json:"route,omitempty"`
|
||||
|
||||
// A http rule can either redirect or forward (default) traffic. If
|
||||
// traffic passthrough option is specified in the rule,
|
||||
@@ -528,7 +532,7 @@ type HTTPMatchRequest struct {
|
||||
SourceNamespace string `json:"sourceNamespace,omitempty"`
|
||||
}
|
||||
|
||||
type DestinationWeight struct {
|
||||
type HTTPRouteDestination struct {
|
||||
// REQUIRED. Destination uniquely identifies the instances of a service
|
||||
// to which the request/connection should be forwarded to.
|
||||
Destination Destination `json:"destination"`
|
||||
@@ -538,6 +542,9 @@ type DestinationWeight struct {
|
||||
// If there is only destination in a rule, the weight value is assumed to
|
||||
// be 100.
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// Header manipulation rules
|
||||
Headers *Headers `json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// PortSelector specifies the number of a port to be used for
|
||||
@@ -590,7 +597,7 @@ type TCPRoute struct {
|
||||
// Currently, only one destination is allowed for TCP services. When TCP
|
||||
// weighted routing support is introduced in Envoy, multiple destinations
|
||||
// with weights can be specified.
|
||||
Route DestinationWeight `json:"route"`
|
||||
Route HTTPRouteDestination `json:"route"`
|
||||
}
|
||||
|
||||
// L4 connection match attributes. Note that L4 connection matching support
|
||||
|
||||
@@ -229,23 +229,6 @@ func (in *DestinationRuleSpec) DeepCopy() *DestinationRuleSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DestinationWeight) DeepCopyInto(out *DestinationWeight) {
|
||||
*out = *in
|
||||
in.Destination.DeepCopyInto(&out.Destination)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DestinationWeight.
|
||||
func (in *DestinationWeight) DeepCopy() *DestinationWeight {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DestinationWeight)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Distribute) DeepCopyInto(out *Distribute) {
|
||||
*out = *in
|
||||
@@ -456,7 +439,7 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) {
|
||||
}
|
||||
if in.Route != nil {
|
||||
in, out := &in.Route, &out.Route
|
||||
*out = make([]DestinationWeight, len(*in))
|
||||
*out = make([]HTTPRouteDestination, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
@@ -514,6 +497,28 @@ func (in *HTTPRoute) DeepCopy() *HTTPRoute {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPRouteDestination) DeepCopyInto(out *HTTPRouteDestination) {
|
||||
*out = *in
|
||||
in.Destination.DeepCopyInto(&out.Destination)
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = new(Headers)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteDestination.
|
||||
func (in *HTTPRouteDestination) DeepCopy() *HTTPRouteDestination {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPRouteDestination)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPSettings) DeepCopyInto(out *HTTPSettings) {
|
||||
*out = *in
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
flaggerv1beta1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/flagger/v1beta1"
|
||||
gatewayv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gateway/v1"
|
||||
gatewayapiv1alpha2 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1alpha2"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1beta1"
|
||||
gloov1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gloo/v1"
|
||||
networkingv1alpha3 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3"
|
||||
kedav1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/keda/v1alpha1"
|
||||
@@ -48,6 +49,7 @@ type Interface interface {
|
||||
FlaggerV1beta1() flaggerv1beta1.FlaggerV1beta1Interface
|
||||
GatewayV1() gatewayv1.GatewayV1Interface
|
||||
GatewayapiV1alpha2() gatewayapiv1alpha2.GatewayapiV1alpha2Interface
|
||||
GatewayapiV1beta1() gatewayapiv1beta1.GatewayapiV1beta1Interface
|
||||
GlooV1() gloov1.GlooV1Interface
|
||||
NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3Interface
|
||||
KedaV1alpha1() kedav1alpha1.KedaV1alpha1Interface
|
||||
@@ -68,6 +70,7 @@ type Clientset struct {
|
||||
flaggerV1beta1 *flaggerv1beta1.FlaggerV1beta1Client
|
||||
gatewayV1 *gatewayv1.GatewayV1Client
|
||||
gatewayapiV1alpha2 *gatewayapiv1alpha2.GatewayapiV1alpha2Client
|
||||
gatewayapiV1beta1 *gatewayapiv1beta1.GatewayapiV1beta1Client
|
||||
glooV1 *gloov1.GlooV1Client
|
||||
networkingV1alpha3 *networkingv1alpha3.NetworkingV1alpha3Client
|
||||
kedaV1alpha1 *kedav1alpha1.KedaV1alpha1Client
|
||||
@@ -104,6 +107,11 @@ func (c *Clientset) GatewayapiV1alpha2() gatewayapiv1alpha2.GatewayapiV1alpha2In
|
||||
return c.gatewayapiV1alpha2
|
||||
}
|
||||
|
||||
// GatewayapiV1beta1 retrieves the GatewayapiV1beta1Client
|
||||
func (c *Clientset) GatewayapiV1beta1() gatewayapiv1beta1.GatewayapiV1beta1Interface {
|
||||
return c.gatewayapiV1beta1
|
||||
}
|
||||
|
||||
// GlooV1 retrieves the GlooV1Client
|
||||
func (c *Clientset) GlooV1() gloov1.GlooV1Interface {
|
||||
return c.glooV1
|
||||
@@ -213,6 +221,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.gatewayapiV1beta1, err = gatewayapiv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.glooV1, err = gloov1.NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -275,6 +287,7 @@ func New(c rest.Interface) *Clientset {
|
||||
cs.flaggerV1beta1 = flaggerv1beta1.New(c)
|
||||
cs.gatewayV1 = gatewayv1.New(c)
|
||||
cs.gatewayapiV1alpha2 = gatewayapiv1alpha2.New(c)
|
||||
cs.gatewayapiV1beta1 = gatewayapiv1beta1.New(c)
|
||||
cs.glooV1 = gloov1.New(c)
|
||||
cs.networkingV1alpha3 = networkingv1alpha3.New(c)
|
||||
cs.kedaV1alpha1 = kedav1alpha1.New(c)
|
||||
|
||||
@@ -30,6 +30,8 @@ import (
|
||||
fakegatewayv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gateway/v1/fake"
|
||||
gatewayapiv1alpha2 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1alpha2"
|
||||
fakegatewayapiv1alpha2 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1alpha2/fake"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1beta1"
|
||||
fakegatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1beta1/fake"
|
||||
gloov1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gloo/v1"
|
||||
fakegloov1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gloo/v1/fake"
|
||||
networkingv1alpha3 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3"
|
||||
@@ -130,6 +132,11 @@ func (c *Clientset) GatewayapiV1alpha2() gatewayapiv1alpha2.GatewayapiV1alpha2In
|
||||
return &fakegatewayapiv1alpha2.FakeGatewayapiV1alpha2{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// GatewayapiV1beta1 retrieves the GatewayapiV1beta1Client
|
||||
func (c *Clientset) GatewayapiV1beta1() gatewayapiv1beta1.GatewayapiV1beta1Interface {
|
||||
return &fakegatewayapiv1beta1.FakeGatewayapiV1beta1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// GlooV1 retrieves the GlooV1Client
|
||||
func (c *Clientset) GlooV1() gloov1.GlooV1Interface {
|
||||
return &fakegloov1.FakeGlooV1{Fake: &c.Fake}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
appmeshv1beta2 "github.com/fluxcd/flagger/pkg/apis/appmesh/v1beta2"
|
||||
flaggerv1beta1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
gatewayapiv1alpha2 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
gatewayv1 "github.com/fluxcd/flagger/pkg/apis/gloo/gateway/v1"
|
||||
gloov1 "github.com/fluxcd/flagger/pkg/apis/gloo/gloo/v1"
|
||||
networkingv1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
@@ -49,6 +50,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
flaggerv1beta1.AddToScheme,
|
||||
gatewayv1.AddToScheme,
|
||||
gatewayapiv1alpha2.AddToScheme,
|
||||
gatewayapiv1beta1.AddToScheme,
|
||||
gloov1.AddToScheme,
|
||||
networkingv1alpha3.AddToScheme,
|
||||
kedav1alpha1.AddToScheme,
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
appmeshv1beta2 "github.com/fluxcd/flagger/pkg/apis/appmesh/v1beta2"
|
||||
flaggerv1beta1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
gatewayapiv1alpha2 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
gatewayv1 "github.com/fluxcd/flagger/pkg/apis/gloo/gateway/v1"
|
||||
gloov1 "github.com/fluxcd/flagger/pkg/apis/gloo/gloo/v1"
|
||||
networkingv1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
@@ -49,6 +50,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
flaggerv1beta1.AddToScheme,
|
||||
gatewayv1.AddToScheme,
|
||||
gatewayapiv1alpha2.AddToScheme,
|
||||
gatewayapiv1beta1.AddToScheme,
|
||||
gloov1.AddToScheme,
|
||||
networkingv1alpha3.AddToScheme,
|
||||
kedav1alpha1.AddToScheme,
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1beta1
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gatewayapi/v1beta1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeGatewayapiV1beta1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeGatewayapiV1beta1) HTTPRoutes(namespace string) v1beta1.HTTPRouteInterface {
|
||||
return &FakeHTTPRoutes{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeGatewayapiV1beta1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeHTTPRoutes implements HTTPRouteInterface
|
||||
type FakeHTTPRoutes struct {
|
||||
Fake *FakeGatewayapiV1beta1
|
||||
ns string
|
||||
}
|
||||
|
||||
var httproutesResource = schema.GroupVersionResource{Group: "gatewayapi", Version: "v1beta1", Resource: "httproutes"}
|
||||
|
||||
var httproutesKind = schema.GroupVersionKind{Group: "gatewayapi", Version: "v1beta1", Kind: "HTTPRoute"}
|
||||
|
||||
// Get takes name of the hTTPRoute, and returns the corresponding hTTPRoute object, and an error if there is any.
|
||||
func (c *FakeHTTPRoutes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(httproutesResource, c.ns, name), &v1beta1.HTTPRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of HTTPRoutes that match those selectors.
|
||||
func (c *FakeHTTPRoutes) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.HTTPRouteList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(httproutesResource, httproutesKind, c.ns, opts), &v1beta1.HTTPRouteList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.HTTPRouteList{ListMeta: obj.(*v1beta1.HTTPRouteList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.HTTPRouteList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested hTTPRoutes.
|
||||
func (c *FakeHTTPRoutes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(httproutesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a hTTPRoute and creates it. Returns the server's representation of the hTTPRoute, and an error, if there is any.
|
||||
func (c *FakeHTTPRoutes) Create(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.CreateOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(httproutesResource, c.ns, hTTPRoute), &v1beta1.HTTPRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a hTTPRoute and updates it. Returns the server's representation of the hTTPRoute, and an error, if there is any.
|
||||
func (c *FakeHTTPRoutes) Update(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(httproutesResource, c.ns, hTTPRoute), &v1beta1.HTTPRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeHTTPRoutes) UpdateStatus(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (*v1beta1.HTTPRoute, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(httproutesResource, "status", c.ns, hTTPRoute), &v1beta1.HTTPRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), err
|
||||
}
|
||||
|
||||
// Delete takes name of the hTTPRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeHTTPRoutes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteActionWithOptions(httproutesResource, c.ns, name, opts), &v1beta1.HTTPRoute{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeHTTPRoutes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(httproutesResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.HTTPRouteList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched hTTPRoute.
|
||||
func (c *FakeHTTPRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.HTTPRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(httproutesResource, c.ns, name, pt, data, subresources...), &v1beta1.HTTPRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), err
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/client/clientset/versioned/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type GatewayapiV1beta1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
HTTPRoutesGetter
|
||||
}
|
||||
|
||||
// GatewayapiV1beta1Client is used to interact with features provided by the gatewayapi group.
|
||||
type GatewayapiV1beta1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *GatewayapiV1beta1Client) HTTPRoutes(namespace string) HTTPRouteInterface {
|
||||
return newHTTPRoutes(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new GatewayapiV1beta1Client for the given config.
|
||||
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
|
||||
// where httpClient was generated with rest.HTTPClientFor(c).
|
||||
func NewForConfig(c *rest.Config) (*GatewayapiV1beta1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient, err := rest.HTTPClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewForConfigAndClient(&config, httpClient)
|
||||
}
|
||||
|
||||
// NewForConfigAndClient creates a new GatewayapiV1beta1Client for the given config and http client.
|
||||
// Note the http client provided takes precedence over the configured transport values.
|
||||
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GatewayapiV1beta1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientForConfigAndClient(&config, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GatewayapiV1beta1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new GatewayapiV1beta1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *GatewayapiV1beta1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new GatewayapiV1beta1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *GatewayapiV1beta1Client {
|
||||
return &GatewayapiV1beta1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1beta1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *GatewayapiV1beta1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
type HTTPRouteExpansion interface{}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
scheme "github.com/fluxcd/flagger/pkg/client/clientset/versioned/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// HTTPRoutesGetter has a method to return a HTTPRouteInterface.
|
||||
// A group's client should implement this interface.
|
||||
type HTTPRoutesGetter interface {
|
||||
HTTPRoutes(namespace string) HTTPRouteInterface
|
||||
}
|
||||
|
||||
// HTTPRouteInterface has methods to work with HTTPRoute resources.
|
||||
type HTTPRouteInterface interface {
|
||||
Create(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.CreateOptions) (*v1beta1.HTTPRoute, error)
|
||||
Update(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (*v1beta1.HTTPRoute, error)
|
||||
UpdateStatus(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (*v1beta1.HTTPRoute, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.HTTPRoute, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.HTTPRouteList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.HTTPRoute, err error)
|
||||
HTTPRouteExpansion
|
||||
}
|
||||
|
||||
// hTTPRoutes implements HTTPRouteInterface
|
||||
type hTTPRoutes struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newHTTPRoutes returns a HTTPRoutes
|
||||
func newHTTPRoutes(c *GatewayapiV1beta1Client, namespace string) *hTTPRoutes {
|
||||
return &hTTPRoutes{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the hTTPRoute, and returns the corresponding hTTPRoute object, and an error if there is any.
|
||||
func (c *hTTPRoutes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
result = &v1beta1.HTTPRoute{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of HTTPRoutes that match those selectors.
|
||||
func (c *hTTPRoutes) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.HTTPRouteList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.HTTPRouteList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested hTTPRoutes.
|
||||
func (c *hTTPRoutes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a hTTPRoute and creates it. Returns the server's representation of the hTTPRoute, and an error, if there is any.
|
||||
func (c *hTTPRoutes) Create(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.CreateOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
result = &v1beta1.HTTPRoute{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(hTTPRoute).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a hTTPRoute and updates it. Returns the server's representation of the hTTPRoute, and an error, if there is any.
|
||||
func (c *hTTPRoutes) Update(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
result = &v1beta1.HTTPRoute{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
Name(hTTPRoute.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(hTTPRoute).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *hTTPRoutes) UpdateStatus(ctx context.Context, hTTPRoute *v1beta1.HTTPRoute, opts v1.UpdateOptions) (result *v1beta1.HTTPRoute, err error) {
|
||||
result = &v1beta1.HTTPRoute{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
Name(hTTPRoute.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(hTTPRoute).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the hTTPRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *hTTPRoutes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *hTTPRoutes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched hTTPRoute.
|
||||
func (c *hTTPRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.HTTPRoute, err error) {
|
||||
result = &v1beta1.HTTPRoute{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("httproutes").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package gatewayapi
|
||||
|
||||
import (
|
||||
v1alpha2 "github.com/fluxcd/flagger/pkg/client/informers/externalversions/gatewayapi/v1alpha2"
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/client/informers/externalversions/gatewayapi/v1beta1"
|
||||
internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
@@ -27,6 +28,8 @@ import (
|
||||
type Interface interface {
|
||||
// V1alpha2 provides access to shared informers for resources in V1alpha2.
|
||||
V1alpha2() v1alpha2.Interface
|
||||
// V1beta1 provides access to shared informers for resources in V1beta1.
|
||||
V1beta1() v1beta1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
@@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
func (g *group) V1alpha2() v1alpha2.Interface {
|
||||
return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
||||
// V1beta1 returns a new v1beta1.Interface.
|
||||
func (g *group) V1beta1() v1beta1.Interface {
|
||||
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
versioned "github.com/fluxcd/flagger/pkg/client/clientset/versioned"
|
||||
internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/client/listers/gatewayapi/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// HTTPRouteInformer provides access to a shared informer and lister for
|
||||
// HTTPRoutes.
|
||||
type HTTPRouteInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1beta1.HTTPRouteLister
|
||||
}
|
||||
|
||||
type hTTPRouteInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewHTTPRouteInformer constructs a new informer for HTTPRoute type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewHTTPRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredHTTPRouteInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredHTTPRouteInformer constructs a new informer for HTTPRoute type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredHTTPRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.GatewayapiV1beta1().HTTPRoutes(namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.GatewayapiV1beta1().HTTPRoutes(namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&gatewayapiv1beta1.HTTPRoute{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *hTTPRouteInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredHTTPRouteInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *hTTPRouteInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&gatewayapiv1beta1.HTTPRoute{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *hTTPRouteInformer) Lister() v1beta1.HTTPRouteLister {
|
||||
return v1beta1.NewHTTPRouteLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// HTTPRoutes returns a HTTPRouteInformer.
|
||||
HTTPRoutes() HTTPRouteInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// HTTPRoutes returns a HTTPRouteInformer.
|
||||
func (v *version) HTTPRoutes() HTTPRouteInformer {
|
||||
return &hTTPRouteInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
v1beta2 "github.com/fluxcd/flagger/pkg/apis/appmesh/v1beta2"
|
||||
flaggerv1beta1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
v1alpha2 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
gatewayapiv1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
v1 "github.com/fluxcd/flagger/pkg/apis/gloo/gateway/v1"
|
||||
gloov1 "github.com/fluxcd/flagger/pkg/apis/gloo/gloo/v1"
|
||||
v1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
@@ -97,6 +98,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
case v1alpha2.SchemeGroupVersion.WithResource("httproutes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Gatewayapi().V1alpha2().HTTPRoutes().Informer()}, nil
|
||||
|
||||
// Group=gatewayapi, Version=v1beta1
|
||||
case gatewayapiv1beta1.SchemeGroupVersion.WithResource("httproutes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Gatewayapi().V1beta1().HTTPRoutes().Informer()}, nil
|
||||
|
||||
// Group=gloo.solo.io, Version=v1
|
||||
case gloov1.SchemeGroupVersion.WithResource("upstreams"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Gloo().V1().Upstreams().Informer()}, nil
|
||||
|
||||
27
pkg/client/listers/gatewayapi/v1beta1/expansion_generated.go
Normal file
27
pkg/client/listers/gatewayapi/v1beta1/expansion_generated.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
// HTTPRouteListerExpansion allows custom methods to be added to
|
||||
// HTTPRouteLister.
|
||||
type HTTPRouteListerExpansion interface{}
|
||||
|
||||
// HTTPRouteNamespaceListerExpansion allows custom methods to be added to
|
||||
// HTTPRouteNamespaceLister.
|
||||
type HTTPRouteNamespaceListerExpansion interface{}
|
||||
99
pkg/client/listers/gatewayapi/v1beta1/httproute.go
Normal file
99
pkg/client/listers/gatewayapi/v1beta1/httproute.go
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1beta1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// HTTPRouteLister helps list HTTPRoutes.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type HTTPRouteLister interface {
|
||||
// List lists all HTTPRoutes in the indexer.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1beta1.HTTPRoute, err error)
|
||||
// HTTPRoutes returns an object that can list and get HTTPRoutes.
|
||||
HTTPRoutes(namespace string) HTTPRouteNamespaceLister
|
||||
HTTPRouteListerExpansion
|
||||
}
|
||||
|
||||
// hTTPRouteLister implements the HTTPRouteLister interface.
|
||||
type hTTPRouteLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewHTTPRouteLister returns a new HTTPRouteLister.
|
||||
func NewHTTPRouteLister(indexer cache.Indexer) HTTPRouteLister {
|
||||
return &hTTPRouteLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all HTTPRoutes in the indexer.
|
||||
func (s *hTTPRouteLister) List(selector labels.Selector) (ret []*v1beta1.HTTPRoute, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.HTTPRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// HTTPRoutes returns an object that can list and get HTTPRoutes.
|
||||
func (s *hTTPRouteLister) HTTPRoutes(namespace string) HTTPRouteNamespaceLister {
|
||||
return hTTPRouteNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// HTTPRouteNamespaceLister helps list and get HTTPRoutes.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type HTTPRouteNamespaceLister interface {
|
||||
// List lists all HTTPRoutes in the indexer for a given namespace.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1beta1.HTTPRoute, err error)
|
||||
// Get retrieves the HTTPRoute from the indexer for a given namespace and name.
|
||||
// Objects returned here must be treated as read-only.
|
||||
Get(name string) (*v1beta1.HTTPRoute, error)
|
||||
HTTPRouteNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// hTTPRouteNamespaceLister implements the HTTPRouteNamespaceLister
|
||||
// interface.
|
||||
type hTTPRouteNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all HTTPRoutes in the indexer for a given namespace.
|
||||
func (s hTTPRouteNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.HTTPRoute, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.HTTPRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the HTTPRoute from the indexer for a given namespace and name.
|
||||
func (s hTTPRouteNamespaceLister) Get(name string) (*v1beta1.HTTPRoute, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1beta1.Resource("httproute"), name)
|
||||
}
|
||||
return obj.(*v1beta1.HTTPRoute), nil
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bo
|
||||
}
|
||||
|
||||
if metadata {
|
||||
fields = alertMetadata(canary)
|
||||
fields = append(fields, alertMetadata(canary)...)
|
||||
}
|
||||
|
||||
// send alert with the global notifier
|
||||
|
||||
@@ -193,13 +193,20 @@ func (factory *Factory) MeshRouter(provider string, labelSelector string) Interf
|
||||
kubeClient: factory.kubeClient,
|
||||
kumaClient: factory.meshClient,
|
||||
}
|
||||
case strings.HasPrefix(provider, flaggerv1.GatewayAPIProvider):
|
||||
case strings.HasPrefix(provider, flaggerv1.GatewayAPIProvider+":v1alpha2"):
|
||||
return &GatewayAPIRouter{
|
||||
logger: factory.logger,
|
||||
kubeClient: factory.kubeClient,
|
||||
gatewayAPIClient: factory.meshClient,
|
||||
setOwnerRefs: factory.setOwnerRefs,
|
||||
}
|
||||
case strings.HasPrefix(provider, flaggerv1.GatewayAPIProvider+":v1beta1"):
|
||||
return &GatewayAPIV1Beta1Router{
|
||||
logger: factory.logger,
|
||||
kubeClient: factory.kubeClient,
|
||||
gatewayAPIClient: factory.meshClient,
|
||||
setOwnerRefs: factory.setOwnerRefs,
|
||||
}
|
||||
case provider == flaggerv1.KubernetesProvider:
|
||||
return &NopRouter{}
|
||||
default:
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
clientset "github.com/fluxcd/flagger/pkg/client/clientset/versioned"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -85,7 +86,7 @@ func (gwr *GatewayAPIRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
httpRouteSpec := v1alpha2.HTTPRouteSpec{
|
||||
CommonRouteSpec: v1alpha2.CommonRouteSpec{
|
||||
ParentRefs: canary.Spec.Service.GatewayRefs,
|
||||
ParentRefs: toV1alpha2ParentRefs(canary.Spec.Service.GatewayRefs),
|
||||
},
|
||||
Hostnames: hostNames,
|
||||
Rules: []v1alpha2.HTTPRouteRule{
|
||||
@@ -249,7 +250,7 @@ func (gwr *GatewayAPIRouter) SetRoutes(
|
||||
}
|
||||
httpRouteSpec := v1alpha2.HTTPRouteSpec{
|
||||
CommonRouteSpec: v1alpha2.CommonRouteSpec{
|
||||
ParentRefs: canary.Spec.Service.GatewayRefs,
|
||||
ParentRefs: toV1alpha2ParentRefs(canary.Spec.Service.GatewayRefs),
|
||||
},
|
||||
Hostnames: hostNames,
|
||||
Rules: []v1alpha2.HTTPRouteRule{
|
||||
@@ -405,3 +406,18 @@ func (gwr *GatewayAPIRouter) mergeMatchConditions(analysis, service []v1alpha2.H
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
func toV1alpha2ParentRefs(gatewayRefs []v1beta1.ParentReference) []v1alpha2.ParentReference {
|
||||
parentRefs := make([]v1alpha2.ParentReference, 0)
|
||||
for i := 0; i < len(gatewayRefs); i++ {
|
||||
gatewayRef := gatewayRefs[i]
|
||||
parentRefs = append(parentRefs, v1alpha2.ParentReference{
|
||||
Group: (*v1alpha2.Group)(gatewayRef.Group),
|
||||
Kind: (*v1alpha2.Kind)(gatewayRef.Kind),
|
||||
Namespace: (*v1alpha2.Namespace)(gatewayRef.Namespace),
|
||||
Name: (v1alpha2.ObjectName)(gatewayRef.Name),
|
||||
SectionName: (*v1alpha2.SectionName)(gatewayRef.SectionName),
|
||||
})
|
||||
}
|
||||
return parentRefs
|
||||
}
|
||||
|
||||
402
pkg/router/gateway_api_v1beta1.go
Normal file
402
pkg/router/gateway_api_v1beta1.go
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
clientset "github.com/fluxcd/flagger/pkg/client/clientset/versioned"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"go.uber.org/zap"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
var (
|
||||
v1beta1PathMatchType = v1beta1.PathMatchPathPrefix
|
||||
v1beta1PathMatchRegex = v1beta1.PathMatchRegularExpression
|
||||
v1beta1PathMatchExact = v1beta1.PathMatchExact
|
||||
v1beta1PathMatchPrefix = v1beta1.PathMatchPathPrefix
|
||||
v1beta1HeaderMatchExact = v1beta1.HeaderMatchExact
|
||||
v1beta1HeaderMatchRegex = v1beta1.HeaderMatchRegularExpression
|
||||
v1beta1QueryMatchExact = v1beta1.QueryParamMatchExact
|
||||
v1beta1QueryMatchRegex = v1beta1.QueryParamMatchRegularExpression
|
||||
)
|
||||
|
||||
type GatewayAPIV1Beta1Router struct {
|
||||
gatewayAPIClient clientset.Interface
|
||||
kubeClient kubernetes.Interface
|
||||
logger *zap.SugaredLogger
|
||||
setOwnerRefs bool
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) Reconcile(canary *flaggerv1.Canary) error {
|
||||
if len(canary.Spec.Service.GatewayRefs) == 0 {
|
||||
return fmt.Errorf("GatewayRefs must be specified when using Gateway API as a provider.")
|
||||
}
|
||||
|
||||
apexSvcName, primarySvcName, canarySvcName := canary.GetServiceNames()
|
||||
|
||||
hrNamespace := canary.Namespace
|
||||
|
||||
var hostNames []v1beta1.Hostname
|
||||
for _, host := range canary.Spec.Service.Hosts {
|
||||
hostNames = append(hostNames, v1beta1.Hostname(host))
|
||||
}
|
||||
matches, err := gwr.mapRouteMatches(canary.Spec.Service.Match)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid request matching selectors: %w", err)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
matches = append(matches, v1beta1.HTTPRouteMatch{
|
||||
Path: &v1beta1.HTTPPathMatch{
|
||||
Type: &v1beta1PathMatchType,
|
||||
Value: &pathMatchValue,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
httpRouteSpec := v1beta1.HTTPRouteSpec{
|
||||
CommonRouteSpec: v1beta1.CommonRouteSpec{
|
||||
ParentRefs: canary.Spec.Service.GatewayRefs,
|
||||
},
|
||||
Hostnames: hostNames,
|
||||
Rules: []v1beta1.HTTPRouteRule{
|
||||
{
|
||||
Matches: matches,
|
||||
BackendRefs: []v1beta1.HTTPBackendRef{
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(primarySvcName, initialPrimaryWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(canarySvcName, initialCanaryWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// A/B testing
|
||||
if len(canary.GetAnalysis().Match) > 0 {
|
||||
analysisMatches, _ := gwr.mapRouteMatches(canary.GetAnalysis().Match)
|
||||
// serviceMatches, _ := gwr.mapRouteMatches(canary.Spec.Service.Match)
|
||||
httpRouteSpec.Rules[0].Matches = gwr.mergeMatchConditions(analysisMatches, matches)
|
||||
httpRouteSpec.Rules = append(httpRouteSpec.Rules, v1beta1.HTTPRouteRule{
|
||||
Matches: matches,
|
||||
BackendRefs: []v1beta1.HTTPBackendRef{
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(primarySvcName, initialPrimaryWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
httpRoute, err := gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).Get(
|
||||
context.TODO(), apexSvcName, metav1.GetOptions{},
|
||||
)
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
metadata := canary.Spec.Service.Apex
|
||||
if metadata == nil {
|
||||
metadata = &flaggerv1.CustomMetadata{}
|
||||
}
|
||||
if metadata.Labels == nil {
|
||||
metadata.Labels = make(map[string]string)
|
||||
}
|
||||
if metadata.Annotations == nil {
|
||||
metadata.Annotations = make(map[string]string)
|
||||
}
|
||||
route := &v1beta1.HTTPRoute{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: apexSvcName,
|
||||
Namespace: hrNamespace,
|
||||
Labels: metadata.Labels,
|
||||
Annotations: filterMetadata(metadata.Annotations),
|
||||
},
|
||||
Spec: httpRouteSpec,
|
||||
}
|
||||
|
||||
if gwr.setOwnerRefs {
|
||||
route.OwnerReferences = []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
|
||||
Group: flaggerv1.SchemeGroupVersion.Group,
|
||||
Version: flaggerv1.SchemeGroupVersion.Version,
|
||||
Kind: flaggerv1.CanaryKind,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
_, err := gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).
|
||||
Create(context.TODO(), route, metav1.CreateOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPRoute %s.%s create error: %w", apexSvcName, hrNamespace, err)
|
||||
}
|
||||
gwr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("HTTPRoute %s.%s created", route.GetName(), hrNamespace)
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("HTTPRoute %s.%s get error: %w", apexSvcName, hrNamespace, err)
|
||||
}
|
||||
|
||||
if httpRoute != nil {
|
||||
diff := cmp.Diff(
|
||||
httpRoute.Spec, httpRouteSpec,
|
||||
cmpopts.IgnoreFields(v1beta1.BackendRef{}, "Weight"),
|
||||
)
|
||||
if diff != "" && httpRoute.Name != "" {
|
||||
hrClone := httpRoute.DeepCopy()
|
||||
hrClone.Spec = httpRouteSpec
|
||||
_, err := gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).
|
||||
Update(context.TODO(), hrClone, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPRoute %s.%s update error: %w while reconciling", hrClone.GetName(), hrNamespace, err)
|
||||
}
|
||||
gwr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("HTTPRoute %s.%s updated", hrClone.GetName(), hrNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) GetRoutes(canary *flaggerv1.Canary) (
|
||||
primaryWeight int,
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
apexSvcName, primarySvcName, canarySvcName := canary.GetServiceNames()
|
||||
hrNamespace := canary.Namespace
|
||||
httpRoute, err := gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).Get(context.TODO(), apexSvcName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("HTTPRoute %s.%s get error: %w", apexSvcName, hrNamespace, err)
|
||||
return
|
||||
}
|
||||
for _, rule := range httpRoute.Spec.Rules {
|
||||
// A/B testing: Avoid reading the rule with only for backendRef.
|
||||
if len(rule.BackendRefs) == 2 {
|
||||
for _, backendRef := range rule.BackendRefs {
|
||||
if backendRef.Name == v1beta1.ObjectName(primarySvcName) {
|
||||
primaryWeight = int(*backendRef.Weight)
|
||||
}
|
||||
if backendRef.Name == v1beta1.ObjectName(canarySvcName) {
|
||||
canaryWeight = int(*backendRef.Weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) SetRoutes(
|
||||
canary *flaggerv1.Canary,
|
||||
primaryWeight int,
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
pWeight := int32(primaryWeight)
|
||||
cWeight := int32(canaryWeight)
|
||||
apexSvcName, primarySvcName, canarySvcName := canary.GetServiceNames()
|
||||
hrNamespace := canary.Namespace
|
||||
httpRoute, err := gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).Get(context.TODO(), apexSvcName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPRoute %s.%s get error: %w", apexSvcName, hrNamespace, err)
|
||||
}
|
||||
hrClone := httpRoute.DeepCopy()
|
||||
hostNames := []v1beta1.Hostname{}
|
||||
for _, host := range canary.Spec.Service.Hosts {
|
||||
hostNames = append(hostNames, v1beta1.Hostname(host))
|
||||
}
|
||||
matches, err := gwr.mapRouteMatches(canary.Spec.Service.Match)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid request matching selectors: %w", err)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
matches = append(matches, v1beta1.HTTPRouteMatch{
|
||||
Path: &v1beta1.HTTPPathMatch{
|
||||
Type: &v1beta1PathMatchType,
|
||||
Value: &pathMatchValue,
|
||||
},
|
||||
})
|
||||
}
|
||||
httpRouteSpec := v1beta1.HTTPRouteSpec{
|
||||
CommonRouteSpec: v1beta1.CommonRouteSpec{
|
||||
ParentRefs: canary.Spec.Service.GatewayRefs,
|
||||
},
|
||||
Hostnames: hostNames,
|
||||
Rules: []v1beta1.HTTPRouteRule{
|
||||
{
|
||||
Matches: matches,
|
||||
BackendRefs: []v1beta1.HTTPBackendRef{
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(primarySvcName, pWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(canarySvcName, cWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
hrClone.Spec = httpRouteSpec
|
||||
|
||||
// A/B testing
|
||||
if len(canary.GetAnalysis().Match) > 0 {
|
||||
analysisMatches, _ := gwr.mapRouteMatches(canary.GetAnalysis().Match)
|
||||
hrClone.Spec.Rules[0].Matches = gwr.mergeMatchConditions(analysisMatches, matches)
|
||||
hrClone.Spec.Rules = append(hrClone.Spec.Rules, v1beta1.HTTPRouteRule{
|
||||
Matches: matches,
|
||||
BackendRefs: []v1beta1.HTTPBackendRef{
|
||||
{
|
||||
BackendRef: gwr.makeBackendRef(primarySvcName, initialPrimaryWeight, canary.Spec.Service.Port),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_, err = gwr.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes(hrNamespace).Update(context.TODO(), hrClone, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPRoute %s.%s update error: %w while setting weights", hrClone.GetName(), hrNamespace, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) Finalize(_ *flaggerv1.Canary) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) mapRouteMatches(requestMatches []v1alpha3.HTTPMatchRequest) ([]v1beta1.HTTPRouteMatch, error) {
|
||||
matches := []v1beta1.HTTPRouteMatch{}
|
||||
|
||||
for _, requestMatch := range requestMatches {
|
||||
match := v1beta1.HTTPRouteMatch{}
|
||||
if requestMatch.Uri != nil {
|
||||
if requestMatch.Uri.Regex != "" {
|
||||
match.Path = &v1beta1.HTTPPathMatch{
|
||||
Type: &v1beta1PathMatchRegex,
|
||||
Value: &requestMatch.Uri.Regex,
|
||||
}
|
||||
} else if requestMatch.Uri.Exact != "" {
|
||||
match.Path = &v1beta1.HTTPPathMatch{
|
||||
Type: &v1beta1PathMatchExact,
|
||||
Value: &requestMatch.Uri.Exact,
|
||||
}
|
||||
} else if requestMatch.Uri.Prefix != "" {
|
||||
match.Path = &v1beta1.HTTPPathMatch{
|
||||
Type: &v1beta1PathMatchPrefix,
|
||||
Value: &requestMatch.Uri.Prefix,
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Gateway API doesn't support the specified path matching selector: %+v\n", requestMatch.Uri)
|
||||
}
|
||||
}
|
||||
if requestMatch.Method != nil {
|
||||
if requestMatch.Method.Exact != "" {
|
||||
method := v1beta1.HTTPMethod(requestMatch.Method.Exact)
|
||||
match.Method = &method
|
||||
} else {
|
||||
return nil, fmt.Errorf("Gateway API doesn't support the specified header matching selector: %+v\n", requestMatch.Headers)
|
||||
}
|
||||
}
|
||||
for key, val := range requestMatch.Headers {
|
||||
headerMatch := v1beta1.HTTPHeaderMatch{}
|
||||
if val.Exact != "" {
|
||||
headerMatch.Name = v1beta1.HTTPHeaderName(key)
|
||||
headerMatch.Type = &v1beta1HeaderMatchExact
|
||||
headerMatch.Value = val.Exact
|
||||
} else if val.Regex != "" {
|
||||
headerMatch.Name = v1beta1.HTTPHeaderName(key)
|
||||
headerMatch.Type = &v1beta1HeaderMatchRegex
|
||||
headerMatch.Value = val.Regex
|
||||
} else {
|
||||
return nil, fmt.Errorf("Gateway API doesn't support the specified header matching selector: %+v\n", requestMatch.Headers)
|
||||
}
|
||||
if (v1beta1.HTTPHeaderMatch{} != headerMatch) {
|
||||
match.Headers = append(match.Headers, headerMatch)
|
||||
}
|
||||
}
|
||||
|
||||
for key, val := range requestMatch.QueryParams {
|
||||
queryMatch := v1beta1.HTTPQueryParamMatch{}
|
||||
if val.Exact != "" {
|
||||
queryMatch.Name = key
|
||||
queryMatch.Type = &v1beta1QueryMatchExact
|
||||
queryMatch.Value = val.Exact
|
||||
} else if val.Regex != "" {
|
||||
queryMatch.Name = key
|
||||
queryMatch.Type = &v1beta1QueryMatchRegex
|
||||
queryMatch.Value = val.Regex
|
||||
} else {
|
||||
return nil, fmt.Errorf("Gateway API doesn't support the specified query matching selector: %+v\n", requestMatch.QueryParams)
|
||||
}
|
||||
|
||||
if (v1beta1.HTTPQueryParamMatch{} != queryMatch) {
|
||||
match.QueryParams = append(match.QueryParams, queryMatch)
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(match, v1beta1.HTTPRouteMatch{}) {
|
||||
matches = append(matches, match)
|
||||
}
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) makeBackendRef(svcName string, weight, port int32) v1beta1.BackendRef {
|
||||
return v1beta1.BackendRef{
|
||||
BackendObjectReference: v1beta1.BackendObjectReference{
|
||||
Group: (*v1beta1.Group)(&backendRefGroup),
|
||||
Kind: (*v1beta1.Kind)(&backendRefKind),
|
||||
Name: v1beta1.ObjectName(svcName),
|
||||
Port: (*v1beta1.PortNumber)(&port),
|
||||
},
|
||||
Weight: &weight,
|
||||
}
|
||||
}
|
||||
|
||||
func (gwr *GatewayAPIV1Beta1Router) mergeMatchConditions(analysis, service []v1beta1.HTTPRouteMatch) []v1beta1.HTTPRouteMatch {
|
||||
if len(analysis) == 0 {
|
||||
return service
|
||||
}
|
||||
|
||||
merged := make([]v1beta1.HTTPRouteMatch, len(service)*len(analysis))
|
||||
num := 0
|
||||
for _, a := range analysis {
|
||||
for _, s := range service {
|
||||
merged[num] = *s.DeepCopy()
|
||||
if len(a.Headers) > 0 {
|
||||
merged[num].Headers = a.Headers
|
||||
}
|
||||
if len(a.QueryParams) > 0 {
|
||||
merged[num].QueryParams = a.QueryParams
|
||||
}
|
||||
num++
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
72
pkg/router/gateway_api_v1beta1_test.go
Normal file
72
pkg/router/gateway_api_v1beta1_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestGatewayAPIV1Beta1Router_Reconcile(t *testing.T) {
|
||||
canary := newTestGatewayAPICanary()
|
||||
mocks := newFixture(canary)
|
||||
router := &GatewayAPIV1Beta1Router{
|
||||
gatewayAPIClient: mocks.meshClient,
|
||||
kubeClient: mocks.kubeClient,
|
||||
logger: mocks.logger,
|
||||
}
|
||||
|
||||
err := router.Reconcile(canary)
|
||||
require.NoError(t, err)
|
||||
|
||||
httpRoute, err := router.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
routeRules := httpRoute.Spec.Rules
|
||||
require.Equal(t, len(routeRules), 1)
|
||||
|
||||
backendRefs := routeRules[0].BackendRefs
|
||||
require.Equal(t, len(backendRefs), 2)
|
||||
assert.Equal(t, int32(100), *backendRefs[0].Weight)
|
||||
assert.Equal(t, int32(0), *backendRefs[1].Weight)
|
||||
}
|
||||
|
||||
func TestGatewayAPIV1Beta1Router_Routes(t *testing.T) {
|
||||
canary := newTestGatewayAPICanary()
|
||||
mocks := newFixture(canary)
|
||||
router := &GatewayAPIV1Beta1Router{
|
||||
gatewayAPIClient: mocks.meshClient,
|
||||
kubeClient: mocks.kubeClient,
|
||||
logger: mocks.logger,
|
||||
}
|
||||
|
||||
err := router.Reconcile(canary)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.SetRoutes(canary, 50, 50, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
httpRoute, err := router.gatewayAPIClient.GatewayapiV1beta1().HTTPRoutes("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
primary := httpRoute.Spec.Rules[0].BackendRefs[0]
|
||||
assert.Equal(t, int32(50), *primary.Weight)
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
@@ -30,6 +32,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
istiov1alpha1 "github.com/fluxcd/flagger/pkg/apis/istio/common/v1alpha1"
|
||||
istiov1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
clientset "github.com/fluxcd/flagger/pkg/client/clientset/versioned"
|
||||
)
|
||||
@@ -43,6 +46,13 @@ type IstioRouter struct {
|
||||
setOwnerRefs bool
|
||||
}
|
||||
|
||||
const cookieHeader = "Cookie"
|
||||
const setCookieHeader = "Set-Cookie"
|
||||
const stickyRouteName = "sticky-route"
|
||||
const maxAgeAttr = "Max-Age"
|
||||
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
// Reconcile creates or updates the Istio virtual service and destination rules
|
||||
func (ir *IstioRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
_, primaryName, canaryName := canary.GetServiceNames()
|
||||
@@ -153,7 +163,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
// create destinations with primary weight 100% and canary weight 0%
|
||||
canaryRoute := []istiov1alpha3.DestinationWeight{
|
||||
canaryRoute := []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, 100),
|
||||
makeDestination(canary, canaryName, 0),
|
||||
}
|
||||
@@ -199,7 +209,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
Retries: canary.Spec.Service.Retries,
|
||||
CorsPolicy: canary.Spec.Service.CorsPolicy,
|
||||
Headers: canary.Spec.Service.Headers,
|
||||
Route: []istiov1alpha3.DestinationWeight{
|
||||
Route: []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, 100),
|
||||
},
|
||||
},
|
||||
@@ -255,13 +265,28 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
virtualService.Spec.Hosts = []string{}
|
||||
}
|
||||
|
||||
ignoreCmpOptions := []cmp.Option{
|
||||
cmpopts.IgnoreFields(istiov1alpha3.HTTPRouteDestination{}, "Weight"),
|
||||
cmpopts.IgnoreFields(istiov1alpha3.HTTPRoute{}, "Mirror", "MirrorPercentage"),
|
||||
}
|
||||
if canary.Spec.Analysis.SessionAffinity != nil {
|
||||
// We ignore this route as this does not do weighted routing and is handled exclusively
|
||||
// by SetRoutes().
|
||||
ignoreSlice := cmpopts.IgnoreSliceElements(func(t istiov1alpha3.HTTPRoute) bool {
|
||||
if t.Name == stickyRouteName {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
ignoreCmpOptions = append(ignoreCmpOptions, ignoreSlice)
|
||||
ignoreCmpOptions = append(ignoreCmpOptions, cmpopts.IgnoreFields(istiov1alpha3.HTTPRouteDestination{}, "Headers"))
|
||||
}
|
||||
// update service but keep the original destination weights and mirror
|
||||
if virtualService != nil {
|
||||
if diff := cmp.Diff(
|
||||
newSpec,
|
||||
virtualService.Spec,
|
||||
cmpopts.IgnoreFields(istiov1alpha3.DestinationWeight{}, "Weight"),
|
||||
cmpopts.IgnoreFields(istiov1alpha3.HTTPRoute{}, "Mirror", "MirrorPercentage"),
|
||||
ignoreCmpOptions...,
|
||||
); diff != "" {
|
||||
vtClone := virtualService.DeepCopy()
|
||||
vtClone.Spec = newSpec
|
||||
@@ -333,6 +358,23 @@ func (ir *IstioRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored = true
|
||||
}
|
||||
|
||||
if canary.Spec.Analysis.SessionAffinity != nil {
|
||||
for _, http := range vs.Spec.Http {
|
||||
for _, routeDest := range http.Route {
|
||||
// we are interested in the route that sets the cookie as that's the route
|
||||
// that does weighted routing.
|
||||
if routeDest.Headers != nil {
|
||||
if routeDest.Destination.Host == primaryName {
|
||||
primaryWeight = routeDest.Weight
|
||||
}
|
||||
if routeDest.Destination.Host == canaryName {
|
||||
canaryWeight = routeDest.Weight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
err = fmt.Errorf("VirtualService %s.%s does not contain routes for %s-primary and %s-canary",
|
||||
apexName, canary.Namespace, apexName, apexName)
|
||||
@@ -358,20 +400,103 @@ func (ir *IstioRouter) SetRoutes(
|
||||
vsCopy := vs.DeepCopy()
|
||||
|
||||
// weighted routing (progressive canary)
|
||||
vsCopy.Spec.Http = []istiov1alpha3.HTTPRoute{
|
||||
{
|
||||
Match: canary.Spec.Service.Match,
|
||||
Rewrite: canary.Spec.Service.Rewrite,
|
||||
Timeout: canary.Spec.Service.Timeout,
|
||||
Retries: canary.Spec.Service.Retries,
|
||||
CorsPolicy: canary.Spec.Service.CorsPolicy,
|
||||
Headers: canary.Spec.Service.Headers,
|
||||
Route: []istiov1alpha3.DestinationWeight{
|
||||
makeDestination(canary, primaryName, primaryWeight),
|
||||
makeDestination(canary, canaryName, canaryWeight),
|
||||
},
|
||||
weightedRoute := istiov1alpha3.HTTPRoute{
|
||||
Match: canary.Spec.Service.Match,
|
||||
Rewrite: canary.Spec.Service.Rewrite,
|
||||
Timeout: canary.Spec.Service.Timeout,
|
||||
Retries: canary.Spec.Service.Retries,
|
||||
CorsPolicy: canary.Spec.Service.CorsPolicy,
|
||||
Headers: canary.Spec.Service.Headers,
|
||||
Route: []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, primaryWeight),
|
||||
makeDestination(canary, canaryName, canaryWeight),
|
||||
},
|
||||
}
|
||||
vsCopy.Spec.Http = []istiov1alpha3.HTTPRoute{
|
||||
weightedRoute,
|
||||
}
|
||||
|
||||
if canary.Spec.Analysis.SessionAffinity != nil {
|
||||
// If a canary run is active, we want all responses corresponding to requests hitting the canary deployment
|
||||
// (due to weighted routing) to include a `Set-Cookie` header. All requests that have the `Cookie` header
|
||||
// and match the value of the `Set-Cookie` header will be routed to the canary deployment.
|
||||
stickyRoute := weightedRoute
|
||||
stickyRoute.Name = stickyRouteName
|
||||
if canaryWeight != 0 {
|
||||
if canary.Status.SessionAffinityCookie == "" {
|
||||
canary.Status.SessionAffinityCookie = fmt.Sprintf("%s=%s", canary.Spec.Analysis.SessionAffinity.CookieName, randSeq())
|
||||
}
|
||||
|
||||
for i, routeDest := range weightedRoute.Route {
|
||||
if routeDest.Destination.Host == canaryName {
|
||||
if routeDest.Headers == nil {
|
||||
routeDest.Headers = &istiov1alpha3.Headers{
|
||||
Response: &istiov1alpha3.HeaderOperations{},
|
||||
}
|
||||
}
|
||||
routeDest.Headers.Response.Add = map[string]string{
|
||||
setCookieHeader: fmt.Sprintf("%s; %s=%d", canary.Status.SessionAffinityCookie, maxAgeAttr,
|
||||
canary.Spec.Analysis.SessionAffinity.GetMaxAge(),
|
||||
),
|
||||
}
|
||||
}
|
||||
weightedRoute.Route[i] = routeDest
|
||||
}
|
||||
|
||||
cookieMatch := istiov1alpha3.HTTPMatchRequest{
|
||||
Headers: map[string]istiov1alpha1.StringMatch{
|
||||
cookieHeader: {
|
||||
Exact: canary.Status.SessionAffinityCookie,
|
||||
},
|
||||
},
|
||||
}
|
||||
canaryMatch := mergeMatchConditions([]istiov1alpha3.HTTPMatchRequest{cookieMatch}, canary.Spec.Service.Match)
|
||||
stickyRoute.Match = canaryMatch
|
||||
stickyRoute.Route = []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, 0),
|
||||
makeDestination(canary, canaryName, 100),
|
||||
}
|
||||
} else {
|
||||
// If canary weight is 0 and SessionAffinityCookie is non-blank, then it belongs to a previous canary run.
|
||||
if canary.Status.SessionAffinityCookie != "" {
|
||||
canary.Status.PreviousSessionAffinityCookie = canary.Status.SessionAffinityCookie
|
||||
}
|
||||
previousCookie := canary.Status.PreviousSessionAffinityCookie
|
||||
|
||||
// Match against the previous session cookie and delete that cookie
|
||||
if previousCookie != "" {
|
||||
cookieMatch := istiov1alpha3.HTTPMatchRequest{
|
||||
Headers: map[string]istiov1alpha1.StringMatch{
|
||||
cookieHeader: {
|
||||
Exact: previousCookie,
|
||||
},
|
||||
},
|
||||
}
|
||||
canaryMatch := mergeMatchConditions([]istiov1alpha3.HTTPMatchRequest{cookieMatch}, canary.Spec.Service.Match)
|
||||
stickyRoute.Match = canaryMatch
|
||||
|
||||
if stickyRoute.Headers == nil {
|
||||
stickyRoute.Headers = &istiov1alpha3.Headers{
|
||||
Response: &istiov1alpha3.HeaderOperations{
|
||||
Add: map[string]string{},
|
||||
},
|
||||
}
|
||||
} else if stickyRoute.Headers.Response == nil {
|
||||
stickyRoute.Headers.Response = &istiov1alpha3.HeaderOperations{
|
||||
Add: map[string]string{},
|
||||
}
|
||||
} else if stickyRoute.Headers.Response.Add == nil {
|
||||
stickyRoute.Headers.Response.Add = map[string]string{}
|
||||
}
|
||||
stickyRoute.Headers.Response.Add[setCookieHeader] = fmt.Sprintf("%s; %s=%d", previousCookie, maxAgeAttr, -1)
|
||||
}
|
||||
|
||||
canary.Status.SessionAffinityCookie = ""
|
||||
}
|
||||
vsCopy.Spec.Http = []istiov1alpha3.HTTPRoute{
|
||||
stickyRoute, weightedRoute,
|
||||
}
|
||||
}
|
||||
|
||||
if mirrored {
|
||||
vsCopy.Spec.Http[0].Mirror = &istiov1alpha3.Destination{
|
||||
@@ -395,7 +520,7 @@ func (ir *IstioRouter) SetRoutes(
|
||||
Retries: canary.Spec.Service.Retries,
|
||||
CorsPolicy: canary.Spec.Service.CorsPolicy,
|
||||
Headers: canary.Spec.Service.Headers,
|
||||
Route: []istiov1alpha3.DestinationWeight{
|
||||
Route: []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, primaryWeight),
|
||||
makeDestination(canary, canaryName, canaryWeight),
|
||||
},
|
||||
@@ -407,7 +532,7 @@ func (ir *IstioRouter) SetRoutes(
|
||||
Retries: canary.Spec.Service.Retries,
|
||||
CorsPolicy: canary.Spec.Service.CorsPolicy,
|
||||
Headers: canary.Spec.Service.Headers,
|
||||
Route: []istiov1alpha3.DestinationWeight{
|
||||
Route: []istiov1alpha3.HTTPRouteDestination{
|
||||
makeDestination(canary, primaryName, primaryWeight),
|
||||
},
|
||||
},
|
||||
@@ -483,8 +608,8 @@ func mergeMatchConditions(canary, defaults []istiov1alpha3.HTTPMatchRequest) []i
|
||||
}
|
||||
|
||||
// makeDestination returns a an destination weight for the specified host
|
||||
func makeDestination(canary *flaggerv1.Canary, host string, weight int) istiov1alpha3.DestinationWeight {
|
||||
dest := istiov1alpha3.DestinationWeight{
|
||||
func makeDestination(canary *flaggerv1.Canary, host string, weight int) istiov1alpha3.HTTPRouteDestination {
|
||||
dest := istiov1alpha3.HTTPRouteDestination{
|
||||
Destination: istiov1alpha3.Destination{
|
||||
Host: host,
|
||||
},
|
||||
@@ -495,7 +620,7 @@ func makeDestination(canary *flaggerv1.Canary, host string, weight int) istiov1a
|
||||
if canary.Spec.Service.PortDiscovery &&
|
||||
(len(canary.Spec.Service.Gateways) > 0 &&
|
||||
canary.Spec.Service.Gateways[0] != "mesh" || canary.Spec.Service.Delegation) {
|
||||
dest = istiov1alpha3.DestinationWeight{
|
||||
dest = istiov1alpha3.HTTPRouteDestination{
|
||||
Destination: istiov1alpha3.Destination{
|
||||
Host: host,
|
||||
Port: &istiov1alpha3.PortSelector{
|
||||
@@ -508,3 +633,13 @@ func makeDestination(canary *flaggerv1.Canary, host string, weight int) istiov1a
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
func randSeq() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
b := make([]rune, 10)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -122,7 +124,7 @@ func TestIstioRouter_SetRoutes(t *testing.T) {
|
||||
vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
var pRoute, cRoute istiov1alpha3.DestinationWeight
|
||||
var pRoute, cRoute istiov1alpha3.HTTPRouteDestination
|
||||
var mirror *istiov1alpha3.Destination
|
||||
for _, http := range vs.Spec.Http {
|
||||
for _, route := range http.Route {
|
||||
@@ -142,6 +144,164 @@ func TestIstioRouter_SetRoutes(t *testing.T) {
|
||||
|
||||
})
|
||||
|
||||
t.Run("session affinity", func(t *testing.T) {
|
||||
canary := mocks.canary.DeepCopy()
|
||||
cookieKey := "flagger-cookie"
|
||||
// enable session affinity and start canary run
|
||||
canary.Spec.Analysis.SessionAffinity = &v1beta1.SessionAffinity{
|
||||
CookieName: cookieKey,
|
||||
MaxAge: 300,
|
||||
}
|
||||
err := router.SetRoutes(canary, 0, 10, false)
|
||||
|
||||
vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, vs.Spec.Http, 2)
|
||||
stickyRoute := vs.Spec.Http[0]
|
||||
weightedRoute := vs.Spec.Http[1]
|
||||
|
||||
// stickyRoute should match against a cookie and direct all traffic to the canary when a canary run is active.
|
||||
var found bool
|
||||
for _, match := range stickyRoute.Match {
|
||||
if val, ok := match.Headers[cookieHeader]; ok {
|
||||
found = true
|
||||
assert.True(t, strings.HasPrefix(val.Exact, cookieKey))
|
||||
for _, routeDest := range stickyRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 0, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 100, routeDest.Weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
|
||||
// weightedRoute should do regular weight based routing and inject the Set-Cookie header
|
||||
// for all responses returned from the canary deployment.
|
||||
for _, routeDest := range weightedRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 0, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 10, routeDest.Weight)
|
||||
val, ok := routeDest.Headers.Response.Add[setCookieHeader]
|
||||
assert.True(t, ok)
|
||||
assert.True(t, strings.HasPrefix(val, cookieKey))
|
||||
assert.True(t, strings.Contains(val, "Max-Age=300"))
|
||||
}
|
||||
}
|
||||
assert.True(t, strings.HasPrefix(canary.Status.SessionAffinityCookie, cookieKey))
|
||||
|
||||
// reconcile canary, destination rules, virtual services
|
||||
err = router.Reconcile(canary)
|
||||
require.NoError(t, err)
|
||||
|
||||
reconciledVS, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// routes should not be changed.
|
||||
assert.Len(t, vs.Spec.Http, 2)
|
||||
assert.NotNil(t, reconciledVS)
|
||||
assert.Equal(t, cmp.Diff(reconciledVS.Spec.Http[0], stickyRoute), "")
|
||||
assert.Equal(t, cmp.Diff(reconciledVS.Spec.Http[1], weightedRoute), "")
|
||||
|
||||
// further continue the canary run
|
||||
err = router.SetRoutes(canary, 50, 50, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
vs, err = mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, vs.Spec.Http, 2)
|
||||
stickyRoute = vs.Spec.Http[0]
|
||||
weightedRoute = vs.Spec.Http[1]
|
||||
|
||||
found = false
|
||||
for _, match := range stickyRoute.Match {
|
||||
if val, ok := match.Headers[cookieHeader]; ok {
|
||||
found = true
|
||||
assert.True(t, strings.HasPrefix(val.Exact, cookieKey))
|
||||
for _, routeDest := range stickyRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 0, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 100, routeDest.Weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
|
||||
for _, routeDest := range weightedRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 50, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 50, routeDest.Weight)
|
||||
val, ok := routeDest.Headers.Response.Add[setCookieHeader]
|
||||
assert.True(t, ok)
|
||||
assert.True(t, strings.HasPrefix(val, cookieKey))
|
||||
assert.True(t, strings.Contains(val, "Max-Age=300"))
|
||||
}
|
||||
}
|
||||
assert.True(t, strings.HasPrefix(canary.Status.SessionAffinityCookie, cookieKey))
|
||||
sessionAffinityCookie := canary.Status.SessionAffinityCookie
|
||||
|
||||
// promotion
|
||||
err = router.SetRoutes(canary, 100, 0, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
vs, err = mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, vs.Spec.Http, 2)
|
||||
stickyRoute = vs.Spec.Http[0]
|
||||
weightedRoute = vs.Spec.Http[1]
|
||||
|
||||
found = false
|
||||
for _, match := range stickyRoute.Match {
|
||||
if val, ok := match.Headers[cookieHeader]; ok {
|
||||
found = true
|
||||
assert.True(t, strings.HasPrefix(val.Exact, cookieKey))
|
||||
for _, routeDest := range stickyRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 100, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 0, routeDest.Weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
|
||||
assert.Equal(t, canary.Status.SessionAffinityCookie, "")
|
||||
assert.Equal(t, canary.Status.PreviousSessionAffinityCookie, sessionAffinityCookie)
|
||||
|
||||
val, ok := stickyRoute.Headers.Response.Add[setCookieHeader]
|
||||
assert.True(t, ok)
|
||||
assert.True(t, strings.HasPrefix(val, sessionAffinityCookie))
|
||||
assert.True(t, strings.Contains(val, "Max-Age=-1"))
|
||||
|
||||
// delete the Set-Cookie header from responses returned by the weighted route
|
||||
for _, routeDest := range weightedRoute.Route {
|
||||
if routeDest.Destination.Host == pHost {
|
||||
assert.Equal(t, 100, routeDest.Weight)
|
||||
}
|
||||
if routeDest.Destination.Host == cHost {
|
||||
assert.Equal(t, 0, routeDest.Weight)
|
||||
if routeDest.Headers != nil && routeDest.Headers.Response != nil {
|
||||
_, ok := routeDest.Headers.Response.Add[setCookieHeader]
|
||||
assert.False(t, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("mirror", func(t *testing.T) {
|
||||
for _, w := range []int{0, 10, 50} {
|
||||
p, c := 100, 0
|
||||
@@ -154,7 +314,7 @@ func TestIstioRouter_SetRoutes(t *testing.T) {
|
||||
vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
var pRoute, cRoute istiov1alpha3.DestinationWeight
|
||||
var pRoute, cRoute istiov1alpha3.HTTPRouteDestination
|
||||
var mirror *istiov1alpha3.Destination
|
||||
var mirrorWeight *istiov1alpha3.Percent
|
||||
for _, http := range vs.Spec.Http {
|
||||
@@ -310,8 +470,8 @@ func TestIstioRouter_ABTest(t *testing.T) {
|
||||
|
||||
pHost := fmt.Sprintf("%s-primary", mocks.abtest.Spec.TargetRef.Name)
|
||||
cHost := fmt.Sprintf("%s-canary", mocks.abtest.Spec.TargetRef.Name)
|
||||
pRoute := istiov1alpha3.DestinationWeight{}
|
||||
cRoute := istiov1alpha3.DestinationWeight{}
|
||||
pRoute := istiov1alpha3.HTTPRouteDestination{}
|
||||
cRoute := istiov1alpha3.HTTPRouteDestination{}
|
||||
var mirror *istiov1alpha3.Destination
|
||||
|
||||
for _, http := range vs.Spec.Http {
|
||||
@@ -427,7 +587,7 @@ func TestIstioRouter_Finalize(t *testing.T) {
|
||||
Http: []istiov1alpha3.HTTPRoute{
|
||||
{
|
||||
Match: nil,
|
||||
Route: []istiov1alpha3.DestinationWeight{
|
||||
Route: []istiov1alpha3.HTTPRouteDestination{
|
||||
{
|
||||
Destination: istiov1alpha3.Destination{Host: "podinfo"},
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
appmesh "github.com/fluxcd/flagger/pkg/apis/appmesh"
|
||||
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
"github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1alpha2"
|
||||
gatewayapiv1 "github.com/fluxcd/flagger/pkg/apis/gatewayapi/v1beta1"
|
||||
istiov1alpha1 "github.com/fluxcd/flagger/pkg/apis/istio/common/v1alpha1"
|
||||
istiov1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
|
||||
clientset "github.com/fluxcd/flagger/pkg/client/clientset/versioned"
|
||||
@@ -507,7 +507,7 @@ func newTestGatewayAPICanary() *flaggerv1.Canary {
|
||||
IntVal: 9898,
|
||||
},
|
||||
PortDiscovery: true,
|
||||
GatewayRefs: []v1alpha2.ParentReference{
|
||||
GatewayRefs: []gatewayapiv1.ParentReference{
|
||||
{
|
||||
Name: "podinfo",
|
||||
},
|
||||
|
||||
@@ -16,5 +16,5 @@ limitations under the License.
|
||||
|
||||
package version
|
||||
|
||||
var VERSION = "1.24.1"
|
||||
var VERSION = "1.26.0"
|
||||
var REVISION = "unknown"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -o errexit
|
||||
|
||||
CONTOUR_VER="v1.22.1"
|
||||
CONTOUR_VER="v1.23.0"
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
mkdir -p ${REPO_ROOT}/bin
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
set -o errexit
|
||||
|
||||
CONTOUR_VER="v1.21.0"
|
||||
GATEWAY_API_VER="v1alpha2"
|
||||
CONTOUR_VER="v1.23.0"
|
||||
GATEWAY_API_VER="v1beta1"
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
KUSTOMIZE_VERSION=4.5.2
|
||||
OS=$(uname -s)
|
||||
@@ -18,15 +18,15 @@ echo ">>> Installing Contour components, Gateway API CRDs"
|
||||
kubectl apply -f https://raw.githubusercontent.com/projectcontour/contour/${CONTOUR_VER}/examples/render/contour-gateway-provisioner.yaml
|
||||
|
||||
kubectl -n projectcontour rollout status deployment/contour-gateway-provisioner
|
||||
kubectl -n gateway-api wait --for=condition=complete job/gateway-api-admission
|
||||
kubectl -n gateway-api wait --for=condition=complete job/gateway-api-admission-patch
|
||||
kubectl -n gateway-api rollout status deployment/gateway-api-admission-server
|
||||
kubectl -n gateway-system wait --for=condition=complete job/gateway-api-admission
|
||||
kubectl -n gateway-system wait --for=condition=complete job/gateway-api-admission-patch
|
||||
kubectl -n gateway-system rollout status deployment/gateway-api-admission-server
|
||||
kubectl -n projectcontour get all
|
||||
|
||||
echo ">>> Creating GatewayClass"
|
||||
cat <<EOF | kubectl apply -f -
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: contour
|
||||
spec:
|
||||
@@ -36,7 +36,7 @@ EOF
|
||||
echo ">>> Creating Gateway"
|
||||
cat <<EOF | kubectl apply -f -
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: contour
|
||||
namespace: projectcontour
|
||||
|
||||
Reference in New Issue
Block a user