diff --git a/.gitbook.yaml b/.gitbook.yaml index 1c8ec9fc..725a7458 100644 --- a/.gitbook.yaml +++ b/.gitbook.yaml @@ -14,3 +14,4 @@ redirects: usage/crossover-progressive-delivery: tutorials/crossover-progressive-delivery.md usage/traefik-progressive-delivery: tutorials/traefik-progressive-delivery.md usage/osm-progressive-delivery: tutorials/osm-progressive-delivery.md + usage/kuma-progressive-delivery: tutorials/kuma-progressive-delivery.md diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index da3560ea..1bf56ad0 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -23,6 +23,7 @@ jobs: - gloo - skipper - osm + - kuma - kubernetes steps: - name: Checkout diff --git a/artifacts/examples/kuma-canary.yaml b/artifacts/examples/kuma-canary.yaml new file mode 100644 index 00000000..12dbb416 --- /dev/null +++ b/artifacts/examples/kuma-canary.yaml @@ -0,0 +1,50 @@ +apiVersion: flagger.app/v1beta1 +kind: Canary +metadata: + name: podinfo + namespace: test + annotations: + kuma.io/mesh: default +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: podinfo + progressDeadlineSeconds: 60 + service: + port: 9898 + targetPort: 9898 + apex: + annotations: + 9898.service.kuma.io/protocol: "http" + canary: + annotations: + 9898.service.kuma.io/protocol: "http" + primary: + annotations: + 9898.service.kuma.io/protocol: "http" + analysis: + interval: 15s + threshold: 15 + maxWeight: 50 + stepWeight: 10 + metrics: + - name: request-success-rate + threshold: 99 + interval: 1m + - name: request-duration + threshold: 500 + interval: 30s + webhooks: + - name: acceptance-test + type: pre-rollout + url: http://flagger-loadtester.test/ + timeout: 30s + metadata: + type: bash + cmd: "curl -sd 'test' http://podinfo-canary.test:9898/token | grep token" + - name: load-test + type: rollout + url: http://flagger-loadtester.test/ + metadata: + cmd: "hey -z 2m -q 10 -c 2 http://podinfo-canary.test:9898/" diff --git a/charts/flagger/templates/rbac.yaml b/charts/flagger/templates/rbac.yaml index 8f27bbf8..303aae15 100644 --- a/charts/flagger/templates/rbac.yaml +++ b/charts/flagger/templates/rbac.yaml @@ -195,6 +195,19 @@ rules: - update - patch - delete + - apiGroups: + - kuma.io + resources: + - trafficroutes + - trafficroutes/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete - nonResourceURLs: - /version verbs: diff --git a/cmd/flagger/main.go b/cmd/flagger/main.go index e26121db..8efb4cf8 100644 --- a/cmd/flagger/main.go +++ b/cmd/flagger/main.go @@ -106,7 +106,7 @@ func init() { flag.BoolVar(&zapReplaceGlobals, "zap-replace-globals", false, "Whether to change the logging level of the global zap logger.") flag.StringVar(&zapEncoding, "zap-encoding", "json", "Zap logger encoding.") flag.StringVar(&namespace, "namespace", "", "Namespace that flagger would watch canary object.") - flag.StringVar(&meshProvider, "mesh-provider", "istio", "Service mesh provider, can be istio, linkerd, appmesh, contour, gloo, nginx, skipper, traefik or osm.") + flag.StringVar(&meshProvider, "mesh-provider", "istio", "Service mesh provider, can be istio, linkerd, appmesh, contour, gloo, nginx, skipper, traefik, osm or kuma.") flag.StringVar(&selectorLabels, "selector-labels", "app,name,app.kubernetes.io/name", "List of pod labels that Flagger uses to create pod selectors.") flag.StringVar(&ingressAnnotationsPrefix, "ingress-annotations-prefix", "nginx.ingress.kubernetes.io", "Annotations prefix for NGINX ingresses.") flag.StringVar(&ingressClass, "ingress-class", "", "Ingress class used for annotating HTTPProxy objects.") diff --git a/docs/diagrams/flagger-kuma-canary.png b/docs/diagrams/flagger-kuma-canary.png new file mode 100644 index 00000000..beae54c1 Binary files /dev/null and b/docs/diagrams/flagger-kuma-canary.png differ diff --git a/docs/gitbook/README.md b/docs/gitbook/README.md index d4946e5d..e85e2c8e 100644 --- a/docs/gitbook/README.md +++ b/docs/gitbook/README.md @@ -37,6 +37,7 @@ After installing Flagger, you can follow one of these tutorials to get started: * [Linkerd](tutorials/linkerd-progressive-delivery.md) * [AWS App Mesh](tutorials/appmesh-progressive-delivery.md) * [Open Service Mesh](tutorials/osm-progressive-delivery.md) +* [Kuma](tutorials/kuma-progressive-delivery.md) **Ingress controller tutorials** diff --git a/docs/gitbook/SUMMARY.md b/docs/gitbook/SUMMARY.md index 5439a16d..ef8b4e06 100644 --- a/docs/gitbook/SUMMARY.md +++ b/docs/gitbook/SUMMARY.md @@ -31,6 +31,7 @@ * [Skipper Canary Deployments](tutorials/skipper-progressive-delivery.md) * [Traefik Canary Deployments](tutorials/traefik-progressive-delivery.md) * [Open Service Mesh Deployments](tutorials/osm-progressive-delivery.md) +* [Kuma Canary Deployments](tutorials/kuma-progressive-delivery.md) * [Blue/Green Deployments](tutorials/kubernetes-blue-green.md) * [Canary analysis with Prometheus Operator](tutorials/prometheus-operator.md) * [Zero downtime deployments](tutorials/zero-downtime-deployments.md) diff --git a/docs/gitbook/tutorials/kuma-progressive-delivery.md b/docs/gitbook/tutorials/kuma-progressive-delivery.md new file mode 100644 index 00000000..5b184772 --- /dev/null +++ b/docs/gitbook/tutorials/kuma-progressive-delivery.md @@ -0,0 +1,252 @@ +# Kuma Canary Deployments + +This guide shows you how to use Kuma and Flagger to automate canary deployments. + +![Flagger Kuma Canary](https://raw.githubusercontent.com/fluxcd/flagger/main/docs/diagrams/flagger-kuma-canary.png) + +## Prerequisites + +Flagger requires a Kubernetes cluster **v1.16** or newer and Kuma **1.3** or newer. + +Install Kuma and Prometheus (part of Kuma Metrics): + +```bash +kumactl install control-plane | kubectl apply -f - +kumactl install metrics | kubectl apply -f - +``` + +Install Flagger in the `kuma-system` namespace: + +```bash +kubectl apply -k github.com/fluxcd/flagger//kustomize/kuma +``` + +## Bootstrap + +Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA), +then creates a series of objects (Kubernetes deployments, ClusterIP services and Kuma `TrafficRoute`). +These objects expose the application inside the mesh and drive the canary analysis and promotion. + +Create a test namespace and enable Kuma sidecar injection: + +```bash +kubectl create ns test +kubectl annotate namespace test kuma.io/sidecar-injection=enabled +``` + +Install the load testing service to generate traffic during the canary analysis: + +```bash +kubectl apply -k https://github.com/fluxcd/flagger//kustomize/tester?ref=main +``` + +Create a deployment and a horizontal pod autoscaler: + +```bash +kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main +``` + +Create a canary custom resource for the `podinfo` deployment: + +```yaml +apiVersion: flagger.app/v1beta1 +kind: Canary +metadata: + name: podinfo + namespace: test + annotations: + kuma.io/mesh: default +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: podinfo + progressDeadlineSeconds: 60 + service: + port: 9898 + targetPort: 9898 + apex: + annotations: + 9898.service.kuma.io/protocol: "http" + canary: + annotations: + 9898.service.kuma.io/protocol: "http" + primary: + annotations: + 9898.service.kuma.io/protocol: "http" + analysis: + # schedule interval (default 60s) + interval: 30s + # 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: 5 + metrics: + - name: request-success-rate + threshold: 99 + interval: 1m + - name: request-duration + threshold: 500 + interval: 30s + webhooks: + - name: acceptance-test + type: pre-rollout + url: http://flagger-loadtester.test/ + timeout: 30s + metadata: + type: bash + cmd: "curl -sd 'test' http://podinfo-canary.test:9898/token | grep token" + - name: load-test + type: rollout + url: http://flagger-loadtester.test/ + metadata: + cmd: "hey -z 2m -q 10 -c 2 http://podinfo-canary.test:9898/" +``` + +Save the above resource as `podinfo-canary.yaml` and then apply it: + +```bash +kubectl apply -f ./podinfo-canary.yaml +``` + +When the canary analysis starts, Flagger will call the pre-rollout webhooks before routing traffic to the canary. The canary analysis will run for five minutes while validating the HTTP metrics and rollout hooks every half a minute. + +After a couple of seconds Flagger will create the canary objects: + +```bash +# applied +deployment.apps/podinfo +horizontalpodautoscaler.autoscaling/podinfo +ingresses.extensions/podinfo +canary.flagger.app/podinfo + +# generated +deployment.apps/podinfo-primary +horizontalpodautoscaler.autoscaling/podinfo-primary +service/podinfo +service/podinfo-canary +service/podinfo-primary +trafficroutes.kuma.io/podinfo +``` + +After the boostrap, the podinfo deployment will be scaled to zero and the traffic to `podinfo.test` will be routed to the primary pods. During the canary analysis, the `podinfo-canary.test` address can be used to target directly the canary pods. + +## Automated canary promotion + +Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators like HTTP requests success rate, requests average duration and pod health. Based on analysis of the KPIs a canary is promoted or aborted, and the analysis result is published to Slack. + +![Flagger Canary Stages](https://raw.githubusercontent.com/fluxcd/flagger/main/docs/diagrams/flagger-canary-steps.png) + +Trigger a canary deployment by updating the container image: + +```bash +kubectl -n test set image deployment/podinfo \ +podinfod=stefanprodan/podinfo:3.1.1 +``` + +Flagger detects that the deployment revision changed and starts a new rollout: + +```text +kubectl -n test describe canary/podinfo + +Status: + Canary Weight: 0 + Failed Checks: 0 + Phase: Succeeded +Events: + New revision detected! Scaling up podinfo.test + Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available + Pre-rollout check acceptance-test passed + Advance podinfo.test canary weight 5 + Advance podinfo.test canary weight 10 + Advance podinfo.test canary weight 15 + Advance podinfo.test canary weight 20 + Advance podinfo.test canary weight 25 + Waiting for podinfo.test rollout to finish: 1 of 2 updated replicas are available + Advance podinfo.test canary weight 30 + Advance podinfo.test canary weight 35 + Advance podinfo.test canary weight 40 + Advance podinfo.test canary weight 45 + Advance podinfo.test canary weight 50 + Copying podinfo.test template spec to podinfo-primary.test + Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available + Promotion completed! Scaling down podinfo.test +``` + +**Note** that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis. + +A canary deployment is triggered by changes in any of the following objects: + +* Deployment PodSpec \(container image, command, ports, env, resources, etc\) +* ConfigMaps mounted as volumes or mapped to environment variables +* Secrets mounted as volumes or mapped to environment variables + +You can monitor all canaries with: + +```bash +watch kubectl get canaries --all-namespaces + +NAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME +test podinfo Progressing 15 2019-06-30T14:05:07Z +prod frontend Succeeded 0 2019-06-30T16:15:07Z +prod backend Failed 0 2019-06-30T17:05:07Z +``` + +## Automated rollback + +During the canary analysis you can generate HTTP 500 errors and high latency to test if Flagger pauses and rolls back the faulted version. + +Trigger another canary deployment: + +```bash +kubectl -n test set image deployment/podinfo \ +podinfod=stefanprodan/podinfo:3.1.2 +``` + +Exec into the load tester pod with: + +```bash +kubectl -n test exec -it flagger-loadtester-xx-xx sh +``` + +Generate HTTP 500 errors: + +```bash +watch -n 1 curl http://podinfo-canary.test:9898/status/500 +``` + +Generate latency: + +```bash +watch -n 1 curl http://podinfo-canary.test:9898/delay/1 +``` + +When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary, the canary is scaled to zero and the rollout is marked as failed. + +```text +kubectl -n test describe canary/podinfo + +Status: + Canary Weight: 0 + Failed Checks: 10 + Phase: Failed +Events: + Starting canary analysis for podinfo.test + Pre-rollout check acceptance-test passed + Advance podinfo.test canary weight 5 + Advance podinfo.test canary weight 10 + Advance podinfo.test canary weight 15 + Halt podinfo.test advancement success rate 69.17% < 99% + Halt podinfo.test advancement success rate 61.39% < 99% + Halt podinfo.test advancement success rate 55.06% < 99% + Halt podinfo.test advancement request duration 1.20s > 0.5s + Halt podinfo.test advancement request duration 1.45s > 0.5s + Rolling back podinfo.test failed checks threshold reached 5 + Canary failed! Scaling down podinfo.test +``` + +The above procedures can be extended with [custom metrics](../usage/metrics.md) checks, [webhooks](../usage/webhooks.md), [manual promotion](../usage/webhooks.md#manual-gating) approval and [Slack or MS Teams](../usage/alerting.md) notifications. diff --git a/docs/gitbook/usage/deployment-strategies.md b/docs/gitbook/usage/deployment-strategies.md index 9483dbb9..7e5c1c5c 100644 --- a/docs/gitbook/usage/deployment-strategies.md +++ b/docs/gitbook/usage/deployment-strategies.md @@ -3,7 +3,7 @@ Flagger can run automated application analysis, promotion and rollback for the following deployment strategies: * **Canary Release** \(progressive traffic shifting\) - * Istio, Linkerd, App Mesh, NGINX, Skipper, Contour, Gloo Edge, Traefik, Open Service Mesh + * Istio, Linkerd, App Mesh, NGINX, Skipper, Contour, Gloo Edge, Traefik, Open Service Mesh, Kuma * **A/B Testing** \(HTTP headers and cookies traffic routing\) * Istio, App Mesh, NGINX, Contour, Gloo Edge * **Blue/Green** \(traffic switching\) diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 3ed27fdc..ecac5a46 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -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" \ + "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" \ --output-base "${TEMP_DIR}" \ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt diff --git a/kustomize/base/flagger/rbac.yaml b/kustomize/base/flagger/rbac.yaml index 354de833..bb1134a4 100644 --- a/kustomize/base/flagger/rbac.yaml +++ b/kustomize/base/flagger/rbac.yaml @@ -177,6 +177,19 @@ rules: - update - patch - delete + - apiGroups: + - kuma.io + resources: + - trafficroutes + - trafficroutes/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete - nonResourceURLs: - /version verbs: diff --git a/kustomize/kuma/kustomization.yaml b/kustomize/kuma/kustomization.yaml new file mode 100644 index 00000000..bdd2d17a --- /dev/null +++ b/kustomize/kuma/kustomization.yaml @@ -0,0 +1,5 @@ +namespace: kuma-system +bases: + - ../base/flagger/ +patchesStrategicMerge: + - patch.yaml diff --git a/kustomize/kuma/patch.yaml b/kustomize/kuma/patch.yaml new file mode 100644 index 00000000..cbcc4f88 --- /dev/null +++ b/kustomize/kuma/patch.yaml @@ -0,0 +1,14 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flagger +spec: + template: + spec: + containers: + - name: flagger + args: + - -log-level=info + - -include-label-prefix=app.kubernetes.io + - -mesh-provider=kuma + - -metrics-server=http://prometheus-server.kuma-metrics:80 diff --git a/pkg/apis/flagger/v1beta1/provider.go b/pkg/apis/flagger/v1beta1/provider.go index fb48d13f..dcfa8d72 100644 --- a/pkg/apis/flagger/v1beta1/provider.go +++ b/pkg/apis/flagger/v1beta1/provider.go @@ -12,4 +12,5 @@ const ( SkipperProvider string = "skipper" TraefikProvider string = "traefik" OsmProvider string = "osm" + KumaProvider string = "kuma" ) diff --git a/pkg/apis/kuma/register.go b/pkg/apis/kuma/register.go new file mode 100644 index 00000000..fd3cb1ac --- /dev/null +++ b/pkg/apis/kuma/register.go @@ -0,0 +1,5 @@ +package kuma + +const ( + GroupName = "kuma.io" +) diff --git a/pkg/apis/kuma/v1alpha1/doc.go b/pkg/apis/kuma/v1alpha1/doc.go new file mode 100644 index 00000000..0cb846ef --- /dev/null +++ b/pkg/apis/kuma/v1alpha1/doc.go @@ -0,0 +1,5 @@ +// +k8s:deepcopy-gen=package + +// Package v1 is the v1 version of the API. +// +groupName=kuma.io +package v1alpha1 diff --git a/pkg/apis/kuma/v1alpha1/register.go b/pkg/apis/kuma/v1alpha1/register.go new file mode 100644 index 00000000..8a7b17b1 --- /dev/null +++ b/pkg/apis/kuma/v1alpha1/register.go @@ -0,0 +1,36 @@ +package v1alpha1 + +import ( + "github.com/fluxcd/flagger/pkg/apis/kuma" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is the GroupVersion for the Kuma API +var SchemeGroupVersion = schema.GroupVersion{Group: kuma.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource gets a Kuma GroupResource for a specified resource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TrafficRoute{}, + &TrafficRouteList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/kuma/v1alpha1/trafficroute.go b/pkg/apis/kuma/v1alpha1/trafficroute.go new file mode 100644 index 00000000..175b0646 --- /dev/null +++ b/pkg/apis/kuma/v1alpha1/trafficroute.go @@ -0,0 +1,82 @@ +/* +Copyright 2019 Kuma 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +genclient:nonNamespaced + +// TrafficRoute is the Schema for the Traffic Routes API. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type TrafficRoute struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Mesh string `json:"mesh,omitempty"` + Spec TrafficRouteSpec `json:"spec,omitempty"` +} + +// TrafficRouteList defines a list of TrafficRoute objects. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type TrafficRouteList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TrafficRoute `json:"items"` +} + +// TrafficRouteSpec defines the spec for a TrafficRoute. +type TrafficRouteSpec struct { + // List of selectors to match data plane proxies that are sources of traffic. + Sources []*Selector `json:"sources,omitempty"` + // List of selectors to match services that are destinations of traffic. + // + // Notice the difference between sources and destinations. + // While the source of traffic is always a data plane proxy within a mesh, + // the destination is a service that could be either within or outside + // of a mesh. + Destinations []*Selector `json:"destinations,omitempty"` + // Configuration for the route. + Conf *TrafficRouteConf `json:"conf,omitempty"` +} + +// Selector defines the configuration for which Kuma services should be targeted. +type Selector struct { + // Tags to match, can be used for both source and destinations + Match map[string]string `json:"match,omitempty"` +} + +// TrafficRouteConf defines the destination configuration. +type TrafficRouteConf struct { + // List of destinations with weights assigned to them. + // When used, "destination" is not allowed. + Split []*TrafficRouteSplit `json:"split,omitempty"` +} + +// TrafficRouteSplit defines a destination with a weight assigned to it. +type TrafficRouteSplit struct { + // Weight assigned to that destination. + // Weights are not percentages. For example two destinations with + // weights the same weight "1" will receive both same amount of the traffic. + // 0 means that the destination will be ignored. + Weight uint32 `json:"weight"` + // Selector to match individual endpoints that comprise that destination. + // + // Notice that an endpoint can be either inside or outside the mesh. + // In the former case an endpoint corresponds to a data plane proxy, + // in the latter case an endpoint is an External Service. + Destination map[string]string `json:"destination,omitempty"` +} diff --git a/pkg/apis/kuma/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kuma/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..8e3d4038 --- /dev/null +++ b/pkg/apis/kuma/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,202 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Selector) DeepCopyInto(out *Selector) { + *out = *in + if in.Match != nil { + in, out := &in.Match, &out.Match + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector. +func (in *Selector) DeepCopy() *Selector { + if in == nil { + return nil + } + out := new(Selector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficRoute) DeepCopyInto(out *TrafficRoute) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRoute. +func (in *TrafficRoute) DeepCopy() *TrafficRoute { + if in == nil { + return nil + } + out := new(TrafficRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficRoute) 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 *TrafficRouteConf) DeepCopyInto(out *TrafficRouteConf) { + *out = *in + if in.Split != nil { + in, out := &in.Split, &out.Split + *out = make([]*TrafficRouteSplit, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TrafficRouteSplit) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRouteConf. +func (in *TrafficRouteConf) DeepCopy() *TrafficRouteConf { + if in == nil { + return nil + } + out := new(TrafficRouteConf) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficRouteList) DeepCopyInto(out *TrafficRouteList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TrafficRoute, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRouteList. +func (in *TrafficRouteList) DeepCopy() *TrafficRouteList { + if in == nil { + return nil + } + out := new(TrafficRouteList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficRouteList) 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 *TrafficRouteSpec) DeepCopyInto(out *TrafficRouteSpec) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]*Selector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Selector) + (*in).DeepCopyInto(*out) + } + } + } + if in.Destinations != nil { + in, out := &in.Destinations, &out.Destinations + *out = make([]*Selector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Selector) + (*in).DeepCopyInto(*out) + } + } + } + if in.Conf != nil { + in, out := &in.Conf, &out.Conf + *out = new(TrafficRouteConf) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRouteSpec. +func (in *TrafficRouteSpec) DeepCopy() *TrafficRouteSpec { + if in == nil { + return nil + } + out := new(TrafficRouteSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficRouteSplit) DeepCopyInto(out *TrafficRouteSplit) { + *out = *in + if in.Destination != nil { + in, out := &in.Destination, &out.Destination + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRouteSplit. +func (in *TrafficRouteSplit) DeepCopy() *TrafficRouteSplit { + if in == nil { + return nil + } + out := new(TrafficRouteSplit) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index d923ab7b..ecc007f5 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -28,6 +28,7 @@ import ( gatewayv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gateway/v1" gloov1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/gloo/v1" networkingv1alpha3 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3" + kumav1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/kuma/v1alpha1" projectcontourv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/projectcontour/v1" splitv1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/smi/v1alpha1" splitv1alpha2 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/smi/v1alpha2" @@ -46,6 +47,7 @@ type Interface interface { GatewayV1() gatewayv1.GatewayV1Interface GlooV1() gloov1.GlooV1Interface NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3Interface + KumaV1alpha1() kumav1alpha1.KumaV1alpha1Interface ProjectcontourV1() projectcontourv1.ProjectcontourV1Interface SplitV1alpha1() splitv1alpha1.SplitV1alpha1Interface SplitV1alpha2() splitv1alpha2.SplitV1alpha2Interface @@ -63,6 +65,7 @@ type Clientset struct { gatewayV1 *gatewayv1.GatewayV1Client glooV1 *gloov1.GlooV1Client networkingV1alpha3 *networkingv1alpha3.NetworkingV1alpha3Client + kumaV1alpha1 *kumav1alpha1.KumaV1alpha1Client projectcontourV1 *projectcontourv1.ProjectcontourV1Client splitV1alpha1 *splitv1alpha1.SplitV1alpha1Client splitV1alpha2 *splitv1alpha2.SplitV1alpha2Client @@ -100,6 +103,11 @@ func (c *Clientset) NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3In return c.networkingV1alpha3 } +// KumaV1alpha1 retrieves the KumaV1alpha1Client +func (c *Clientset) KumaV1alpha1() kumav1alpha1.KumaV1alpha1Interface { + return c.kumaV1alpha1 +} + // ProjectcontourV1 retrieves the ProjectcontourV1Client func (c *Clientset) ProjectcontourV1() projectcontourv1.ProjectcontourV1Interface { return c.projectcontourV1 @@ -189,6 +197,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, if err != nil { return nil, err } + cs.kumaV1alpha1, err = kumav1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } cs.projectcontourV1, err = projectcontourv1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err @@ -236,6 +248,7 @@ func New(c rest.Interface) *Clientset { cs.gatewayV1 = gatewayv1.New(c) cs.glooV1 = gloov1.New(c) cs.networkingV1alpha3 = networkingv1alpha3.New(c) + cs.kumaV1alpha1 = kumav1alpha1.New(c) cs.projectcontourV1 = projectcontourv1.New(c) cs.splitV1alpha1 = splitv1alpha1.New(c) cs.splitV1alpha2 = splitv1alpha2.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 63e5a360..0c8b64c8 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -32,6 +32,8 @@ import ( 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" fakenetworkingv1alpha3 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3/fake" + kumav1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/kuma/v1alpha1" + fakekumav1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake" projectcontourv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/projectcontour/v1" fakeprojectcontourv1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/projectcontour/v1/fake" splitv1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/smi/v1alpha1" @@ -129,6 +131,11 @@ func (c *Clientset) NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3In return &fakenetworkingv1alpha3.FakeNetworkingV1alpha3{Fake: &c.Fake} } +// KumaV1alpha1 retrieves the KumaV1alpha1Client +func (c *Clientset) KumaV1alpha1() kumav1alpha1.KumaV1alpha1Interface { + return &fakekumav1alpha1.FakeKumaV1alpha1{Fake: &c.Fake} +} + // ProjectcontourV1 retrieves the ProjectcontourV1Client func (c *Clientset) ProjectcontourV1() projectcontourv1.ProjectcontourV1Interface { return &fakeprojectcontourv1.FakeProjectcontourV1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 18145710..f4f594b0 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -25,6 +25,7 @@ import ( 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" + kumav1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" projectcontourv1 "github.com/fluxcd/flagger/pkg/apis/projectcontour/v1" splitv1alpha1 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha1" splitv1alpha2 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha2" @@ -47,6 +48,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ gatewayv1.AddToScheme, gloov1.AddToScheme, networkingv1alpha3.AddToScheme, + kumav1alpha1.AddToScheme, projectcontourv1.AddToScheme, splitv1alpha1.AddToScheme, splitv1alpha2.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 0c95149c..a5082453 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -25,6 +25,7 @@ import ( 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" + kumav1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" projectcontourv1 "github.com/fluxcd/flagger/pkg/apis/projectcontour/v1" splitv1alpha1 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha1" splitv1alpha2 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha2" @@ -47,6 +48,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ gatewayv1.AddToScheme, gloov1.AddToScheme, networkingv1alpha3.AddToScheme, + kumav1alpha1.AddToScheme, projectcontourv1.AddToScheme, splitv1alpha1.AddToScheme, splitv1alpha2.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/doc.go new file mode 100644 index 00000000..9c7b8cc3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/doc.go @@ -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 v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/doc.go new file mode 100644 index 00000000..1ccd9119 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_kuma_client.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_kuma_client.go new file mode 100644 index 00000000..d75ef37d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_kuma_client.go @@ -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 ( + v1alpha1 "github.com/fluxcd/flagger/pkg/client/clientset/versioned/typed/kuma/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeKumaV1alpha1 struct { + *testing.Fake +} + +func (c *FakeKumaV1alpha1) TrafficRoutes() v1alpha1.TrafficRouteInterface { + return &FakeTrafficRoutes{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeKumaV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_trafficroute.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_trafficroute.go new file mode 100644 index 00000000..51d2e154 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/fake/fake_trafficroute.go @@ -0,0 +1,122 @@ +/* +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" + + v1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + 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" +) + +// FakeTrafficRoutes implements TrafficRouteInterface +type FakeTrafficRoutes struct { + Fake *FakeKumaV1alpha1 +} + +var trafficroutesResource = schema.GroupVersionResource{Group: "kuma.io", Version: "v1alpha1", Resource: "trafficroutes"} + +var trafficroutesKind = schema.GroupVersionKind{Group: "kuma.io", Version: "v1alpha1", Kind: "TrafficRoute"} + +// Get takes name of the trafficRoute, and returns the corresponding trafficRoute object, and an error if there is any. +func (c *FakeTrafficRoutes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrafficRoute, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(trafficroutesResource, name), &v1alpha1.TrafficRoute{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TrafficRoute), err +} + +// List takes label and field selectors, and returns the list of TrafficRoutes that match those selectors. +func (c *FakeTrafficRoutes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrafficRouteList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(trafficroutesResource, trafficroutesKind, opts), &v1alpha1.TrafficRouteList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.TrafficRouteList{ListMeta: obj.(*v1alpha1.TrafficRouteList).ListMeta} + for _, item := range obj.(*v1alpha1.TrafficRouteList).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 trafficRoutes. +func (c *FakeTrafficRoutes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(trafficroutesResource, opts)) +} + +// Create takes the representation of a trafficRoute and creates it. Returns the server's representation of the trafficRoute, and an error, if there is any. +func (c *FakeTrafficRoutes) Create(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.CreateOptions) (result *v1alpha1.TrafficRoute, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(trafficroutesResource, trafficRoute), &v1alpha1.TrafficRoute{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TrafficRoute), err +} + +// Update takes the representation of a trafficRoute and updates it. Returns the server's representation of the trafficRoute, and an error, if there is any. +func (c *FakeTrafficRoutes) Update(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.UpdateOptions) (result *v1alpha1.TrafficRoute, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(trafficroutesResource, trafficRoute), &v1alpha1.TrafficRoute{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TrafficRoute), err +} + +// Delete takes name of the trafficRoute and deletes it. Returns an error if one occurs. +func (c *FakeTrafficRoutes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(trafficroutesResource, name, opts), &v1alpha1.TrafficRoute{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTrafficRoutes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(trafficroutesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.TrafficRouteList{}) + return err +} + +// Patch applies the patch and returns the patched trafficRoute. +func (c *FakeTrafficRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrafficRoute, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(trafficroutesResource, name, pt, data, subresources...), &v1alpha1.TrafficRoute{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TrafficRoute), err +} diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/generated_expansion.go new file mode 100644 index 00000000..b8a7a3e7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/generated_expansion.go @@ -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 v1alpha1 + +type TrafficRouteExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/kuma_client.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/kuma_client.go new file mode 100644 index 00000000..1fdbd2b9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/kuma_client.go @@ -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 v1alpha1 + +import ( + "net/http" + + v1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + "github.com/fluxcd/flagger/pkg/client/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type KumaV1alpha1Interface interface { + RESTClient() rest.Interface + TrafficRoutesGetter +} + +// KumaV1alpha1Client is used to interact with features provided by the kuma.io group. +type KumaV1alpha1Client struct { + restClient rest.Interface +} + +func (c *KumaV1alpha1Client) TrafficRoutes() TrafficRouteInterface { + return newTrafficRoutes(c) +} + +// NewForConfig creates a new KumaV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*KumaV1alpha1Client, 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 KumaV1alpha1Client 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) (*KumaV1alpha1Client, 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 &KumaV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new KumaV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *KumaV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new KumaV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *KumaV1alpha1Client { + return &KumaV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.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 *KumaV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/kuma/v1alpha1/trafficroute.go b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/trafficroute.go new file mode 100644 index 00000000..76089aba --- /dev/null +++ b/pkg/client/clientset/versioned/typed/kuma/v1alpha1/trafficroute.go @@ -0,0 +1,168 @@ +/* +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 v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + 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" +) + +// TrafficRoutesGetter has a method to return a TrafficRouteInterface. +// A group's client should implement this interface. +type TrafficRoutesGetter interface { + TrafficRoutes() TrafficRouteInterface +} + +// TrafficRouteInterface has methods to work with TrafficRoute resources. +type TrafficRouteInterface interface { + Create(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.CreateOptions) (*v1alpha1.TrafficRoute, error) + Update(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.UpdateOptions) (*v1alpha1.TrafficRoute, 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) (*v1alpha1.TrafficRoute, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.TrafficRouteList, 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 *v1alpha1.TrafficRoute, err error) + TrafficRouteExpansion +} + +// trafficRoutes implements TrafficRouteInterface +type trafficRoutes struct { + client rest.Interface +} + +// newTrafficRoutes returns a TrafficRoutes +func newTrafficRoutes(c *KumaV1alpha1Client) *trafficRoutes { + return &trafficRoutes{ + client: c.RESTClient(), + } +} + +// Get takes name of the trafficRoute, and returns the corresponding trafficRoute object, and an error if there is any. +func (c *trafficRoutes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrafficRoute, err error) { + result = &v1alpha1.TrafficRoute{} + err = c.client.Get(). + Resource("trafficroutes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TrafficRoutes that match those selectors. +func (c *trafficRoutes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrafficRouteList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.TrafficRouteList{} + err = c.client.Get(). + Resource("trafficroutes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested trafficRoutes. +func (c *trafficRoutes) 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(). + Resource("trafficroutes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a trafficRoute and creates it. Returns the server's representation of the trafficRoute, and an error, if there is any. +func (c *trafficRoutes) Create(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.CreateOptions) (result *v1alpha1.TrafficRoute, err error) { + result = &v1alpha1.TrafficRoute{} + err = c.client.Post(). + Resource("trafficroutes"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficRoute). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a trafficRoute and updates it. Returns the server's representation of the trafficRoute, and an error, if there is any. +func (c *trafficRoutes) Update(ctx context.Context, trafficRoute *v1alpha1.TrafficRoute, opts v1.UpdateOptions) (result *v1alpha1.TrafficRoute, err error) { + result = &v1alpha1.TrafficRoute{} + err = c.client.Put(). + Resource("trafficroutes"). + Name(trafficRoute.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficRoute). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the trafficRoute and deletes it. Returns an error if one occurs. +func (c *trafficRoutes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("trafficroutes"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *trafficRoutes) 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(). + Resource("trafficroutes"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched trafficRoute. +func (c *trafficRoutes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrafficRoute, err error) { + result = &v1alpha1.TrafficRoute{} + err = c.client.Patch(pt). + Resource("trafficroutes"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index a876cbe4..a4bd8fc0 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -30,6 +30,7 @@ import ( gloo "github.com/fluxcd/flagger/pkg/client/informers/externalversions/gloo" internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces" istio "github.com/fluxcd/flagger/pkg/client/informers/externalversions/istio" + kuma "github.com/fluxcd/flagger/pkg/client/informers/externalversions/kuma" projectcontour "github.com/fluxcd/flagger/pkg/client/informers/externalversions/projectcontour" smi "github.com/fluxcd/flagger/pkg/client/informers/externalversions/smi" traefik "github.com/fluxcd/flagger/pkg/client/informers/externalversions/traefik" @@ -184,6 +185,7 @@ type SharedInformerFactory interface { Gateway() gateway.Interface Gloo() gloo.Interface Networking() istio.Interface + Kuma() kuma.Interface Projectcontour() projectcontour.Interface Split() smi.Interface Traefik() traefik.Interface @@ -209,6 +211,10 @@ func (f *sharedInformerFactory) Networking() istio.Interface { return istio.New(f, f.namespace, f.tweakListOptions) } +func (f *sharedInformerFactory) Kuma() kuma.Interface { + return kuma.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Projectcontour() projectcontour.Interface { return projectcontour.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 05b56a26..13bb2c33 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -27,8 +27,9 @@ import ( 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" + v1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" projectcontourv1 "github.com/fluxcd/flagger/pkg/apis/projectcontour/v1" - v1alpha1 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha1" + smiv1alpha1 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha1" v1alpha2 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha2" smiv1alpha3 "github.com/fluxcd/flagger/pkg/apis/smi/v1alpha3" traefikv1alpha1 "github.com/fluxcd/flagger/pkg/apis/traefik/v1alpha1" @@ -94,6 +95,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case gloov1.SchemeGroupVersion.WithResource("upstreams"): return &genericInformer{resource: resource.GroupResource(), informer: f.Gloo().V1().Upstreams().Informer()}, nil + // Group=kuma.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("trafficroutes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Kuma().V1alpha1().TrafficRoutes().Informer()}, nil + // Group=networking.istio.io, Version=v1alpha3 case v1alpha3.SchemeGroupVersion.WithResource("destinationrules"): return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha3().DestinationRules().Informer()}, nil @@ -105,7 +110,7 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Projectcontour().V1().HTTPProxies().Informer()}, nil // Group=split.smi-spec.io, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("trafficsplits"): + case smiv1alpha1.SchemeGroupVersion.WithResource("trafficsplits"): return &genericInformer{resource: resource.GroupResource(), informer: f.Split().V1alpha1().TrafficSplits().Informer()}, nil // Group=split.smi-spec.io, Version=v1alpha2 diff --git a/pkg/client/informers/externalversions/kuma/interface.go b/pkg/client/informers/externalversions/kuma/interface.go new file mode 100644 index 00000000..757fbc9c --- /dev/null +++ b/pkg/client/informers/externalversions/kuma/interface.go @@ -0,0 +1,46 @@ +/* +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 kuma + +import ( + internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/fluxcd/flagger/pkg/client/informers/externalversions/kuma/v1alpha1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group 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 &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/kuma/v1alpha1/interface.go b/pkg/client/informers/externalversions/kuma/v1alpha1/interface.go new file mode 100644 index 00000000..6e51c0c4 --- /dev/null +++ b/pkg/client/informers/externalversions/kuma/v1alpha1/interface.go @@ -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 v1alpha1 + +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 { + // TrafficRoutes returns a TrafficRouteInformer. + TrafficRoutes() TrafficRouteInformer +} + +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} +} + +// TrafficRoutes returns a TrafficRouteInformer. +func (v *version) TrafficRoutes() TrafficRouteInformer { + return &trafficRouteInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/kuma/v1alpha1/trafficroute.go b/pkg/client/informers/externalversions/kuma/v1alpha1/trafficroute.go new file mode 100644 index 00000000..a2f46b94 --- /dev/null +++ b/pkg/client/informers/externalversions/kuma/v1alpha1/trafficroute.go @@ -0,0 +1,89 @@ +/* +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 v1alpha1 + +import ( + "context" + time "time" + + kumav1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + versioned "github.com/fluxcd/flagger/pkg/client/clientset/versioned" + internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/fluxcd/flagger/pkg/client/listers/kuma/v1alpha1" + 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" +) + +// TrafficRouteInformer provides access to a shared informer and lister for +// TrafficRoutes. +type TrafficRouteInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.TrafficRouteLister +} + +type trafficRouteInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewTrafficRouteInformer constructs a new informer for TrafficRoute 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 NewTrafficRouteInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTrafficRouteInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredTrafficRouteInformer constructs a new informer for TrafficRoute 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 NewFilteredTrafficRouteInformer(client versioned.Interface, 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.KumaV1alpha1().TrafficRoutes().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KumaV1alpha1().TrafficRoutes().Watch(context.TODO(), options) + }, + }, + &kumav1alpha1.TrafficRoute{}, + resyncPeriod, + indexers, + ) +} + +func (f *trafficRouteInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTrafficRouteInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *trafficRouteInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&kumav1alpha1.TrafficRoute{}, f.defaultInformer) +} + +func (f *trafficRouteInformer) Lister() v1alpha1.TrafficRouteLister { + return v1alpha1.NewTrafficRouteLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/kuma/v1alpha1/expansion_generated.go b/pkg/client/listers/kuma/v1alpha1/expansion_generated.go new file mode 100644 index 00000000..6e7c6048 --- /dev/null +++ b/pkg/client/listers/kuma/v1alpha1/expansion_generated.go @@ -0,0 +1,23 @@ +/* +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 v1alpha1 + +// TrafficRouteListerExpansion allows custom methods to be added to +// TrafficRouteLister. +type TrafficRouteListerExpansion interface{} diff --git a/pkg/client/listers/kuma/v1alpha1/trafficroute.go b/pkg/client/listers/kuma/v1alpha1/trafficroute.go new file mode 100644 index 00000000..d6869f67 --- /dev/null +++ b/pkg/client/listers/kuma/v1alpha1/trafficroute.go @@ -0,0 +1,68 @@ +/* +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 v1alpha1 + +import ( + v1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TrafficRouteLister helps list TrafficRoutes. +// All objects returned here must be treated as read-only. +type TrafficRouteLister interface { + // List lists all TrafficRoutes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.TrafficRoute, err error) + // Get retrieves the TrafficRoute from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.TrafficRoute, error) + TrafficRouteListerExpansion +} + +// trafficRouteLister implements the TrafficRouteLister interface. +type trafficRouteLister struct { + indexer cache.Indexer +} + +// NewTrafficRouteLister returns a new TrafficRouteLister. +func NewTrafficRouteLister(indexer cache.Indexer) TrafficRouteLister { + return &trafficRouteLister{indexer: indexer} +} + +// List lists all TrafficRoutes in the indexer. +func (s *trafficRouteLister) List(selector labels.Selector) (ret []*v1alpha1.TrafficRoute, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.TrafficRoute)) + }) + return ret, err +} + +// Get retrieves the TrafficRoute from the index for a given name. +func (s *trafficRouteLister) Get(name string) (*v1alpha1.TrafficRoute, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("trafficroute"), name) + } + return obj.(*v1alpha1.TrafficRoute), nil +} diff --git a/pkg/metrics/observers/factory.go b/pkg/metrics/observers/factory.go index 9b54dbe5..23e4bd2f 100644 --- a/pkg/metrics/observers/factory.go +++ b/pkg/metrics/observers/factory.go @@ -84,6 +84,10 @@ func (factory Factory) Observer(provider string) Interface { return &OsmObserver{ client: factory.Client, } + case provider == flaggerv1.KumaProvider: + return &KumaObserver{ + client: factory.Client, + } default: return &IstioObserver{ client: factory.Client, diff --git a/pkg/metrics/observers/kuma.go b/pkg/metrics/observers/kuma.go new file mode 100644 index 00000000..699fea04 --- /dev/null +++ b/pkg/metrics/observers/kuma.go @@ -0,0 +1,94 @@ +/* +Copyright 2021 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 observers + +import ( + "fmt" + "time" + + flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1" + "github.com/fluxcd/flagger/pkg/metrics/providers" +) + +// TODO [@johnharris85]: Do we also need to select by mesh here? These could be duplicated (but in different meshes). +// We're currently getting the mesh name from an annotation on the Canary object, but that isn't propagated to the +// MetricTemplateModel. +var kumaQueries = map[string]string{ + "request-success-rate": ` + sum( + rate( + envoy_cluster_upstream_rq{ + envoy_cluster_name=~"{{ target }}-canary_{{ namespace }}_svc_[0-9a-zA-Z-]+", + envoy_response_code!~"5.*" + }[{{ interval }}] + ) + ) + / + sum( + rate( + envoy_cluster_upstream_rq{ + envoy_cluster_name=~"{{ target }}-canary_{{ namespace }}_svc_[0-9a-zA-Z-]+", + }[{{ interval }}] + ) + ) + * 100`, + "request-duration": ` + histogram_quantile( + 0.99, + sum( + rate( + envoy_cluster_upstream_rq_time_bucket{ + envoy_cluster_name=~"{{ target }}-canary_{{ namespace }}_svc_[0-9a-zA-Z-]+", + }[{{ interval }}] + ) + ) by (le) + )`, +} + +type KumaObserver struct { + client providers.Interface +} + +func (ob *KumaObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { + query, err := RenderQuery(kumaQueries["request-success-rate"], model) + + if err != nil { + return 0, fmt.Errorf("rendering query failed: %w", err) + } + + value, err := ob.client.RunQuery(query) + if err != nil { + return 0, fmt.Errorf("running query failed: %w", err) + } + + return value, nil +} + +func (ob *KumaObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { + query, err := RenderQuery(kumaQueries["request-duration"], model) + if err != nil { + return 0, fmt.Errorf("rendering query failed: %w", err) + } + + value, err := ob.client.RunQuery(query) + if err != nil { + return 0, fmt.Errorf("running query failed: %w", err) + } + + ms := time.Duration(int64(value)) * time.Millisecond + return ms, nil +} diff --git a/pkg/metrics/observers/kuma_test.go b/pkg/metrics/observers/kuma_test.go new file mode 100644 index 00000000..dda802a1 --- /dev/null +++ b/pkg/metrics/observers/kuma_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2021 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 observers + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1" + "github.com/fluxcd/flagger/pkg/metrics/providers" +) + +func TestKumaObserver_GetRequestSuccessRate(t *testing.T) { + expected := ` sum( rate( envoy_cluster_upstream_rq{ envoy_cluster_name=~"podinfo-canary_default_svc_[0-9a-zA-Z-]+", envoy_response_code!~"5.*" }[1m] ) ) / sum( rate( envoy_cluster_upstream_rq{ envoy_cluster_name=~"podinfo-canary_default_svc_[0-9a-zA-Z-]+", }[1m] ) ) * 100` + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + promql := r.URL.Query()["query"][0] + assert.Equal(t, expected, promql) + + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1,"100"]}]}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + client, err := providers.NewPrometheusProvider(flaggerv1.MetricTemplateProvider{ + Type: "prometheus", + Address: ts.URL, + SecretRef: nil, + }, nil) + require.NoError(t, err) + + observer := &KumaObserver{ + client: client, + } + + val, err := observer.GetRequestSuccessRate(flaggerv1.MetricTemplateModel{ + Name: "podinfo", + Namespace: "default", + Target: "podinfo", + Service: "podinfo", + Interval: "1m", + }) + require.NoError(t, err) + + assert.Equal(t, float64(100), val) +} + +func TestKumaObserver_GetRequestDuration(t *testing.T) { + expected := ` histogram_quantile( 0.99, sum( rate( envoy_cluster_upstream_rq_time_bucket{ envoy_cluster_name=~"podinfo-canary_default_svc_[0-9a-zA-Z-]+", }[1m] ) ) by (le) )` + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + promql := r.URL.Query()["query"][0] + assert.Equal(t, expected, promql) + + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1,"100"]}]}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + client, err := providers.NewPrometheusProvider(flaggerv1.MetricTemplateProvider{ + Type: "prometheus", + Address: ts.URL, + SecretRef: nil, + }, nil) + require.NoError(t, err) + + observer := &KumaObserver{ + client: client, + } + + val, err := observer.GetRequestDuration(flaggerv1.MetricTemplateModel{ + Name: "podinfo", + Namespace: "default", + Target: "podinfo", + Service: "podinfo", + Interval: "1m", + }) + require.NoError(t, err) + + assert.Equal(t, 100*time.Millisecond, val) +} diff --git a/pkg/router/factory.go b/pkg/router/factory.go index 5b7adc25..e5a864e7 100644 --- a/pkg/router/factory.go +++ b/pkg/router/factory.go @@ -170,6 +170,13 @@ func (factory *Factory) MeshRouter(provider string, labelSelector string) Interf smiClient: factory.meshClient, targetMesh: flaggerv1.OsmProvider, } + case provider == flaggerv1.KumaProvider: + return &KumaRouter{ + logger: factory.logger, + flaggerClient: factory.flaggerClient, + kubeClient: factory.kubeClient, + kumaClient: factory.meshClient, + } case provider == flaggerv1.KubernetesProvider: return &NopRouter{} default: diff --git a/pkg/router/kuma.go b/pkg/router/kuma.go new file mode 100644 index 00000000..75b1b0fa --- /dev/null +++ b/pkg/router/kuma.go @@ -0,0 +1,212 @@ +package router + +import ( + "context" + "fmt" + "strings" + + flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1" + kumav1alpha1 "github.com/fluxcd/flagger/pkg/apis/kuma/v1alpha1" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + + "go.uber.org/zap" + "k8s.io/client-go/kubernetes" + + clientset "github.com/fluxcd/flagger/pkg/client/clientset/versioned" +) + +// KumaRouter is managing TrafficRoute objects +type KumaRouter struct { + kubeClient kubernetes.Interface + kumaClient clientset.Interface + flaggerClient clientset.Interface + logger *zap.SugaredLogger +} + +// Reconcile creates or updates the Kuma TrafficRoute +func (kr *KumaRouter) Reconcile(canary *flaggerv1.Canary) error { + apexName, primaryName, canaryName := canary.GetServiceNames() + + trSpec := kumav1alpha1.TrafficRouteSpec{ + Sources: []*kumav1alpha1.Selector{ + { + Match: map[string]string{ + "kuma.io/service": "*", + }, + }, + }, + Destinations: []*kumav1alpha1.Selector{ + { + Match: map[string]string{ + "kuma.io/service": fmt.Sprintf("%s_%s_svc_%d", apexName, canary.Namespace, canary.Spec.Service.Port), + }, + }, + }, + Conf: &kumav1alpha1.TrafficRouteConf{ + Split: []*kumav1alpha1.TrafficRouteSplit{ + { + Weight: uint32(100), + Destination: map[string]string{ + "kuma.io/service": fmt.Sprintf("%s_%s_svc_%d", primaryName, canary.Namespace, canary.Spec.Service.Port), + }, + }, + { + Weight: uint32(0), + Destination: map[string]string{ + "kuma.io/service": fmt.Sprintf("%s_%s_svc_%d", canaryName, canary.Namespace, canary.Spec.Service.Port), + }, + }, + }, + }, + } + + tr, err := kr.kumaClient.KumaV1alpha1().TrafficRoutes().Get(context.TODO(), apexName, metav1.GetOptions{}) + + // create TrafficRoute + 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) + metadata.Annotations[fmt.Sprintf("%d.service.kuma.io", canary.Spec.Service.Port)] = "http" + } + + meshName, ok := canary.Annotations["kuma.io/mesh"] + if !ok { + meshName = "default" + } + + t := &kumav1alpha1.TrafficRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: apexName, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(canary, schema.GroupVersionKind{ + Group: flaggerv1.SchemeGroupVersion.Group, + Version: flaggerv1.SchemeGroupVersion.Version, + Kind: flaggerv1.CanaryKind, + }), + }, + Annotations: filterMetadata(metadata.Annotations), + }, + Spec: trSpec, + Mesh: meshName, + } + + _, err := kr.kumaClient.KumaV1alpha1().TrafficRoutes().Create(context.TODO(), t, metav1.CreateOptions{}) + + if err != nil { + return fmt.Errorf("TrafficRoute %s create error: %w", apexName, err) + } + + kr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). + Infof("TrafficRoute %s created", t.GetName()) + return nil + } else if err != nil { + return fmt.Errorf("TrafficRoute %s get query error: %w", apexName, err) + } + + // update TrafficRoute + if diff := cmp.Diff(trSpec, tr.Spec, cmpopts.IgnoreFields(kumav1alpha1.TrafficRouteSplit{}, "Weight")); diff != "" { + trClone := tr.DeepCopy() + trClone.Spec = trSpec + + _, err := kr.kumaClient.KumaV1alpha1().TrafficRoutes().Update(context.TODO(), trClone, metav1.UpdateOptions{}) + + if err != nil { + return fmt.Errorf("TrafficRoute %s update error: %w", apexName, err) + } + + kr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). + Infof("TrafficRoute %s.%s updated", apexName, canary.Namespace) + return nil + } + + return nil +} + +// GetRoutes returns the destinations weight for primary and canary +func (kr *KumaRouter) GetRoutes(canary *flaggerv1.Canary) ( + primaryWeight int, + canaryWeight int, + mirrored bool, + err error, +) { + apexName, primaryName, canaryName := canary.GetServiceNames() + tr, err := kr.kumaClient.KumaV1alpha1().TrafficRoutes().Get(context.TODO(), apexName, metav1.GetOptions{}) + + if err != nil { + err = fmt.Errorf("TrafficRoute %s get query error %v", apexName, err) + return + } + + for _, split := range tr.Spec.Conf.Split { + if strings.Split(split.Destination["kuma.io/service"], "_")[0] == primaryName { + primaryWeight = int(split.Weight) + canaryWeight = 100 - primaryWeight + } + } + + if primaryWeight == 0 && canaryWeight == 0 { + err = fmt.Errorf("TrafficRoute %s does not contain routes for %s and %s", + apexName, primaryName, canaryName) + } + + mirrored = false + + return +} + +// SetRoutes updates the destinations weight for primary and canary +func (kr *KumaRouter) SetRoutes( + canary *flaggerv1.Canary, + primaryWeight int, + canaryWeight int, + _ bool, +) error { + apexName, primaryName, canaryName := canary.GetServiceNames() + tr, err := kr.kumaClient.KumaV1alpha1().TrafficRoutes().Get(context.TODO(), apexName, metav1.GetOptions{}) + + if err != nil { + return fmt.Errorf("TrafficRoute %s get query error %v", apexName, err) + } + + conf := &kumav1alpha1.TrafficRouteConf{ + Split: []*kumav1alpha1.TrafficRouteSplit{ + { + Weight: uint32(primaryWeight), + Destination: map[string]string{ + "kuma.io/service": fmt.Sprintf("%s_%s_svc_%d", primaryName, canary.Namespace, canary.Spec.Service.Port), + }, + }, + { + Weight: uint32(canaryWeight), + Destination: map[string]string{ + "kuma.io/service": fmt.Sprintf("%s_%s_svc_%d", canaryName, canary.Namespace, canary.Spec.Service.Port), + }, + }, + }, + } + + trClone := tr.DeepCopy() + trClone.Spec.Conf = conf + + _, err = kr.kumaClient.KumaV1alpha1().TrafficRoutes().Update(context.TODO(), trClone, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("TrafficRoute %s update error %v", apexName, err) + } + + return nil +} + +func (kr *KumaRouter) Finalize(_ *flaggerv1.Canary) error { + return nil +} diff --git a/pkg/router/kuma_test.go b/pkg/router/kuma_test.go new file mode 100644 index 00000000..52f10b89 --- /dev/null +++ b/pkg/router/kuma_test.go @@ -0,0 +1,78 @@ +/* +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 TestKumaRouter_Reconcile(t *testing.T) { + canary := newTestSMICanary() + mocks := newFixture(canary) + router := &KumaRouter{ + logger: mocks.logger, + flaggerClient: mocks.flaggerClient, + kumaClient: mocks.meshClient, + kubeClient: mocks.kubeClient, + } + + // init + err := router.Reconcile(canary) + require.NoError(t, err) + + // test insert + trafficRoute, err := router.kumaClient.KumaV1alpha1().TrafficRoutes().Get(context.TODO(), "podinfo", metav1.GetOptions{}) + require.NoError(t, err) + + splits := trafficRoute.Spec.Conf.Split + require.Len(t, splits, 2) + assert.Equal(t, uint32(100), splits[0].Weight) + assert.Equal(t, uint32(0), splits[1].Weight) + +} + +func TestKumaRouter_Routes(t *testing.T) { + canary := newTestSMICanary() + mocks := newFixture(canary) + router := &KumaRouter{ + logger: mocks.logger, + flaggerClient: mocks.flaggerClient, + kumaClient: mocks.meshClient, + kubeClient: mocks.kubeClient, + } + + // init + err := router.Reconcile(canary) + require.NoError(t, err) + + // test set routers + err = router.SetRoutes(canary, 50, 50, false) + require.NoError(t, err) + + trafficRoute, err := router.kumaClient.KumaV1alpha1().TrafficRoutes().Get(context.TODO(), "podinfo", metav1.GetOptions{}) + require.NoError(t, err) + + primary := trafficRoute.Spec.Conf.Split[0] + assert.Equal(t, uint32(50), primary.Weight) + +} diff --git a/test/kuma/install.sh b/test/kuma/install.sh new file mode 100755 index 00000000..fe121e62 --- /dev/null +++ b/test/kuma/install.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -o errexit + +KUMA_VER="1.4.1" +REPO_ROOT=$(git rev-parse --show-toplevel) +mkdir -p ${REPO_ROOT}/bin + +echo ">>> Downloading Kuma ${KUMA_VER}" +curl -SsL https://download.konghq.com/mesh-alpine/kuma-${KUMA_VER}-ubuntu-amd64.tar.gz -o kuma-${KUMA_VER}.tar.gz +tar xvzf kuma-${KUMA_VER}.tar.gz +cp kuma-${KUMA_VER}/bin/kumactl ${REPO_ROOT}/bin/kumactl +chmod +x ${REPO_ROOT}/bin/kumactl + +echo ">>> Installing Kuma ${KUMA_VER}" +${REPO_ROOT}/bin/kumactl install control-plane | kubectl apply -f - + +echo ">>> Installing Kuma Metrics" +${REPO_ROOT}/bin/kumactl install metrics | kubectl apply -f - + +echo ">>> Waiting for Kuma Control Plane to be ready" +kubectl wait --for=condition=ready pod -n kuma-system -l app=kuma-control-plane + +echo ">>> Configuring Default Kuma Mesh" +cat <>> Installing Flagger' +kubectl apply -k ${REPO_ROOT}/kustomize/kuma + +kubectl -n kuma-system set image deployment/flagger flagger=test/flagger:latest +kubectl -n kuma-system rollout status deployment/flagger diff --git a/test/kuma/run.sh b/test/kuma/run.sh new file mode 100755 index 00000000..67153fa9 --- /dev/null +++ b/test/kuma/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -o errexit + +REPO_ROOT=$(git rev-parse --show-toplevel) +DIR="$(cd "$(dirname "$0")" && pwd)" + +"$DIR"/install.sh + +"$REPO_ROOT"/test/workloads/init.sh +"$DIR"/test-canary.sh diff --git a/test/kuma/test-canary.sh b/test/kuma/test-canary.sh new file mode 100755 index 00000000..5b86906b --- /dev/null +++ b/test/kuma/test-canary.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +# This script runs Kuma e2e tests for Canary initialization, analysis and promotion + +set -o errexit + +REPO_ROOT=$(git rev-parse --show-toplevel) + +cat <>> Waiting for primary to be ready' +retries=50 +count=0 +ok=false +until ${ok}; do + kubectl -n test get canary/podinfo | grep 'Initialized' && ok=true || ok=false + sleep 5 + count=$(($count + 1)) + if [[ ${count} -eq ${retries} ]]; then + kubectl -n kuma-system logs deployment/flagger + echo "No more retries left" + exit 1 + fi +done + +echo '✔ Canary initialization test passed' + +passed=$(kubectl -n test get svc/podinfo -o jsonpath='{.spec.selector.app}' 2>&1 | { grep podinfo-primary || true; }) +if [ -z "$passed" ]; then + echo -e '\u2716 podinfo selector test failed' + exit 1 +fi + +echo '✔ Canary service custom metadata test passed' + +echo '>>> Triggering canary deployment' +kubectl -n test set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.1 + +echo '>>> Waiting for canary promotion' +retries=50 +count=0 +ok=false +until ${ok}; do + kubectl -n test describe deployment/podinfo-primary | grep '3.1.1' && ok=true || ok=false + sleep 10 + kubectl -n kuma-system logs deployment/flagger --tail 1 + count=$(($count + 1)) + if [[ ${count} -eq ${retries} ]]; then + kubectl -n kuma-system logs deployment/flagger + echo "No more retries left" + exit 1 + fi +done + +echo '>>> Waiting for canary finalization' +retries=50 +count=0 +ok=false +until ${ok}; do + kubectl -n test get canary/podinfo | grep 'Succeeded' && ok=true || ok=false + sleep 5 + count=$(($count + 1)) + if [[ ${count} -eq ${retries} ]]; then + kubectl -n kuma-system logs deployment/flagger + echo "No more retries left" + exit 1 + fi +done + +echo '✔ Canary promotion test passed' + +cat <>> Triggering canary deployment rollback test' +kubectl -n test set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.2 + +echo '>>> Waiting for canary rollback' +retries=50 +count=0 +ok=false +until ${ok}; do + kubectl -n test get canary/podinfo | grep 'Failed' && ok=true || ok=false + sleep 10 + kubectl -n kuma-system logs deployment/flagger --tail 1 + count=$(($count + 1)) + if [[ ${count} -eq ${retries} ]]; then + kubectl -n kuma-system logs deployment/flagger + echo "No more retries left" + exit 1 + fi +done + +echo '✔ Canary rollback test passed' diff --git a/test/workloads/init.sh b/test/workloads/init.sh index ff42fbe6..2b615a12 100755 --- a/test/workloads/init.sh +++ b/test/workloads/init.sh @@ -13,6 +13,7 @@ echo '>>> Creating test namespace' kubectl create namespace test kubectl label namespace test istio-injection=enabled kubectl annotate namespace test linkerd.io/inject=enabled +kubectl annotate namespace test kuma.io/sidecar-injection=enabled echo '>>> Installing the load tester' kubectl apply -k ${REPO_ROOT}/kustomize/tester