diff --git a/LICENSE b/LICENSE index 261eeb9e9..6e292ed28 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018 Weaveworks. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 478200f10..5910ad9b7 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ You can change the canary analysis _max weight_ and the _step weight_ percentage For a deployment named _podinfo_, a canary promotion can be defined using Flagger's custom resource: ```yaml -apiVersion: flagger.app/v1alpha1 +apiVersion: flagger.app/v1alpha2 kind: Canary metadata: name: podinfo @@ -87,7 +87,7 @@ spec: # the maximum time in seconds for the canary deployment # to make progress before it is rollback (default 600s) progressDeadlineSeconds: 60 - # hpa reference (optional) + # HPA reference (optional) autoscalerRef: apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler @@ -100,16 +100,17 @@ spec: - public-gateway.istio-system.svc.cluster.local # Istio virtual service host names (optional) hosts: - - app.istio.weavedx.com + - app.iowa.weavedx.com canaryAnalysis: # max number of failed metric checks before rollback - threshold: 5 + threshold: 10 # max traffic percentage routed to canary # percentage (0-100) maxWeight: 50 # canary increment step # percentage (0-100) - stepWeight: 10 + stepWeight: 5 + # Istio Prometheus checks metrics: - name: istio_requests_total # minimum req success rate (non 5xx responses) @@ -121,6 +122,14 @@ spec: # milliseconds threshold: 500 interval: 30s + # external checks (optional) + webhooks: + - name: integration-tests + url: http://podinfo.test:9898/echo + timeout: 1m + metadata: + test: "all" + token: "16688eb5e9f289f1991c" ``` The canary analysis is using the following promql queries: @@ -166,6 +175,22 @@ histogram_quantile(0.99, ) ``` +The canary analysis can be extended with webhooks. +Flagger would call a URL (HTTP POST) and determine from the response status code (HTTP 2xx) if the canary is failing or not. + +Webhook payload: + +```json +{ + "name": "podinfo", + "namespace": "test", + "metadata": { + "test": "all", + "token": "16688eb5e9f289f1991c" + } +} +``` + ### Automated canary analysis, promotions and rollbacks Create a test namespace with Istio sidecar injection enabled: diff --git a/artifacts/canaries/canary.yaml b/artifacts/canaries/canary.yaml index 08bae8a0d..5547df555 100644 --- a/artifacts/canaries/canary.yaml +++ b/artifacts/canaries/canary.yaml @@ -1,4 +1,4 @@ -apiVersion: flagger.app/v1alpha1 +apiVersion: flagger.app/v1alpha2 kind: Canary metadata: name: podinfo @@ -35,6 +35,7 @@ spec: # canary increment step # percentage (0-100) stepWeight: 5 + # Istio Prometheus checks metrics: - name: istio_requests_total # minimum req success rate (non 5xx responses) @@ -46,3 +47,11 @@ spec: # milliseconds threshold: 500 interval: 30s + # external checks (optional) + webhooks: + - name: integration-tests + url: http://podinfo.test:9898/echo + timeout: 1m + metadata: + test: "all" + token: "16688eb5e9f289f1991c" \ No newline at end of file diff --git a/artifacts/flagger/crd.yaml b/artifacts/flagger/crd.yaml index 9b7da8d16..6304a3908 100644 --- a/artifacts/flagger/crd.yaml +++ b/artifacts/flagger/crd.yaml @@ -4,11 +4,14 @@ metadata: name: canaries.flagger.app spec: group: flagger.app - version: v1alpha1 + version: v1alpha2 versions: - - name: v1alpha1 + - name: v1alpha2 served: true storage: true + - name: v1alpha1 + served: true + storage: false names: plural: canaries singular: canary @@ -26,6 +29,8 @@ spec: progressDeadlineSeconds: type: number targetRef: + type: object + required: ['apiVersion', 'kind', 'name'] properties: apiVersion: type: string @@ -34,6 +39,8 @@ spec: name: type: string autoscalerRef: + type: object + required: ['apiVersion', 'kind', 'name'] properties: apiVersion: type: string @@ -42,6 +49,8 @@ spec: name: type: string service: + type: object + required: ['port'] properties: port: type: number @@ -58,6 +67,7 @@ spec: properties: items: type: object + required: ['name', 'interval', 'threshold'] properties: name: type: string @@ -66,3 +76,18 @@ spec: pattern: "^[0-9]+(m)" threshold: type: number + webhooks: + type: array + properties: + items: + type: object + required: ['name', 'url', 'timeout'] + properties: + name: + type: string + url: + type: string + format: url + timeout: + type: string + pattern: "^[0-9]+(s)" diff --git a/artifacts/flagger/deployment.yaml b/artifacts/flagger/deployment.yaml index 3ca1f7973..fc1328459 100644 --- a/artifacts/flagger/deployment.yaml +++ b/artifacts/flagger/deployment.yaml @@ -22,7 +22,7 @@ spec: serviceAccountName: flagger containers: - name: flagger - image: quay.io/stefanprodan/flagger:0.1.2 + image: quay.io/stefanprodan/flagger:0.2.0-alpha.1 imagePullPolicy: Always ports: - name: http diff --git a/charts/flagger/Chart.yaml b/charts/flagger/Chart.yaml index f0fc8150c..64f62bfdd 100644 --- a/charts/flagger/Chart.yaml +++ b/charts/flagger/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 name: flagger version: 0.1.2 -appVersion: 0.1.2 +appVersion: 0.2.0-alpha.1 kubeVersion: ">=1.9.0-0" engine: gotpl description: Flagger is a Kubernetes operator that automates the promotion of canary deployments using Istio routing for traffic shifting and Prometheus metrics for canary analysis. diff --git a/charts/flagger/templates/crd.yaml b/charts/flagger/templates/crd.yaml index 58164a920..708ecd86a 100644 --- a/charts/flagger/templates/crd.yaml +++ b/charts/flagger/templates/crd.yaml @@ -3,15 +3,16 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: canaries.flagger.app - annotations: - "helm.sh/resource-policy": keep spec: group: flagger.app - version: v1alpha1 + version: v1alpha2 versions: - - name: v1alpha1 + - name: v1alpha2 served: true storage: true + - name: v1alpha1 + served: true + storage: false names: plural: canaries singular: canary @@ -22,13 +23,15 @@ spec: properties: spec: required: - - targetRef - - service - - canaryAnalysis + - targetRef + - service + - canaryAnalysis properties: progressDeadlineSeconds: type: number targetRef: + type: object + required: ['apiVersion', 'kind', 'name'] properties: apiVersion: type: string @@ -37,6 +40,8 @@ spec: name: type: string autoscalerRef: + type: object + required: ['apiVersion', 'kind', 'name'] properties: apiVersion: type: string @@ -45,6 +50,8 @@ spec: name: type: string service: + type: object + required: ['port'] properties: port: type: number @@ -61,6 +68,7 @@ spec: properties: items: type: object + required: ['name', 'interval', 'threshold'] properties: name: type: string @@ -69,4 +77,20 @@ spec: pattern: "^[0-9]+(m)" threshold: type: number + webhooks: + type: array + properties: + items: + type: object + required: ['name', 'url', 'timeout'] + properties: + name: + type: string + url: + type: string + format: url + timeout: + type: string + pattern: "^[0-9]+(s)" + {{- end }} diff --git a/charts/flagger/values.yaml b/charts/flagger/values.yaml index 15a0b469f..5b5f7da40 100644 --- a/charts/flagger/values.yaml +++ b/charts/flagger/values.yaml @@ -2,7 +2,7 @@ image: repository: quay.io/stefanprodan/flagger - tag: 0.1.2 + tag: 0.2.0-alpha.1 pullPolicy: IfNotPresent controlLoopInterval: "10s" diff --git a/cmd/flagger/main.go b/cmd/flagger/main.go index 6b6766636..23136c691 100644 --- a/cmd/flagger/main.go +++ b/cmd/flagger/main.go @@ -77,7 +77,7 @@ func main() { } flaggerInformerFactory := informers.NewSharedInformerFactory(flaggerClient, time.Second*30) - canaryInformer := flaggerInformerFactory.Flagger().V1alpha1().Canaries() + canaryInformer := flaggerInformerFactory.Flagger().V1alpha2().Canaries() logger.Infof("Starting flagger version %s revision %s", version.VERSION, version.REVISION) diff --git a/docs/gitbook/how-it-works.md b/docs/gitbook/how-it-works.md index beabd7a5f..53fd864cf 100644 --- a/docs/gitbook/how-it-works.md +++ b/docs/gitbook/how-it-works.md @@ -9,7 +9,7 @@ For a deployment named _podinfo_, a canary promotion can be defined using Flagger's custom resource: ```yaml -apiVersion: flagger.app/v1alpha1 +apiVersion: flagger.app/v1alpha2 kind: Canary metadata: name: podinfo @@ -23,7 +23,7 @@ spec: # the maximum time in seconds for the canary deployment # to make progress before it is rollback (default 600s) progressDeadlineSeconds: 60 - # hpa reference (optional) + # HPA reference (optional) autoscalerRef: apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler @@ -36,16 +36,17 @@ spec: - public-gateway.istio-system.svc.cluster.local # Istio virtual service host names (optional) hosts: - - app.istio.weavedx.com + - app.iowa.weavedx.com canaryAnalysis: # max number of failed metric checks before rollback - threshold: 5 + threshold: 10 # max traffic percentage routed to canary # percentage (0-100) maxWeight: 50 # canary increment step # percentage (0-100) - stepWeight: 10 + stepWeight: 5 + # Istio Prometheus checks metrics: - name: istio_requests_total # minimum req success rate (non 5xx responses) @@ -57,7 +58,14 @@ spec: # milliseconds threshold: 500 interval: 30s - + # external checks (optional) + webhooks: + - name: integration-tests + url: http://podinfo.test:9898/echo + timeout: 1m + metadata: + test: "all" + token: "16688eb5e9f289f1991c" ``` ### Canary Deployment @@ -96,12 +104,54 @@ Gated canary promotion stages: You can change the canary analysis _max weight_ and the _step weight_ percentage in the Flagger's custom resource. -### Canary Analisys +### Canary Analysis - The canary analysis is using the following Prometheus queries: +Spec: + +```yaml + canaryAnalysis: + # 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: 5 +``` + +You can determine the minimum time that it takes to validate and promote a canary deployment using this formula: + +``` +controlLoopInterval * (maxWeight / stepWeight) +``` + +And the time it takes for a canary to be rollback: + +``` +controlLoopInterval * threshold +``` + +### HTTP Metrics + +The canary analysis is using the following Prometheus queries: **HTTP requests success rate percentage** +Spec: + +```yaml + canaryAnalysis: + metrics: + - name: istio_requests_total + # minimum req success rate (non 5xx responses) + # percentage (0-100) + threshold: 99 + interval: 1m +``` + +Query: + ```javascript sum( rate( @@ -127,6 +177,20 @@ sum( **HTTP requests milliseconds duration P99** +Spec: + +```yaml + canaryAnalysis: + metrics: + - name: istio_request_duration_seconds_bucket + # maximum req duration P99 + # milliseconds + threshold: 500 + interval: 1m +``` + +Query: + ```javascript histogram_quantile(0.99, sum( @@ -141,3 +205,42 @@ histogram_quantile(0.99, ) ``` +### Webhooks + +The canary analysis can be extended with webhooks. +Flagger would call a URL (HTTP POST) and determine from the response status code (HTTP 2xx) if the canary is failing or not. + +Spec: + +```yaml + canaryAnalysis: + webhooks: + - name: integration-tests + url: http://podinfo.test:9898/echo + timeout: 1m + metadata: + test: "all" + token: "16688eb5e9f289f1991c" +``` + +Webhook payload: + +```json +{ + "name": "podinfo", + "namespace": "test", + "metadata": { + "test": "all", + "token": "16688eb5e9f289f1991c" + } +} +``` + +Response status codes: + +* 200-202 - advance canary by increasing the traffic weight +* timeout or non-2xx - halt advancement and increment failed checks + +On a non-2xx response Flagger will include the response body (if any) in the failed checks log and Kubernetes events. + + diff --git a/docs/gitbook/install/install-istio.md b/docs/gitbook/install/install-istio.md index 784b0c282..6078571c2 100644 --- a/docs/gitbook/install/install-istio.md +++ b/docs/gitbook/install/install-istio.md @@ -333,7 +333,7 @@ kubectl create secret generic cert-manager-credentials \ Create a letsencrypt issuer for CloudDNS \(replace `email@example.com` with a valid email address and `my-gcp-project`with your project ID\): ```yaml -apiVersion: certmanager.k8s.io/v1alpha1 +apiVersion: v1alpha2 kind: Issuer metadata: name: letsencrypt-prod @@ -363,7 +363,7 @@ kubectl apply -f ./letsencrypt-issuer.yaml Create a wildcard certificate \(replace `example.com` with your domain\): ```yaml -apiVersion: certmanager.k8s.io/v1alpha1 +apiVersion: v1alpha2 kind: Certificate metadata: name: istio-gateway diff --git a/docs/gitbook/usage/progressive-delivery.md b/docs/gitbook/usage/progressive-delivery.md index 30d5832e2..b7e1212cc 100644 --- a/docs/gitbook/usage/progressive-delivery.md +++ b/docs/gitbook/usage/progressive-delivery.md @@ -20,7 +20,7 @@ kubectl apply -f ${REPO}/artifacts/canaries/hpa.yaml Create a canary custom resource \(replace example.com with your own domain\): ```yaml -apiVersion: flagger.app/v1alpha1 +apiVersion: v1alpha2 kind: Canary metadata: name: podinfo diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index cfcb54191..95ef57c33 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -23,6 +23,6 @@ CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-ge ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ github.com/stefanprodan/flagger/pkg/client github.com/stefanprodan/flagger/pkg/apis \ - flagger:v1alpha1 \ + flagger:v1alpha2 \ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt diff --git a/pkg/apis/flagger/v1alpha1/doc.go b/pkg/apis/flagger/v1alpha2/doc.go similarity index 89% rename from pkg/apis/flagger/v1alpha1/doc.go rename to pkg/apis/flagger/v1alpha2/doc.go index 6256468c0..c22d2e169 100755 --- a/pkg/apis/flagger/v1alpha1/doc.go +++ b/pkg/apis/flagger/v1alpha2/doc.go @@ -16,6 +16,6 @@ limitations under the License. // +k8s:deepcopy-gen=package -// Package v1alpha1 is the v1alpha1 version of the API. +// Package v1alpha2 is the v1alpha2 version of the API. // +groupName=flagger.app -package v1alpha1 +package v1alpha2 diff --git a/pkg/apis/flagger/v1alpha1/register.go b/pkg/apis/flagger/v1alpha2/register.go similarity index 97% rename from pkg/apis/flagger/v1alpha1/register.go rename to pkg/apis/flagger/v1alpha2/register.go index 47c65f177..43ac3cb4b 100755 --- a/pkg/apis/flagger/v1alpha1/register.go +++ b/pkg/apis/flagger/v1alpha2/register.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1alpha2 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,7 +25,7 @@ import ( ) // SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: rollout.GroupName, Version: "v1alpha1"} +var SchemeGroupVersion = schema.GroupVersion{Group: rollout.GroupName, Version: "v1alpha2"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { diff --git a/pkg/apis/flagger/v1alpha1/types.go b/pkg/apis/flagger/v1alpha2/types.go similarity index 76% rename from pkg/apis/flagger/v1alpha1/types.go rename to pkg/apis/flagger/v1alpha2/types.go index d629866bb..fc71ff917 100755 --- a/pkg/apis/flagger/v1alpha1/types.go +++ b/pkg/apis/flagger/v1alpha2/types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1alpha2 import ( hpav1 "k8s.io/api/autoscaling/v1" @@ -96,19 +96,37 @@ type CanaryService struct { // CanaryAnalysis is used to describe how the analysis should be done type CanaryAnalysis struct { - Threshold int `json:"threshold"` - MaxWeight int `json:"maxWeight"` - StepWeight int `json:"stepWeight"` - Metrics []CanaryMetric `json:"metrics"` + Threshold int `json:"threshold"` + MaxWeight int `json:"maxWeight"` + StepWeight int `json:"stepWeight"` + Metrics []CanaryMetric `json:"metrics"` + Webhooks []CanaryWebhook `json:"webhooks,omitempty"` } -// CanaryMetric hold the reference to Istio metrics used for canary analysis +// CanaryMetric holds the reference to Istio metrics used for canary analysis type CanaryMetric struct { Name string `json:"name"` Interval string `json:"interval"` Threshold int `json:"threshold"` } +// CanaryWebhook holds the reference to external checks used for canary analysis +type CanaryWebhook struct { + Name string `json:"name"` + URL string `json:"url"` + Timeout string `json:"timeout"` + // +optional + Metadata *map[string]string `json:"metadata,omitempty"` +} + +// CanaryWebhookPayload holds the deployment info and metadata sent to webhooks +type CanaryWebhookPayload struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Metadata *map[string]string `json:"metadata,omitempty"` +} + +// GetProgressDeadlineSeconds returns the progress deadline (default 600s) func (c *Canary) GetProgressDeadlineSeconds() int { if c.Spec.ProgressDeadlineSeconds != nil { return int(*c.Spec.ProgressDeadlineSeconds) diff --git a/pkg/apis/flagger/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/flagger/v1alpha2/zz_generated.deepcopy.go similarity index 76% rename from pkg/apis/flagger/v1alpha1/zz_generated.deepcopy.go rename to pkg/apis/flagger/v1alpha2/zz_generated.deepcopy.go index c0361ad46..698ddda3a 100644 --- a/pkg/apis/flagger/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/flagger/v1alpha2/zz_generated.deepcopy.go @@ -18,7 +18,7 @@ limitations under the License. // Code generated by deepcopy-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( runtime "k8s.io/apimachinery/pkg/runtime" @@ -60,6 +60,13 @@ func (in *CanaryAnalysis) DeepCopyInto(out *CanaryAnalysis) { *out = make([]CanaryMetric, len(*in)) copy(*out, *in) } + if in.Webhooks != nil { + in, out := &in.Webhooks, &out.Webhooks + *out = make([]CanaryWebhook, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -189,3 +196,57 @@ func (in *CanaryStatus) DeepCopy() *CanaryStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CanaryWebhook) DeepCopyInto(out *CanaryWebhook) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *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 CanaryWebhook. +func (in *CanaryWebhook) DeepCopy() *CanaryWebhook { + if in == nil { + return nil + } + out := new(CanaryWebhook) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CanaryWebhookPayload) DeepCopyInto(out *CanaryWebhookPayload) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *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 CanaryWebhookPayload. +func (in *CanaryWebhookPayload) DeepCopy() *CanaryWebhookPayload { + if in == nil { + return nil + } + out := new(CanaryWebhookPayload) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 449f44084..7f267a53b 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -19,7 +19,7 @@ limitations under the License. package versioned import ( - flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1" + flaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha2" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -27,27 +27,27 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface - FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface + FlaggerV1alpha2() flaggerv1alpha2.FlaggerV1alpha2Interface // Deprecated: please explicitly pick a version if possible. - Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface + Flagger() flaggerv1alpha2.FlaggerV1alpha2Interface } // Clientset contains the clients for groups. Each group has exactly one // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - flaggerV1alpha1 *flaggerv1alpha1.FlaggerV1alpha1Client + flaggerV1alpha2 *flaggerv1alpha2.FlaggerV1alpha2Client } -// FlaggerV1alpha1 retrieves the FlaggerV1alpha1Client -func (c *Clientset) FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface { - return c.flaggerV1alpha1 +// FlaggerV1alpha2 retrieves the FlaggerV1alpha2Client +func (c *Clientset) FlaggerV1alpha2() flaggerv1alpha2.FlaggerV1alpha2Interface { + return c.flaggerV1alpha2 } // Deprecated: Flagger retrieves the default version of FlaggerClient. // Please explicitly pick a version. -func (c *Clientset) Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface { - return c.flaggerV1alpha1 +func (c *Clientset) Flagger() flaggerv1alpha2.FlaggerV1alpha2Interface { + return c.flaggerV1alpha2 } // Discovery retrieves the DiscoveryClient @@ -66,7 +66,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error - cs.flaggerV1alpha1, err = flaggerv1alpha1.NewForConfig(&configShallowCopy) + cs.flaggerV1alpha2, err = flaggerv1alpha2.NewForConfig(&configShallowCopy) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset - cs.flaggerV1alpha1 = flaggerv1alpha1.NewForConfigOrDie(c) + cs.flaggerV1alpha2 = flaggerv1alpha2.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -91,7 +91,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset - cs.flaggerV1alpha1 = flaggerv1alpha1.New(c) + cs.flaggerV1alpha2 = flaggerv1alpha2.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index c9815dd1c..d378d2b1d 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -20,8 +20,8 @@ package fake import ( clientset "github.com/stefanprodan/flagger/pkg/client/clientset/versioned" - flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1" - fakeflaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake" + flaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha2" + fakeflaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -71,12 +71,12 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} -// FlaggerV1alpha1 retrieves the FlaggerV1alpha1Client -func (c *Clientset) FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface { - return &fakeflaggerv1alpha1.FakeFlaggerV1alpha1{Fake: &c.Fake} +// FlaggerV1alpha2 retrieves the FlaggerV1alpha2Client +func (c *Clientset) FlaggerV1alpha2() flaggerv1alpha2.FlaggerV1alpha2Interface { + return &fakeflaggerv1alpha2.FakeFlaggerV1alpha2{Fake: &c.Fake} } -// Flagger retrieves the FlaggerV1alpha1Client -func (c *Clientset) Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface { - return &fakeflaggerv1alpha1.FakeFlaggerV1alpha1{Fake: &c.Fake} +// Flagger retrieves the FlaggerV1alpha2Client +func (c *Clientset) Flagger() flaggerv1alpha2.FlaggerV1alpha2Interface { + return &fakeflaggerv1alpha2.FakeFlaggerV1alpha2{Fake: &c.Fake} } diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 691e1cdf8..ad9c1316b 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -19,7 +19,7 @@ limitations under the License. package fake import ( - flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -50,5 +50,5 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { - flaggerv1alpha1.AddToScheme(scheme) + flaggerv1alpha2.AddToScheme(scheme) } diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 621cde3db..d38601490 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -19,7 +19,7 @@ limitations under the License. package scheme import ( - flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -50,5 +50,5 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { - flaggerv1alpha1.AddToScheme(scheme) + flaggerv1alpha2.AddToScheme(scheme) } diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/canary.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/canary.go similarity index 79% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/canary.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/canary.go index 8b8b52f18..05e7bab4b 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/canary.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/canary.go @@ -16,10 +16,10 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" scheme "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -35,15 +35,15 @@ type CanariesGetter interface { // CanaryInterface has methods to work with Canary resources. type CanaryInterface interface { - Create(*v1alpha1.Canary) (*v1alpha1.Canary, error) - Update(*v1alpha1.Canary) (*v1alpha1.Canary, error) - UpdateStatus(*v1alpha1.Canary) (*v1alpha1.Canary, error) + Create(*v1alpha2.Canary) (*v1alpha2.Canary, error) + Update(*v1alpha2.Canary) (*v1alpha2.Canary, error) + UpdateStatus(*v1alpha2.Canary) (*v1alpha2.Canary, error) Delete(name string, options *v1.DeleteOptions) error DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error - Get(name string, options v1.GetOptions) (*v1alpha1.Canary, error) - List(opts v1.ListOptions) (*v1alpha1.CanaryList, error) + Get(name string, options v1.GetOptions) (*v1alpha2.Canary, error) + List(opts v1.ListOptions) (*v1alpha2.CanaryList, error) Watch(opts v1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Canary, err error) CanaryExpansion } @@ -54,7 +54,7 @@ type canaries struct { } // newCanaries returns a Canaries -func newCanaries(c *FlaggerV1alpha1Client, namespace string) *canaries { +func newCanaries(c *FlaggerV1alpha2Client, namespace string) *canaries { return &canaries{ client: c.RESTClient(), ns: namespace, @@ -62,8 +62,8 @@ func newCanaries(c *FlaggerV1alpha1Client, namespace string) *canaries { } // Get takes name of the canary, and returns the corresponding canary object, and an error if there is any. -func (c *canaries) Get(name string, options v1.GetOptions) (result *v1alpha1.Canary, err error) { - result = &v1alpha1.Canary{} +func (c *canaries) Get(name string, options v1.GetOptions) (result *v1alpha2.Canary, err error) { + result = &v1alpha2.Canary{} err = c.client.Get(). Namespace(c.ns). Resource("canaries"). @@ -75,8 +75,8 @@ func (c *canaries) Get(name string, options v1.GetOptions) (result *v1alpha1.Can } // List takes label and field selectors, and returns the list of Canaries that match those selectors. -func (c *canaries) List(opts v1.ListOptions) (result *v1alpha1.CanaryList, err error) { - result = &v1alpha1.CanaryList{} +func (c *canaries) List(opts v1.ListOptions) (result *v1alpha2.CanaryList, err error) { + result = &v1alpha2.CanaryList{} err = c.client.Get(). Namespace(c.ns). Resource("canaries"). @@ -97,8 +97,8 @@ func (c *canaries) Watch(opts v1.ListOptions) (watch.Interface, error) { } // Create takes the representation of a canary and creates it. Returns the server's representation of the canary, and an error, if there is any. -func (c *canaries) Create(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) { - result = &v1alpha1.Canary{} +func (c *canaries) Create(canary *v1alpha2.Canary) (result *v1alpha2.Canary, err error) { + result = &v1alpha2.Canary{} err = c.client.Post(). Namespace(c.ns). Resource("canaries"). @@ -109,8 +109,8 @@ func (c *canaries) Create(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err } // Update takes the representation of a canary and updates it. Returns the server's representation of the canary, and an error, if there is any. -func (c *canaries) Update(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) { - result = &v1alpha1.Canary{} +func (c *canaries) Update(canary *v1alpha2.Canary) (result *v1alpha2.Canary, err error) { + result = &v1alpha2.Canary{} err = c.client.Put(). Namespace(c.ns). Resource("canaries"). @@ -124,8 +124,8 @@ func (c *canaries) Update(canary *v1alpha1.Canary) (result *v1alpha1.Canary, 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 *canaries) UpdateStatus(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) { - result = &v1alpha1.Canary{} +func (c *canaries) UpdateStatus(canary *v1alpha2.Canary) (result *v1alpha2.Canary, err error) { + result = &v1alpha2.Canary{} err = c.client.Put(). Namespace(c.ns). Resource("canaries"). @@ -160,8 +160,8 @@ func (c *canaries) DeleteCollection(options *v1.DeleteOptions, listOptions v1.Li } // Patch applies the patch and returns the patched canary. -func (c *canaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error) { - result = &v1alpha1.Canary{} +func (c *canaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Canary, err error) { + result = &v1alpha2.Canary{} err = c.client.Patch(pt). Namespace(c.ns). Resource("canaries"). diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/doc.go similarity index 97% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/doc.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/doc.go index 20b3d7fd1..0b3efa15b 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/doc.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/doc.go @@ -17,4 +17,4 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated typed clients. -package v1alpha1 +package v1alpha2 diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/doc.go similarity index 100% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/doc.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/doc.go diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_canary.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_canary.go similarity index 76% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_canary.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_canary.go index 157beb64a..5df760808 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_canary.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_canary.go @@ -19,7 +19,7 @@ limitations under the License. package fake import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -30,29 +30,29 @@ import ( // FakeCanaries implements CanaryInterface type FakeCanaries struct { - Fake *FakeFlaggerV1alpha1 + Fake *FakeFlaggerV1alpha2 ns string } -var canariesResource = schema.GroupVersionResource{Group: "flagger.app", Version: "v1alpha1", Resource: "canaries"} +var canariesResource = schema.GroupVersionResource{Group: "flagger.app", Version: "v1alpha2", Resource: "canaries"} -var canariesKind = schema.GroupVersionKind{Group: "flagger.app", Version: "v1alpha1", Kind: "Canary"} +var canariesKind = schema.GroupVersionKind{Group: "flagger.app", Version: "v1alpha2", Kind: "Canary"} // Get takes name of the canary, and returns the corresponding canary object, and an error if there is any. -func (c *FakeCanaries) Get(name string, options v1.GetOptions) (result *v1alpha1.Canary, err error) { +func (c *FakeCanaries) Get(name string, options v1.GetOptions) (result *v1alpha2.Canary, err error) { obj, err := c.Fake. - Invokes(testing.NewGetAction(canariesResource, c.ns, name), &v1alpha1.Canary{}) + Invokes(testing.NewGetAction(canariesResource, c.ns, name), &v1alpha2.Canary{}) if obj == nil { return nil, err } - return obj.(*v1alpha1.Canary), err + return obj.(*v1alpha2.Canary), err } // List takes label and field selectors, and returns the list of Canaries that match those selectors. -func (c *FakeCanaries) List(opts v1.ListOptions) (result *v1alpha1.CanaryList, err error) { +func (c *FakeCanaries) List(opts v1.ListOptions) (result *v1alpha2.CanaryList, err error) { obj, err := c.Fake. - Invokes(testing.NewListAction(canariesResource, canariesKind, c.ns, opts), &v1alpha1.CanaryList{}) + Invokes(testing.NewListAction(canariesResource, canariesKind, c.ns, opts), &v1alpha2.CanaryList{}) if obj == nil { return nil, err @@ -62,8 +62,8 @@ func (c *FakeCanaries) List(opts v1.ListOptions) (result *v1alpha1.CanaryList, e if label == nil { label = labels.Everything() } - list := &v1alpha1.CanaryList{ListMeta: obj.(*v1alpha1.CanaryList).ListMeta} - for _, item := range obj.(*v1alpha1.CanaryList).Items { + list := &v1alpha2.CanaryList{ListMeta: obj.(*v1alpha2.CanaryList).ListMeta} + for _, item := range obj.(*v1alpha2.CanaryList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } @@ -79,43 +79,43 @@ func (c *FakeCanaries) Watch(opts v1.ListOptions) (watch.Interface, error) { } // Create takes the representation of a canary and creates it. Returns the server's representation of the canary, and an error, if there is any. -func (c *FakeCanaries) Create(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) { +func (c *FakeCanaries) Create(canary *v1alpha2.Canary) (result *v1alpha2.Canary, err error) { obj, err := c.Fake. - Invokes(testing.NewCreateAction(canariesResource, c.ns, canary), &v1alpha1.Canary{}) + Invokes(testing.NewCreateAction(canariesResource, c.ns, canary), &v1alpha2.Canary{}) if obj == nil { return nil, err } - return obj.(*v1alpha1.Canary), err + return obj.(*v1alpha2.Canary), err } // Update takes the representation of a canary and updates it. Returns the server's representation of the canary, and an error, if there is any. -func (c *FakeCanaries) Update(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) { +func (c *FakeCanaries) Update(canary *v1alpha2.Canary) (result *v1alpha2.Canary, err error) { obj, err := c.Fake. - Invokes(testing.NewUpdateAction(canariesResource, c.ns, canary), &v1alpha1.Canary{}) + Invokes(testing.NewUpdateAction(canariesResource, c.ns, canary), &v1alpha2.Canary{}) if obj == nil { return nil, err } - return obj.(*v1alpha1.Canary), err + return obj.(*v1alpha2.Canary), 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 *FakeCanaries) UpdateStatus(canary *v1alpha1.Canary) (*v1alpha1.Canary, error) { +func (c *FakeCanaries) UpdateStatus(canary *v1alpha2.Canary) (*v1alpha2.Canary, error) { obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(canariesResource, "status", c.ns, canary), &v1alpha1.Canary{}) + Invokes(testing.NewUpdateSubresourceAction(canariesResource, "status", c.ns, canary), &v1alpha2.Canary{}) if obj == nil { return nil, err } - return obj.(*v1alpha1.Canary), err + return obj.(*v1alpha2.Canary), err } // Delete takes name of the canary and deletes it. Returns an error if one occurs. func (c *FakeCanaries) Delete(name string, options *v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(canariesResource, c.ns, name), &v1alpha1.Canary{}) + Invokes(testing.NewDeleteAction(canariesResource, c.ns, name), &v1alpha2.Canary{}) return err } @@ -124,17 +124,17 @@ func (c *FakeCanaries) Delete(name string, options *v1.DeleteOptions) error { func (c *FakeCanaries) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { action := testing.NewDeleteCollectionAction(canariesResource, c.ns, listOptions) - _, err := c.Fake.Invokes(action, &v1alpha1.CanaryList{}) + _, err := c.Fake.Invokes(action, &v1alpha2.CanaryList{}) return err } // Patch applies the patch and returns the patched canary. -func (c *FakeCanaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error) { +func (c *FakeCanaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Canary, err error) { obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(canariesResource, c.ns, name, data, subresources...), &v1alpha1.Canary{}) + Invokes(testing.NewPatchSubresourceAction(canariesResource, c.ns, name, data, subresources...), &v1alpha2.Canary{}) if obj == nil { return nil, err } - return obj.(*v1alpha1.Canary), err + return obj.(*v1alpha2.Canary), err } diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_flagger_client.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_flagger_client.go similarity index 76% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_flagger_client.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_flagger_client.go index 80c6570c5..38f941b1b 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/fake/fake_flagger_client.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/fake/fake_flagger_client.go @@ -19,22 +19,22 @@ limitations under the License. package fake import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha2" rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) -type FakeFlaggerV1alpha1 struct { +type FakeFlaggerV1alpha2 struct { *testing.Fake } -func (c *FakeFlaggerV1alpha1) Canaries(namespace string) v1alpha1.CanaryInterface { +func (c *FakeFlaggerV1alpha2) Canaries(namespace string) v1alpha2.CanaryInterface { return &FakeCanaries{c, namespace} } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. -func (c *FakeFlaggerV1alpha1) RESTClient() rest.Interface { +func (c *FakeFlaggerV1alpha2) RESTClient() rest.Interface { var ret *rest.RESTClient return ret } diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/flagger_client.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/flagger_client.go similarity index 67% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/flagger_client.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/flagger_client.go index bcaf9a44a..ca826fa9e 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/flagger_client.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/flagger_client.go @@ -16,31 +16,31 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/scheme" serializer "k8s.io/apimachinery/pkg/runtime/serializer" rest "k8s.io/client-go/rest" ) -type FlaggerV1alpha1Interface interface { +type FlaggerV1alpha2Interface interface { RESTClient() rest.Interface CanariesGetter } -// FlaggerV1alpha1Client is used to interact with features provided by the flagger.app group. -type FlaggerV1alpha1Client struct { +// FlaggerV1alpha2Client is used to interact with features provided by the flagger.app group. +type FlaggerV1alpha2Client struct { restClient rest.Interface } -func (c *FlaggerV1alpha1Client) Canaries(namespace string) CanaryInterface { +func (c *FlaggerV1alpha2Client) Canaries(namespace string) CanaryInterface { return newCanaries(c, namespace) } -// NewForConfig creates a new FlaggerV1alpha1Client for the given config. -func NewForConfig(c *rest.Config) (*FlaggerV1alpha1Client, error) { +// NewForConfig creates a new FlaggerV1alpha2Client for the given config. +func NewForConfig(c *rest.Config) (*FlaggerV1alpha2Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err @@ -49,12 +49,12 @@ func NewForConfig(c *rest.Config) (*FlaggerV1alpha1Client, error) { if err != nil { return nil, err } - return &FlaggerV1alpha1Client{client}, nil + return &FlaggerV1alpha2Client{client}, nil } -// NewForConfigOrDie creates a new FlaggerV1alpha1Client for the given config and +// NewForConfigOrDie creates a new FlaggerV1alpha2Client for the given config and // panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *FlaggerV1alpha1Client { +func NewForConfigOrDie(c *rest.Config) *FlaggerV1alpha2Client { client, err := NewForConfig(c) if err != nil { panic(err) @@ -62,13 +62,13 @@ func NewForConfigOrDie(c *rest.Config) *FlaggerV1alpha1Client { return client } -// New creates a new FlaggerV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *FlaggerV1alpha1Client { - return &FlaggerV1alpha1Client{c} +// New creates a new FlaggerV1alpha2Client for the given RESTClient. +func New(c rest.Interface) *FlaggerV1alpha2Client { + return &FlaggerV1alpha2Client{c} } func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion + gv := v1alpha2.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} @@ -82,7 +82,7 @@ func setConfigDefaults(config *rest.Config) error { // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. -func (c *FlaggerV1alpha1Client) RESTClient() rest.Interface { +func (c *FlaggerV1alpha2Client) RESTClient() rest.Interface { if c == nil { return nil } diff --git a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/generated_expansion.go similarity index 97% rename from pkg/client/clientset/versioned/typed/flagger/v1alpha1/generated_expansion.go rename to pkg/client/clientset/versioned/typed/flagger/v1alpha2/generated_expansion.go index 8c4a08fda..eb1b8f0d2 100644 --- a/pkg/client/clientset/versioned/typed/flagger/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/flagger/v1alpha2/generated_expansion.go @@ -16,6 +16,6 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 type CanaryExpansion interface{} diff --git a/pkg/client/informers/externalversions/flagger/interface.go b/pkg/client/informers/externalversions/flagger/interface.go index 07bd738c2..420481640 100644 --- a/pkg/client/informers/externalversions/flagger/interface.go +++ b/pkg/client/informers/externalversions/flagger/interface.go @@ -19,14 +19,14 @@ limitations under the License. package flagger import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha2" internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces" ) // 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 + // V1alpha2 provides access to shared informers for resources in V1alpha2. + V1alpha2() v1alpha2.Interface } type group struct { @@ -40,7 +40,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList 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) +// V1alpha2 returns a new v1alpha2.Interface. +func (g *group) V1alpha2() v1alpha2.Interface { + return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/flagger/v1alpha1/canary.go b/pkg/client/informers/externalversions/flagger/v1alpha2/canary.go similarity index 84% rename from pkg/client/informers/externalversions/flagger/v1alpha1/canary.go rename to pkg/client/informers/externalversions/flagger/v1alpha2/canary.go index 89543119b..6e450d35c 100644 --- a/pkg/client/informers/externalversions/flagger/v1alpha1/canary.go +++ b/pkg/client/informers/externalversions/flagger/v1alpha2/canary.go @@ -16,15 +16,15 @@ limitations under the License. // Code generated by informer-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( time "time" - flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" versioned "github.com/stefanprodan/flagger/pkg/client/clientset/versioned" internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -35,7 +35,7 @@ import ( // Canaries. type CanaryInformer interface { Informer() cache.SharedIndexInformer - Lister() v1alpha1.CanaryLister + Lister() v1alpha2.CanaryLister } type canaryInformer struct { @@ -61,16 +61,16 @@ func NewFilteredCanaryInformer(client versioned.Interface, namespace string, res if tweakListOptions != nil { tweakListOptions(&options) } - return client.FlaggerV1alpha1().Canaries(namespace).List(options) + return client.FlaggerV1alpha2().Canaries(namespace).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.FlaggerV1alpha1().Canaries(namespace).Watch(options) + return client.FlaggerV1alpha2().Canaries(namespace).Watch(options) }, }, - &flaggerv1alpha1.Canary{}, + &flaggerv1alpha2.Canary{}, resyncPeriod, indexers, ) @@ -81,9 +81,9 @@ func (f *canaryInformer) defaultInformer(client versioned.Interface, resyncPerio } func (f *canaryInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&flaggerv1alpha1.Canary{}, f.defaultInformer) + return f.factory.InformerFor(&flaggerv1alpha2.Canary{}, f.defaultInformer) } -func (f *canaryInformer) Lister() v1alpha1.CanaryLister { - return v1alpha1.NewCanaryLister(f.Informer().GetIndexer()) +func (f *canaryInformer) Lister() v1alpha2.CanaryLister { + return v1alpha2.NewCanaryLister(f.Informer().GetIndexer()) } diff --git a/pkg/client/informers/externalversions/flagger/v1alpha1/interface.go b/pkg/client/informers/externalversions/flagger/v1alpha2/interface.go similarity index 98% rename from pkg/client/informers/externalversions/flagger/v1alpha1/interface.go rename to pkg/client/informers/externalversions/flagger/v1alpha2/interface.go index 828db89bb..0bd83308f 100644 --- a/pkg/client/informers/externalversions/flagger/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/flagger/v1alpha2/interface.go @@ -16,7 +16,7 @@ limitations under the License. // Code generated by informer-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces" diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 8175499e1..489b8bda7 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -21,7 +21,7 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -52,9 +52,9 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=flagger.app, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("canaries"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1alpha1().Canaries().Informer()}, nil + // Group=flagger.app, Version=v1alpha2 + case v1alpha2.SchemeGroupVersion.WithResource("canaries"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1alpha2().Canaries().Informer()}, nil } diff --git a/pkg/client/listers/flagger/v1alpha1/canary.go b/pkg/client/listers/flagger/v1alpha2/canary.go similarity index 81% rename from pkg/client/listers/flagger/v1alpha1/canary.go rename to pkg/client/listers/flagger/v1alpha2/canary.go index 7ddfe9fb9..0613f340e 100644 --- a/pkg/client/listers/flagger/v1alpha1/canary.go +++ b/pkg/client/listers/flagger/v1alpha2/canary.go @@ -16,10 +16,10 @@ limitations under the License. // Code generated by lister-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 import ( - v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + v1alpha2 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" @@ -28,7 +28,7 @@ import ( // CanaryLister helps list Canaries. type CanaryLister interface { // List lists all Canaries in the indexer. - List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) + List(selector labels.Selector) (ret []*v1alpha2.Canary, err error) // Canaries returns an object that can list and get Canaries. Canaries(namespace string) CanaryNamespaceLister CanaryListerExpansion @@ -45,9 +45,9 @@ func NewCanaryLister(indexer cache.Indexer) CanaryLister { } // List lists all Canaries in the indexer. -func (s *canaryLister) List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) { +func (s *canaryLister) List(selector labels.Selector) (ret []*v1alpha2.Canary, err error) { err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Canary)) + ret = append(ret, m.(*v1alpha2.Canary)) }) return ret, err } @@ -60,9 +60,9 @@ func (s *canaryLister) Canaries(namespace string) CanaryNamespaceLister { // CanaryNamespaceLister helps list and get Canaries. type CanaryNamespaceLister interface { // List lists all Canaries in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) + List(selector labels.Selector) (ret []*v1alpha2.Canary, err error) // Get retrieves the Canary from the indexer for a given namespace and name. - Get(name string) (*v1alpha1.Canary, error) + Get(name string) (*v1alpha2.Canary, error) CanaryNamespaceListerExpansion } @@ -74,21 +74,21 @@ type canaryNamespaceLister struct { } // List lists all Canaries in the indexer for a given namespace. -func (s canaryNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) { +func (s canaryNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.Canary, err error) { err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Canary)) + ret = append(ret, m.(*v1alpha2.Canary)) }) return ret, err } // Get retrieves the Canary from the indexer for a given namespace and name. -func (s canaryNamespaceLister) Get(name string) (*v1alpha1.Canary, error) { +func (s canaryNamespaceLister) Get(name string) (*v1alpha2.Canary, error) { obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) if err != nil { return nil, err } if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("canary"), name) + return nil, errors.NewNotFound(v1alpha2.Resource("canary"), name) } - return obj.(*v1alpha1.Canary), nil + return obj.(*v1alpha2.Canary), nil } diff --git a/pkg/client/listers/flagger/v1alpha1/expansion_generated.go b/pkg/client/listers/flagger/v1alpha2/expansion_generated.go similarity index 98% rename from pkg/client/listers/flagger/v1alpha1/expansion_generated.go rename to pkg/client/listers/flagger/v1alpha2/expansion_generated.go index cf66562eb..6e301aa27 100644 --- a/pkg/client/listers/flagger/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/flagger/v1alpha2/expansion_generated.go @@ -16,7 +16,7 @@ limitations under the License. // Code generated by lister-gen. DO NOT EDIT. -package v1alpha1 +package v1alpha2 // CanaryListerExpansion allows custom methods to be added to // CanaryLister. diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 96c9f28d4..09189a8f8 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -7,11 +7,11 @@ import ( "github.com/google/go-cmp/cmp" istioclientset "github.com/knative/pkg/client/clientset/versioned" - flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" clientset "github.com/stefanprodan/flagger/pkg/client/clientset/versioned" flaggerscheme "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/scheme" - flaggerinformers "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha1" - flaggerlisters "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha1" + flaggerinformers "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha2" + flaggerlisters "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha2" "github.com/stefanprodan/flagger/pkg/notifier" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" diff --git a/pkg/controller/deployer.go b/pkg/controller/deployer.go index ca2dfa203..4f52fa97f 100644 --- a/pkg/controller/deployer.go +++ b/pkg/controller/deployer.go @@ -9,7 +9,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" istioclientset "github.com/knative/pkg/client/clientset/versioned" - flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" clientset "github.com/stefanprodan/flagger/pkg/client/clientset/versioned" "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" @@ -154,7 +154,7 @@ func (c *CanaryDeployer) IsNewSpec(cd *flaggerv1.Canary) (bool, error) { func (c *CanaryDeployer) SetFailedChecks(cd *flaggerv1.Canary, val int) error { cd.Status.FailedChecks = val cd.Status.LastTransitionTime = metav1.Now() - cd, err := c.flaggerClient.FlaggerV1alpha1().Canaries(cd.Namespace).Update(cd) + cd, err := c.flaggerClient.FlaggerV1alpha2().Canaries(cd.Namespace).Update(cd) if err != nil { return fmt.Errorf("deployment %s.%s update error %v", cd.Spec.TargetRef.Name, cd.Namespace, err) } @@ -165,7 +165,7 @@ func (c *CanaryDeployer) SetFailedChecks(cd *flaggerv1.Canary, val int) error { func (c *CanaryDeployer) SetState(cd *flaggerv1.Canary, state flaggerv1.CanaryState) error { cd.Status.State = state cd.Status.LastTransitionTime = metav1.Now() - cd, err := c.flaggerClient.FlaggerV1alpha1().Canaries(cd.Namespace).Update(cd) + cd, err := c.flaggerClient.FlaggerV1alpha2().Canaries(cd.Namespace).Update(cd) if err != nil { return fmt.Errorf("deployment %s.%s update error %v", cd.Spec.TargetRef.Name, cd.Namespace, err) } @@ -192,7 +192,7 @@ func (c *CanaryDeployer) SyncStatus(cd *flaggerv1.Canary, status flaggerv1.Canar cd.Status.FailedChecks = status.FailedChecks cd.Status.CanaryRevision = specEnc cd.Status.LastTransitionTime = metav1.Now() - cd, err = c.flaggerClient.FlaggerV1alpha1().Canaries(cd.Namespace).Update(cd) + cd, err = c.flaggerClient.FlaggerV1alpha2().Canaries(cd.Namespace).Update(cd) if err != nil { return fmt.Errorf("deployment %s.%s update error %v", cd.Spec.TargetRef.Name, cd.Namespace, err) } diff --git a/pkg/controller/deployer_test.go b/pkg/controller/deployer_test.go index e25e997b9..54791bb08 100644 --- a/pkg/controller/deployer_test.go +++ b/pkg/controller/deployer_test.go @@ -3,7 +3,7 @@ package controller import ( "testing" - "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" fakeFlagger "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/fake" "github.com/stefanprodan/flagger/pkg/logging" appsv1 "k8s.io/api/apps/v1" @@ -14,14 +14,14 @@ import ( "k8s.io/client-go/kubernetes/fake" ) -func newTestCanary() *v1alpha1.Canary { - cd := &v1alpha1.Canary{ - TypeMeta: metav1.TypeMeta{APIVersion: v1alpha1.SchemeGroupVersion.String()}, +func newTestCanary() *v1alpha2.Canary { + cd := &v1alpha2.Canary{ + TypeMeta: metav1.TypeMeta{APIVersion: v1alpha2.SchemeGroupVersion.String()}, ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "podinfo", }, - Spec: v1alpha1.CanarySpec{ + Spec: v1alpha2.CanarySpec{ TargetRef: hpav1.CrossVersionObjectReference{ Name: "podinfo", APIVersion: "apps/v1", @@ -31,13 +31,13 @@ func newTestCanary() *v1alpha1.Canary { Name: "podinfo", APIVersion: "autoscaling/v2beta1", Kind: "HorizontalPodAutoscaler", - }, Service: v1alpha1.CanaryService{ + }, Service: v1alpha2.CanaryService{ Port: 9898, - }, CanaryAnalysis: v1alpha1.CanaryAnalysis{ + }, CanaryAnalysis: v1alpha2.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, - Metrics: []v1alpha1.CanaryMetric{ + Metrics: []v1alpha2.CanaryMetric{ { Name: "istio_requests_total", Threshold: 99, @@ -356,7 +356,7 @@ func TestCanaryDeployer_SetFailedChecks(t *testing.T) { t.Fatal(err.Error()) } - res, err := flaggerClient.FlaggerV1alpha1().Canaries("default").Get("podinfo", metav1.GetOptions{}) + res, err := flaggerClient.FlaggerV1alpha2().Canaries("default").Get("podinfo", metav1.GetOptions{}) if err != nil { t.Fatal(err.Error()) } @@ -387,18 +387,18 @@ func TestCanaryDeployer_SetState(t *testing.T) { t.Fatal(err.Error()) } - err = deployer.SetState(canary, v1alpha1.CanaryRunning) + err = deployer.SetState(canary, v1alpha2.CanaryRunning) if err != nil { t.Fatal(err.Error()) } - res, err := flaggerClient.FlaggerV1alpha1().Canaries("default").Get("podinfo", metav1.GetOptions{}) + res, err := flaggerClient.FlaggerV1alpha2().Canaries("default").Get("podinfo", metav1.GetOptions{}) if err != nil { t.Fatal(err.Error()) } - if res.Status.State != v1alpha1.CanaryRunning { - t.Errorf("Got %v wanted %v", res.Status.State, v1alpha1.CanaryRunning) + if res.Status.State != v1alpha2.CanaryRunning { + t.Errorf("Got %v wanted %v", res.Status.State, v1alpha2.CanaryRunning) } } @@ -423,8 +423,8 @@ func TestCanaryDeployer_SyncStatus(t *testing.T) { t.Fatal(err.Error()) } - status := v1alpha1.CanaryStatus{ - State: v1alpha1.CanaryRunning, + status := v1alpha2.CanaryStatus{ + State: v1alpha2.CanaryRunning, FailedChecks: 2, } err = deployer.SyncStatus(canary, status) @@ -432,7 +432,7 @@ func TestCanaryDeployer_SyncStatus(t *testing.T) { t.Fatal(err.Error()) } - res, err := flaggerClient.FlaggerV1alpha1().Canaries("default").Get("podinfo", metav1.GetOptions{}) + res, err := flaggerClient.FlaggerV1alpha2().Canaries("default").Get("podinfo", metav1.GetOptions{}) if err != nil { t.Fatal(err.Error()) } diff --git a/pkg/controller/observer_test.go b/pkg/controller/observer_test.go new file mode 100644 index 000000000..1ef009820 --- /dev/null +++ b/pkg/controller/observer_test.go @@ -0,0 +1,84 @@ +package controller + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" +) + +func TestCanaryObserver_GetDeploymentCounter(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1545905245.458,"100"]}]}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + observer := CanaryObserver{ + metricsServer: ts.URL, + } + + val, err := observer.GetDeploymentCounter("podinfo", "default", "istio_requests_total", "1m") + if err != nil { + t.Fatal(err.Error()) + } + + if val != 100 { + t.Errorf("Got %v wanted %v", val, 100) + } + +} + +func TestCanaryObserver_GetDeploymentHistogram(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1545905245.596,"0.2"]}]}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + observer := CanaryObserver{ + metricsServer: ts.URL, + } + + val, err := observer.GetDeploymentHistogram("podinfo", "default", "istio_request_duration_seconds_bucket", "1m") + if err != nil { + t.Fatal(err.Error()) + } + + if val != 200*time.Millisecond { + t.Errorf("Got %v wanted %v", val, 200*time.Millisecond) + } +} + +func TestCheckMetricsServer(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + json := `{"status":"success","data":{"config.file":"/etc/prometheus/prometheus.yml"}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + ok, err := CheckMetricsServer(ts.URL) + if err != nil { + t.Fatal(err.Error()) + } + + if !ok { + t.Errorf("Got %v wanted %v", ok, true) + } +} + +func TestCheckMetricsServer_Offline(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadGateway) + })) + defer ts.Close() + + ok, err := CheckMetricsServer(ts.URL) + if err == nil { + t.Errorf("Got no error wanted %v", http.StatusBadGateway) + } + + if ok { + t.Errorf("Got %v wanted %v", ok, false) + } +} diff --git a/pkg/controller/recorder.go b/pkg/controller/recorder.go index 717b40911..b1e2193c9 100644 --- a/pkg/controller/recorder.go +++ b/pkg/controller/recorder.go @@ -5,7 +5,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" ) // CanaryRecorder records the canary analysis as Prometheus metrics diff --git a/pkg/controller/router.go b/pkg/controller/router.go index d232c4454..f85e8e133 100644 --- a/pkg/controller/router.go +++ b/pkg/controller/router.go @@ -5,7 +5,7 @@ import ( istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" istioclientset "github.com/knative/pkg/client/clientset/versioned" - flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" clientset "github.com/stefanprodan/flagger/pkg/client/clientset/versioned" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" diff --git a/pkg/controller/scheduler.go b/pkg/controller/scheduler.go index bc1d57f7f..6552898ca 100644 --- a/pkg/controller/scheduler.go +++ b/pkg/controller/scheduler.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -32,7 +32,7 @@ func (c *Controller) scheduleCanaries() { func (c *Controller) advanceCanary(name string, namespace string) { begin := time.Now() // check if the canary exists - cd, err := c.flaggerClient.FlaggerV1alpha1().Canaries(namespace).Get(name, v1.GetOptions{}) + cd, err := c.flaggerClient.FlaggerV1alpha2().Canaries(namespace).Get(name, v1.GetOptions{}) if err != nil { c.logger.Errorf("Canary %s.%s not found", name, namespace) return @@ -139,7 +139,7 @@ func (c *Controller) advanceCanary(name string, namespace string) { if canaryRoute.Weight == 0 { c.recordEventInfof(cd, "Starting canary deployment for %s.%s", cd.Name, cd.Namespace) } else { - if ok := c.checkCanaryMetrics(cd); !ok { + if ok := c.analyseCanary(cd); !ok { if err := c.deployer.SetFailedChecks(cd, cd.Status.FailedChecks+1); err != nil { c.recordEventWarningf(cd, "%v", err) return @@ -242,7 +242,8 @@ func (c *Controller) checkCanaryStatus(cd *flaggerv1.Canary, deployer CanaryDepl return false } -func (c *Controller) checkCanaryMetrics(r *flaggerv1.Canary) bool { +func (c *Controller) analyseCanary(r *flaggerv1.Canary) bool { + // run metrics checks for _, metric := range r.Spec.CanaryAnalysis.Metrics { if metric.Name == "istio_requests_total" { val, err := c.observer.GetDeploymentCounter(r.Spec.TargetRef.Name, r.Namespace, metric.Name, metric.Interval) @@ -272,5 +273,15 @@ func (c *Controller) checkCanaryMetrics(r *flaggerv1.Canary) bool { } } + // run external checks + for _, webhook := range r.Spec.CanaryAnalysis.Webhooks { + err := CallWebhook(r.Name, r.Namespace, webhook) + if err != nil { + c.recordEventWarningf(r, "Halt %s.%s advancement external check %s failed %v", + r.Name, r.Namespace, webhook.Name, err) + return false + } + } + return true } diff --git a/pkg/controller/scheduler_test.go b/pkg/controller/scheduler_test.go index 16c6fbfda..617618cf0 100644 --- a/pkg/controller/scheduler_test.go +++ b/pkg/controller/scheduler_test.go @@ -6,7 +6,7 @@ import ( "time" fakeIstio "github.com/knative/pkg/client/clientset/versioned/fake" - "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1" + "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" fakeFlagger "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/fake" informers "github.com/stefanprodan/flagger/pkg/client/informers/externalversions" "github.com/stefanprodan/flagger/pkg/logging" @@ -47,7 +47,7 @@ func TestScheduler_Init(t *testing.T) { } flaggerInformerFactory := informers.NewSharedInformerFactory(flaggerClient, noResyncPeriodFunc()) - flaggerInformer := flaggerInformerFactory.Flagger().V1alpha1().Canaries() + flaggerInformer := flaggerInformerFactory.Flagger().V1alpha2().Canaries() ctrl := &Controller{ kubeClient: kubeClient, @@ -101,7 +101,7 @@ func TestScheduler_NewRevision(t *testing.T) { } flaggerInformerFactory := informers.NewSharedInformerFactory(flaggerClient, noResyncPeriodFunc()) - flaggerInformer := flaggerInformerFactory.Flagger().V1alpha1().Canaries() + flaggerInformer := flaggerInformerFactory.Flagger().V1alpha2().Canaries() ctrl := &Controller{ kubeClient: kubeClient, @@ -170,7 +170,7 @@ func TestScheduler_Rollback(t *testing.T) { } flaggerInformerFactory := informers.NewSharedInformerFactory(flaggerClient, noResyncPeriodFunc()) - flaggerInformer := flaggerInformerFactory.Flagger().V1alpha1().Canaries() + flaggerInformer := flaggerInformerFactory.Flagger().V1alpha2().Canaries() ctrl := &Controller{ kubeClient: kubeClient, @@ -194,7 +194,7 @@ func TestScheduler_Rollback(t *testing.T) { ctrl.advanceCanary("podinfo", "default") // update failed checks to max - err := deployer.SyncStatus(canary, v1alpha1.CanaryStatus{State: v1alpha1.CanaryRunning, FailedChecks: 11}) + err := deployer.SyncStatus(canary, v1alpha2.CanaryStatus{State: v1alpha2.CanaryRunning, FailedChecks: 11}) if err != nil { t.Fatal(err.Error()) } @@ -202,12 +202,12 @@ func TestScheduler_Rollback(t *testing.T) { // detect changes ctrl.advanceCanary("podinfo", "default") - c, err := flaggerClient.FlaggerV1alpha1().Canaries("default").Get("podinfo", metav1.GetOptions{}) + c, err := flaggerClient.FlaggerV1alpha2().Canaries("default").Get("podinfo", metav1.GetOptions{}) if err != nil { t.Fatal(err.Error()) } - if c.Status.State != v1alpha1.CanaryFailed { - t.Errorf("Got canary state %v wanted %v", c.Status.State, v1alpha1.CanaryFailed) + if c.Status.State != v1alpha2.CanaryFailed { + t.Errorf("Got canary state %v wanted %v", c.Status.State, v1alpha2.CanaryFailed) } } diff --git a/pkg/controller/webhook.go b/pkg/controller/webhook.go new file mode 100644 index 000000000..bfba0ff7c --- /dev/null +++ b/pkg/controller/webhook.go @@ -0,0 +1,70 @@ +package controller + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" + "io/ioutil" + "net/http" + "net/url" + "time" +) + +// CallWebhook does a HTTP POST to an external service and +// returns an error if the response status code is non-2xx +func CallWebhook(name string, namepace string, w flaggerv1.CanaryWebhook) error { + payload := flaggerv1.CanaryWebhookPayload{ + Name: name, + Namespace: namepace, + Metadata: w.Metadata, + } + + payloadBin, err := json.Marshal(payload) + if err != nil { + return err + } + + hook, err := url.Parse(w.URL) + if err != nil { + return err + } + + req, err := http.NewRequest("POST", hook.String(), bytes.NewBuffer(payloadBin)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + if len(w.Timeout) < 2 { + w.Timeout = "10s" + } + + timeout, err := time.ParseDuration(w.Timeout) + if err != nil { + return err + } + + ctx, cancel := context.WithTimeout(req.Context(), timeout) + defer cancel() + + r, err := http.DefaultClient.Do(req.WithContext(ctx)) + if err != nil { + return err + } + defer r.Body.Close() + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + return fmt.Errorf("error reading body: %s", err.Error()) + } + + if r.StatusCode > 202 { + return errors.New(string(b)) + } + + return nil +} diff --git a/pkg/controller/webhook_test.go b/pkg/controller/webhook_test.go new file mode 100644 index 000000000..2e96786de --- /dev/null +++ b/pkg/controller/webhook_test.go @@ -0,0 +1,42 @@ +package controller + +import ( + flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha2" + "net/http" + "net/http/httptest" + "testing" +) + +func TestCallWebhook(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusAccepted) + })) + defer ts.Close() + hook := flaggerv1.CanaryWebhook{ + Name: "validation", + URL: ts.URL, + Timeout: "10s", + Metadata: &map[string]string{"key1": "val1"}, + } + + err := CallWebhook("podinfo", "default", hook) + if err != nil { + t.Fatal(err.Error()) + } +} + +func TestCallWebhook_StatusCode(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer ts.Close() + hook := flaggerv1.CanaryWebhook{ + Name: "validation", + URL: ts.URL, + } + + err := CallWebhook("podinfo", "default", hook) + if err == nil { + t.Errorf("Got no error wanted %v", http.StatusInternalServerError) + } +} diff --git a/pkg/version/version.go b/pkg/version/version.go index dfcef9735..0b3a54f9d 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,4 +1,4 @@ package version -var VERSION = "0.1.2" +var VERSION = "0.2.0-alpha.1" var REVISION = "unknown"