Canary CRD refactoring

- set canaries.flagger.app version to v1alpha1
- replace old Canary spec with CanaryDeployment
This commit is contained in:
Stefan Prodan
2018-10-11 01:43:53 +03:00
parent 5a1412549d
commit 302de10fec
40 changed files with 324 additions and 2013 deletions

1
Gopkg.lock generated
View File

@@ -665,6 +665,7 @@
"k8s.io/api/autoscaling/v1",
"k8s.io/api/core/v1",
"k8s.io/apimachinery/pkg/api/errors",
"k8s.io/apimachinery/pkg/api/resource",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/apimachinery/pkg/labels",
"k8s.io/apimachinery/pkg/runtime",

View File

@@ -1,5 +1,5 @@
apiVersion: flagger.app/v1beta1
kind: CanaryDeployment
apiVersion: flagger.app/v1alpha1
kind: Canary
metadata:
name: podinfo
namespace: test

View File

@@ -4,9 +4,9 @@ metadata:
name: canaries.flagger.app
spec:
group: flagger.app
version: v1beta1
version: v1alpha1
versions:
- name: v1beta1
- name: v1alpha1
served: true
storage: true
names:
@@ -19,75 +19,22 @@ spec:
properties:
spec:
required:
- targetKind
- virtualService
- primary
- canary
- canaryAnalysis
properties:
targetKind:
type: string
virtualService:
properties:
name:
type: string
primary:
properties:
name:
type: string
host:
type: string
canary:
properties:
name:
type: string
host:
type: string
canaryAnalysis:
properties:
threshold:
type: number
maxWeight:
type: number
stepWeight:
type: number
metrics:
type: array
properties:
items:
type: object
properties:
name:
type: string
interval:
type: string
pattern: "^[0-9]+(m)"
threshold:
type: number
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: canarydeployments.flagger.app
spec:
group: flagger.app
version: v1beta1
versions:
- name: v1beta1
served: true
storage: true
names:
plural: canarydeployments
singular: canarydeployment
kind: CanaryDeployment
scope: Namespaced
validation:
openAPIV3Schema:
properties:
spec:
required:
- targetRef
- service
- canaryAnalysis
properties:
targetRef:
properties:
apiVersion:
type: string
kind:
type: string
name:
type: string
service:
properties:
port:
type: number
canaryAnalysis:
properties:
threshold:

View File

@@ -1,42 +0,0 @@
# monitor events: watch "kubectl -n test describe rollout/podinfo | sed -n 35,1000p"
# run tester: kubectl run -n test tester --image=quay.io/stefanprodan/podinfo:1.2.1 -- ./podinfo --port=9898
# generate latency: watch curl http://podinfo-canary:9898/delay/1
# generate errors: watch curl http://podinfo-canary:9898/status/500
# run load test: kubectl run -n test -it --rm --restart=Never hey --image=stefanprodan/loadtest -- sh
# generate load: hey -z 2m -h2 -m POST -d '{test: 1}' -c 10 -q 5 http://podinfo:9898/api/echo
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
namespace: test
spec:
targetKind: Deployment
virtualService:
name: podinfo
primary:
name: podinfo
host: podinfo
canary:
name: podinfo-canary
host: podinfo-canary
canaryAnalysis:
# max number of failed metric checks
# before rolling back the canary
threshold: 5
# max traffic percentage routed to canary
# percentage (0-100)
maxWeight: 50
# canary increment step
# percentage (0-100)
stepWeight: 10
metrics:
- name: istio_requests_total
# minimum req success rate (non 5xx responses)
# percentage (0-100)
threshold: 99
interval: 1m
- name: istio_request_duration_seconds_bucket
# maximum req duration P99
# milliseconds
threshold: 500
interval: 30s

View File

@@ -1,36 +0,0 @@
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfoc
namespace: test
spec:
targetKind: Deployment
virtualService:
name: podinfoc
primary:
name: podinfoc-primary
host: podinfoc-primary
canary:
name: podinfoc-canary
host: podinfoc-canary
canaryAnalysis:
# max number of failed metric checks
# before rolling back the canary
threshold: 10
# max traffic percentage routed to canary
# percentage (0-100)
maxWeight: 50
# canary increment step
# percentage (0-100)
stepWeight: 10
metrics:
- name: istio_requests_total
# minimum req success rate (non 5xx responses)
# percentage (0-100)
threshold: 99
interval: 1m
- name: istio_request_duration_seconds_bucket
# maximum req duration P99
# milliseconds
threshold: 500
interval: 30s

View File

@@ -5,9 +5,9 @@ metadata:
name: canaries.flagger.app
spec:
group: flagger.app
version: v1beta1
version: v1alpha1
versions:
- name: v1beta1
- name: v1alpha1
served: true
storage: true
names:
@@ -20,30 +20,22 @@ spec:
properties:
spec:
required:
- targetKind
- virtualService
- primary
- canary
- canaryAnalysis
- targetRef
- service
- canaryAnalysis
properties:
targetKind:
type: string
virtualService:
targetRef:
properties:
apiVersion:
type: string
kind:
type: string
name:
type: string
primary:
service:
properties:
name:
type: string
host:
type: string
canary:
properties:
name:
type: string
host:
type: string
port:
type: number
canaryAnalysis:
properties:
threshold:

View File

@@ -5,8 +5,6 @@ import (
"log"
"time"
"github.com/stefanprodan/flagger/pkg/operator"
_ "github.com/istio/glog"
sharedclientset "github.com/knative/pkg/client/clientset/versioned"
"github.com/knative/pkg/signals"
@@ -71,9 +69,8 @@ func main() {
logger.Fatalf("Error building example clientset: %s", err.Error())
}
rolloutInformerFactory := informers.NewSharedInformerFactory(rolloutClient, time.Second*30)
rolloutInformer := rolloutInformerFactory.Flagger().V1beta1().Canaries()
canaryDeploymentInformer := rolloutInformerFactory.Flagger().V1beta1().CanaryDeployments()
canaryInformerFactory := informers.NewSharedInformerFactory(rolloutClient, time.Second*30)
canaryInformer := canaryInformerFactory.Flagger().V1alpha1().Canaries()
logger.Infof("Starting flagger version %s revision %s", version.VERSION, version.REVISION)
@@ -98,28 +95,17 @@ func main() {
kubeClient,
sharedClient,
rolloutClient,
rolloutInformer,
canaryInformer,
controlLoopInterval,
metricsServer,
logger,
)
cd := operator.NewController(
kubeClient,
sharedClient,
rolloutClient,
canaryDeploymentInformer,
controlLoopInterval,
metricsServer,
logger,
)
rolloutInformerFactory.Start(stopCh)
canaryInformerFactory.Start(stopCh)
logger.Info("Waiting for informer caches to sync")
for _, synced := range []cache.InformerSynced{
rolloutInformer.Informer().HasSynced,
canaryDeploymentInformer.Informer().HasSynced,
canaryInformer.Informer().HasSynced,
} {
if ok := cache.WaitForCacheSync(stopCh, synced); !ok {
logger.Fatalf("Failed to wait for cache sync")
@@ -133,12 +119,5 @@ func main() {
}
}(c)
// start controller
go func(ctrl *operator.Controller) {
if err := ctrl.Run(2, stopCh); err != nil {
logger.Fatalf("Error running controller: %v", err)
}
}(cd)
<-stopCh
}

View File

@@ -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:v1beta1 \
flagger:v1alpha1 \
--go-header-file ${SCRIPT_ROOT}/hack/boilerplate.go.txt

View File

@@ -16,6 +16,6 @@ limitations under the License.
// +k8s:deepcopy-gen=package
// Package v1beta1 is the v1beta1 version of the API.
// Package v1alpha1 is the v1alpha1 version of the API.
// +groupName=flagger.app
package v1beta1
package v1alpha1

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
package v1alpha1
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: "v1beta1"}
var SchemeGroupVersion = schema.GroupVersion{Group: rollout.GroupName, Version: "v1alpha1"}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
@@ -47,8 +47,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Canary{},
&CanaryList{},
&CanaryDeployment{},
&CanaryDeploymentList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
package v1alpha1
import (
hpav1 "k8s.io/api/autoscaling/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const CanaryDeploymentKind = "CanaryDeployment"
const CanaryKind = "Canary"
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -37,11 +37,14 @@ type Canary struct {
// CanarySpec is the spec for a Canary resource
type CanarySpec struct {
TargetKind string `json:"targetKind"`
Primary Target `json:"primary"`
Canary Target `json:"canary"`
// reference to target resource
TargetRef hpav1.CrossVersionObjectReference `json:"targetRef"`
// virtual service spec
Service CanaryService `json:"service"`
// metrics and thresholds
CanaryAnalysis CanaryAnalysis `json:"canaryAnalysis"`
VirtualService VirtualService `json:"virtualService"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -61,71 +64,21 @@ type CanaryStatus struct {
FailedChecks int `json:"failedChecks"`
}
type Target struct {
Name string `json:"name"`
Host string `json:"host"`
}
type VirtualService struct {
Name string `json:"name"`
type CanaryService struct {
Port int32 `json:"port"`
Gateways []string `json:"gateways"`
Hosts []string `json:"hosts"`
}
type CanaryAnalysis struct {
Threshold int `json:"threshold"`
MaxWeight int `json:"maxWeight"`
StepWeight int `json:"stepWeight"`
Metrics []Metric `json:"metrics"`
Threshold int `json:"threshold"`
MaxWeight int `json:"maxWeight"`
StepWeight int `json:"stepWeight"`
Metrics []CanaryMetric `json:"metrics"`
}
type Metric struct {
type CanaryMetric struct {
Name string `json:"name"`
Interval string `json:"interval"`
Threshold int `json:"threshold"`
}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Canary is a specification for a Canary resource
type CanaryDeployment struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec CanaryDeploymentSpec `json:"spec"`
Status CanaryDeploymentStatus `json:"status"`
}
// CanarySpec is the spec for a Canary resource
type CanaryDeploymentSpec struct {
// reference to target resource
TargetRef hpav1.CrossVersionObjectReference `json:"targetRef"`
// virtual service spec
Service CanaryDeploymentService `json:"service"`
// metrics and thresholds
CanaryAnalysis CanaryAnalysis `json:"canaryAnalysis"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CanaryList is a list of Canary resources
type CanaryDeploymentList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`
Items []CanaryDeployment `json:"items"`
}
// CanaryStatus is used for state persistence (read-only)
type CanaryDeploymentStatus struct {
State string `json:"state"`
CanaryRevision string `json:"canaryRevision"`
FailedChecks int `json:"failedChecks"`
}
type CanaryDeploymentService struct {
Port int32 `json:"port"`
Gateways []string `json:"gateways"`
Hosts []string `json:"hosts"`
}

View File

@@ -18,7 +18,7 @@ limitations under the License.
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
@@ -57,7 +57,7 @@ func (in *CanaryAnalysis) DeepCopyInto(out *CanaryAnalysis) {
*out = *in
if in.Metrics != nil {
in, out := &in.Metrics, &out.Metrics
*out = make([]Metric, len(*in))
*out = make([]CanaryMetric, len(*in))
copy(*out, *in)
}
return
@@ -73,128 +73,6 @@ func (in *CanaryAnalysis) DeepCopy() *CanaryAnalysis {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryDeployment) DeepCopyInto(out *CanaryDeployment) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryDeployment.
func (in *CanaryDeployment) DeepCopy() *CanaryDeployment {
if in == nil {
return nil
}
out := new(CanaryDeployment)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CanaryDeployment) 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 *CanaryDeploymentList) DeepCopyInto(out *CanaryDeploymentList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]CanaryDeployment, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryDeploymentList.
func (in *CanaryDeploymentList) DeepCopy() *CanaryDeploymentList {
if in == nil {
return nil
}
out := new(CanaryDeploymentList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CanaryDeploymentList) 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 *CanaryDeploymentService) DeepCopyInto(out *CanaryDeploymentService) {
*out = *in
if in.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Hosts != nil {
in, out := &in.Hosts, &out.Hosts
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryDeploymentService.
func (in *CanaryDeploymentService) DeepCopy() *CanaryDeploymentService {
if in == nil {
return nil
}
out := new(CanaryDeploymentService)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryDeploymentSpec) DeepCopyInto(out *CanaryDeploymentSpec) {
*out = *in
out.TargetRef = in.TargetRef
in.Service.DeepCopyInto(&out.Service)
in.CanaryAnalysis.DeepCopyInto(&out.CanaryAnalysis)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryDeploymentSpec.
func (in *CanaryDeploymentSpec) DeepCopy() *CanaryDeploymentSpec {
if in == nil {
return nil
}
out := new(CanaryDeploymentSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryDeploymentStatus) DeepCopyInto(out *CanaryDeploymentStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryDeploymentStatus.
func (in *CanaryDeploymentStatus) DeepCopy() *CanaryDeploymentStatus {
if in == nil {
return nil
}
out := new(CanaryDeploymentStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryList) DeepCopyInto(out *CanaryList) {
*out = *in
@@ -228,13 +106,54 @@ func (in *CanaryList) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryMetric) DeepCopyInto(out *CanaryMetric) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryMetric.
func (in *CanaryMetric) DeepCopy() *CanaryMetric {
if in == nil {
return nil
}
out := new(CanaryMetric)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryService) DeepCopyInto(out *CanaryService) {
*out = *in
if in.Gateways != nil {
in, out := &in.Gateways, &out.Gateways
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Hosts != nil {
in, out := &in.Hosts, &out.Hosts
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryService.
func (in *CanaryService) DeepCopy() *CanaryService {
if in == nil {
return nil
}
out := new(CanaryService)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanarySpec) DeepCopyInto(out *CanarySpec) {
*out = *in
out.Primary = in.Primary
out.Canary = in.Canary
out.TargetRef = in.TargetRef
in.Service.DeepCopyInto(&out.Service)
in.CanaryAnalysis.DeepCopyInto(&out.CanaryAnalysis)
out.VirtualService = in.VirtualService
return
}
@@ -263,51 +182,3 @@ 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 *Metric) DeepCopyInto(out *Metric) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metric.
func (in *Metric) DeepCopy() *Metric {
if in == nil {
return nil
}
out := new(Metric)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Target) DeepCopyInto(out *Target) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target.
func (in *Target) DeepCopy() *Target {
if in == nil {
return nil
}
out := new(Target)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VirtualService) DeepCopyInto(out *VirtualService) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualService.
func (in *VirtualService) DeepCopy() *VirtualService {
if in == nil {
return nil
}
out := new(VirtualService)
in.DeepCopyInto(out)
return out
}

View File

@@ -19,7 +19,7 @@ limitations under the License.
package versioned
import (
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1beta1"
flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1"
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
FlaggerV1beta1() flaggerv1beta1.FlaggerV1beta1Interface
FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface
// Deprecated: please explicitly pick a version if possible.
Flagger() flaggerv1beta1.FlaggerV1beta1Interface
Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
flaggerV1beta1 *flaggerv1beta1.FlaggerV1beta1Client
flaggerV1alpha1 *flaggerv1alpha1.FlaggerV1alpha1Client
}
// FlaggerV1beta1 retrieves the FlaggerV1beta1Client
func (c *Clientset) FlaggerV1beta1() flaggerv1beta1.FlaggerV1beta1Interface {
return c.flaggerV1beta1
// FlaggerV1alpha1 retrieves the FlaggerV1alpha1Client
func (c *Clientset) FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface {
return c.flaggerV1alpha1
}
// Deprecated: Flagger retrieves the default version of FlaggerClient.
// Please explicitly pick a version.
func (c *Clientset) Flagger() flaggerv1beta1.FlaggerV1beta1Interface {
return c.flaggerV1beta1
func (c *Clientset) Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface {
return c.flaggerV1alpha1
}
// Discovery retrieves the DiscoveryClient
@@ -66,7 +66,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
}
var cs Clientset
var err error
cs.flaggerV1beta1, err = flaggerv1beta1.NewForConfig(&configShallowCopy)
cs.flaggerV1alpha1, err = flaggerv1alpha1.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.flaggerV1beta1 = flaggerv1beta1.NewForConfigOrDie(c)
cs.flaggerV1alpha1 = flaggerv1alpha1.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.flaggerV1beta1 = flaggerv1beta1.New(c)
cs.flaggerV1alpha1 = flaggerv1alpha1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs

View File

@@ -20,8 +20,8 @@ package fake
import (
clientset "github.com/stefanprodan/flagger/pkg/client/clientset/versioned"
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1beta1"
fakeflaggerv1beta1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1beta1/fake"
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"
"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{}
// FlaggerV1beta1 retrieves the FlaggerV1beta1Client
func (c *Clientset) FlaggerV1beta1() flaggerv1beta1.FlaggerV1beta1Interface {
return &fakeflaggerv1beta1.FakeFlaggerV1beta1{Fake: &c.Fake}
// FlaggerV1alpha1 retrieves the FlaggerV1alpha1Client
func (c *Clientset) FlaggerV1alpha1() flaggerv1alpha1.FlaggerV1alpha1Interface {
return &fakeflaggerv1alpha1.FakeFlaggerV1alpha1{Fake: &c.Fake}
}
// Flagger retrieves the FlaggerV1beta1Client
func (c *Clientset) Flagger() flaggerv1beta1.FlaggerV1beta1Interface {
return &fakeflaggerv1beta1.FakeFlaggerV1beta1{Fake: &c.Fake}
// Flagger retrieves the FlaggerV1alpha1Client
func (c *Clientset) Flagger() flaggerv1alpha1.FlaggerV1alpha1Interface {
return &fakeflaggerv1alpha1.FakeFlaggerV1alpha1{Fake: &c.Fake}
}

View File

@@ -19,7 +19,7 @@ limitations under the License.
package fake
import (
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
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) {
flaggerv1beta1.AddToScheme(scheme)
flaggerv1alpha1.AddToScheme(scheme)
}

View File

@@ -19,7 +19,7 @@ limitations under the License.
package scheme
import (
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
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) {
flaggerv1beta1.AddToScheme(scheme)
flaggerv1alpha1.AddToScheme(scheme)
}

View File

@@ -16,10 +16,10 @@ limitations under the License.
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
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(*v1beta1.Canary) (*v1beta1.Canary, error)
Update(*v1beta1.Canary) (*v1beta1.Canary, error)
UpdateStatus(*v1beta1.Canary) (*v1beta1.Canary, error)
Create(*v1alpha1.Canary) (*v1alpha1.Canary, error)
Update(*v1alpha1.Canary) (*v1alpha1.Canary, error)
UpdateStatus(*v1alpha1.Canary) (*v1alpha1.Canary, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string, options v1.GetOptions) (*v1beta1.Canary, error)
List(opts v1.ListOptions) (*v1beta1.CanaryList, error)
Get(name string, options v1.GetOptions) (*v1alpha1.Canary, error)
List(opts v1.ListOptions) (*v1alpha1.CanaryList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Canary, err error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error)
CanaryExpansion
}
@@ -54,7 +54,7 @@ type canaries struct {
}
// newCanaries returns a Canaries
func newCanaries(c *FlaggerV1beta1Client, namespace string) *canaries {
func newCanaries(c *FlaggerV1alpha1Client, namespace string) *canaries {
return &canaries{
client: c.RESTClient(),
ns: namespace,
@@ -62,8 +62,8 @@ func newCanaries(c *FlaggerV1beta1Client, 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 *v1beta1.Canary, err error) {
result = &v1beta1.Canary{}
func (c *canaries) Get(name string, options v1.GetOptions) (result *v1alpha1.Canary, err error) {
result = &v1alpha1.Canary{}
err = c.client.Get().
Namespace(c.ns).
Resource("canaries").
@@ -75,8 +75,8 @@ func (c *canaries) Get(name string, options v1.GetOptions) (result *v1beta1.Cana
}
// List takes label and field selectors, and returns the list of Canaries that match those selectors.
func (c *canaries) List(opts v1.ListOptions) (result *v1beta1.CanaryList, err error) {
result = &v1beta1.CanaryList{}
func (c *canaries) List(opts v1.ListOptions) (result *v1alpha1.CanaryList, err error) {
result = &v1alpha1.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 *v1beta1.Canary) (result *v1beta1.Canary, err error) {
result = &v1beta1.Canary{}
func (c *canaries) Create(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) {
result = &v1alpha1.Canary{}
err = c.client.Post().
Namespace(c.ns).
Resource("canaries").
@@ -109,8 +109,8 @@ func (c *canaries) Create(canary *v1beta1.Canary) (result *v1beta1.Canary, err e
}
// 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 *v1beta1.Canary) (result *v1beta1.Canary, err error) {
result = &v1beta1.Canary{}
func (c *canaries) Update(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) {
result = &v1alpha1.Canary{}
err = c.client.Put().
Namespace(c.ns).
Resource("canaries").
@@ -124,8 +124,8 @@ func (c *canaries) Update(canary *v1beta1.Canary) (result *v1beta1.Canary, err e
// 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 *v1beta1.Canary) (result *v1beta1.Canary, err error) {
result = &v1beta1.Canary{}
func (c *canaries) UpdateStatus(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) {
result = &v1alpha1.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 *v1beta1.Canary, err error) {
result = &v1beta1.Canary{}
func (c *canaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error) {
result = &v1alpha1.Canary{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("canaries").

View File

@@ -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 v1beta1
package v1alpha1

View File

@@ -19,7 +19,7 @@ limitations under the License.
package fake
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
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 *FakeFlaggerV1beta1
Fake *FakeFlaggerV1alpha1
ns string
}
var canariesResource = schema.GroupVersionResource{Group: "flagger.app", Version: "v1beta1", Resource: "canaries"}
var canariesResource = schema.GroupVersionResource{Group: "flagger.app", Version: "v1alpha1", Resource: "canaries"}
var canariesKind = schema.GroupVersionKind{Group: "flagger.app", Version: "v1beta1", Kind: "Canary"}
var canariesKind = schema.GroupVersionKind{Group: "flagger.app", Version: "v1alpha1", 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 *v1beta1.Canary, err error) {
func (c *FakeCanaries) Get(name string, options v1.GetOptions) (result *v1alpha1.Canary, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(canariesResource, c.ns, name), &v1beta1.Canary{})
Invokes(testing.NewGetAction(canariesResource, c.ns, name), &v1alpha1.Canary{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Canary), err
return obj.(*v1alpha1.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 *v1beta1.CanaryList, err error) {
func (c *FakeCanaries) List(opts v1.ListOptions) (result *v1alpha1.CanaryList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(canariesResource, canariesKind, c.ns, opts), &v1beta1.CanaryList{})
Invokes(testing.NewListAction(canariesResource, canariesKind, c.ns, opts), &v1alpha1.CanaryList{})
if obj == nil {
return nil, err
@@ -62,8 +62,8 @@ func (c *FakeCanaries) List(opts v1.ListOptions) (result *v1beta1.CanaryList, er
if label == nil {
label = labels.Everything()
}
list := &v1beta1.CanaryList{ListMeta: obj.(*v1beta1.CanaryList).ListMeta}
for _, item := range obj.(*v1beta1.CanaryList).Items {
list := &v1alpha1.CanaryList{ListMeta: obj.(*v1alpha1.CanaryList).ListMeta}
for _, item := range obj.(*v1alpha1.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 *v1beta1.Canary) (result *v1beta1.Canary, err error) {
func (c *FakeCanaries) Create(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(canariesResource, c.ns, canary), &v1beta1.Canary{})
Invokes(testing.NewCreateAction(canariesResource, c.ns, canary), &v1alpha1.Canary{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Canary), err
return obj.(*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 *FakeCanaries) Update(canary *v1beta1.Canary) (result *v1beta1.Canary, err error) {
func (c *FakeCanaries) Update(canary *v1alpha1.Canary) (result *v1alpha1.Canary, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(canariesResource, c.ns, canary), &v1beta1.Canary{})
Invokes(testing.NewUpdateAction(canariesResource, c.ns, canary), &v1alpha1.Canary{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Canary), err
return obj.(*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 *FakeCanaries) UpdateStatus(canary *v1beta1.Canary) (*v1beta1.Canary, error) {
func (c *FakeCanaries) UpdateStatus(canary *v1alpha1.Canary) (*v1alpha1.Canary, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(canariesResource, "status", c.ns, canary), &v1beta1.Canary{})
Invokes(testing.NewUpdateSubresourceAction(canariesResource, "status", c.ns, canary), &v1alpha1.Canary{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Canary), err
return obj.(*v1alpha1.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), &v1beta1.Canary{})
Invokes(testing.NewDeleteAction(canariesResource, c.ns, name), &v1alpha1.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, &v1beta1.CanaryList{})
_, err := c.Fake.Invokes(action, &v1alpha1.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 *v1beta1.Canary, err error) {
func (c *FakeCanaries) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Canary, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(canariesResource, c.ns, name, data, subresources...), &v1beta1.Canary{})
Invokes(testing.NewPatchSubresourceAction(canariesResource, c.ns, name, data, subresources...), &v1alpha1.Canary{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.Canary), err
return obj.(*v1alpha1.Canary), err
}

View File

@@ -19,26 +19,22 @@ limitations under the License.
package fake
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeFlaggerV1beta1 struct {
type FakeFlaggerV1alpha1 struct {
*testing.Fake
}
func (c *FakeFlaggerV1beta1) Canaries(namespace string) v1beta1.CanaryInterface {
func (c *FakeFlaggerV1alpha1) Canaries(namespace string) v1alpha1.CanaryInterface {
return &FakeCanaries{c, namespace}
}
func (c *FakeFlaggerV1beta1) CanaryDeployments(namespace string) v1beta1.CanaryDeploymentInterface {
return &FakeCanaryDeployments{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeFlaggerV1beta1) RESTClient() rest.Interface {
func (c *FakeFlaggerV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@@ -16,36 +16,31 @@ limitations under the License.
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
"github.com/stefanprodan/flagger/pkg/client/clientset/versioned/scheme"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
rest "k8s.io/client-go/rest"
)
type FlaggerV1beta1Interface interface {
type FlaggerV1alpha1Interface interface {
RESTClient() rest.Interface
CanariesGetter
CanaryDeploymentsGetter
}
// FlaggerV1beta1Client is used to interact with features provided by the flagger.app group.
type FlaggerV1beta1Client struct {
// FlaggerV1alpha1Client is used to interact with features provided by the flagger.app group.
type FlaggerV1alpha1Client struct {
restClient rest.Interface
}
func (c *FlaggerV1beta1Client) Canaries(namespace string) CanaryInterface {
func (c *FlaggerV1alpha1Client) Canaries(namespace string) CanaryInterface {
return newCanaries(c, namespace)
}
func (c *FlaggerV1beta1Client) CanaryDeployments(namespace string) CanaryDeploymentInterface {
return newCanaryDeployments(c, namespace)
}
// NewForConfig creates a new FlaggerV1beta1Client for the given config.
func NewForConfig(c *rest.Config) (*FlaggerV1beta1Client, error) {
// NewForConfig creates a new FlaggerV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*FlaggerV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
@@ -54,12 +49,12 @@ func NewForConfig(c *rest.Config) (*FlaggerV1beta1Client, error) {
if err != nil {
return nil, err
}
return &FlaggerV1beta1Client{client}, nil
return &FlaggerV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new FlaggerV1beta1Client for the given config and
// NewForConfigOrDie creates a new FlaggerV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *FlaggerV1beta1Client {
func NewForConfigOrDie(c *rest.Config) *FlaggerV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
@@ -67,13 +62,13 @@ func NewForConfigOrDie(c *rest.Config) *FlaggerV1beta1Client {
return client
}
// New creates a new FlaggerV1beta1Client for the given RESTClient.
func New(c rest.Interface) *FlaggerV1beta1Client {
return &FlaggerV1beta1Client{c}
// New creates a new FlaggerV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *FlaggerV1alpha1Client {
return &FlaggerV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1beta1.SchemeGroupVersion
gv := v1alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
@@ -87,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 *FlaggerV1beta1Client) RESTClient() rest.Interface {
func (c *FlaggerV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}

View File

@@ -16,8 +16,6 @@ limitations under the License.
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
type CanaryExpansion interface{}
type CanaryDeploymentExpansion interface{}

View File

@@ -1,174 +0,0 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
scheme "github.com/stefanprodan/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"
)
// CanaryDeploymentsGetter has a method to return a CanaryDeploymentInterface.
// A group's client should implement this interface.
type CanaryDeploymentsGetter interface {
CanaryDeployments(namespace string) CanaryDeploymentInterface
}
// CanaryDeploymentInterface has methods to work with CanaryDeployment resources.
type CanaryDeploymentInterface interface {
Create(*v1beta1.CanaryDeployment) (*v1beta1.CanaryDeployment, error)
Update(*v1beta1.CanaryDeployment) (*v1beta1.CanaryDeployment, error)
UpdateStatus(*v1beta1.CanaryDeployment) (*v1beta1.CanaryDeployment, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string, options v1.GetOptions) (*v1beta1.CanaryDeployment, error)
List(opts v1.ListOptions) (*v1beta1.CanaryDeploymentList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CanaryDeployment, err error)
CanaryDeploymentExpansion
}
// canaryDeployments implements CanaryDeploymentInterface
type canaryDeployments struct {
client rest.Interface
ns string
}
// newCanaryDeployments returns a CanaryDeployments
func newCanaryDeployments(c *FlaggerV1beta1Client, namespace string) *canaryDeployments {
return &canaryDeployments{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the canaryDeployment, and returns the corresponding canaryDeployment object, and an error if there is any.
func (c *canaryDeployments) Get(name string, options v1.GetOptions) (result *v1beta1.CanaryDeployment, err error) {
result = &v1beta1.CanaryDeployment{}
err = c.client.Get().
Namespace(c.ns).
Resource("canarydeployments").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of CanaryDeployments that match those selectors.
func (c *canaryDeployments) List(opts v1.ListOptions) (result *v1beta1.CanaryDeploymentList, err error) {
result = &v1beta1.CanaryDeploymentList{}
err = c.client.Get().
Namespace(c.ns).
Resource("canarydeployments").
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested canaryDeployments.
func (c *canaryDeployments) Watch(opts v1.ListOptions) (watch.Interface, error) {
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("canarydeployments").
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
// Create takes the representation of a canaryDeployment and creates it. Returns the server's representation of the canaryDeployment, and an error, if there is any.
func (c *canaryDeployments) Create(canaryDeployment *v1beta1.CanaryDeployment) (result *v1beta1.CanaryDeployment, err error) {
result = &v1beta1.CanaryDeployment{}
err = c.client.Post().
Namespace(c.ns).
Resource("canarydeployments").
Body(canaryDeployment).
Do().
Into(result)
return
}
// Update takes the representation of a canaryDeployment and updates it. Returns the server's representation of the canaryDeployment, and an error, if there is any.
func (c *canaryDeployments) Update(canaryDeployment *v1beta1.CanaryDeployment) (result *v1beta1.CanaryDeployment, err error) {
result = &v1beta1.CanaryDeployment{}
err = c.client.Put().
Namespace(c.ns).
Resource("canarydeployments").
Name(canaryDeployment.Name).
Body(canaryDeployment).
Do().
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *canaryDeployments) UpdateStatus(canaryDeployment *v1beta1.CanaryDeployment) (result *v1beta1.CanaryDeployment, err error) {
result = &v1beta1.CanaryDeployment{}
err = c.client.Put().
Namespace(c.ns).
Resource("canarydeployments").
Name(canaryDeployment.Name).
SubResource("status").
Body(canaryDeployment).
Do().
Into(result)
return
}
// Delete takes name of the canaryDeployment and deletes it. Returns an error if one occurs.
func (c *canaryDeployments) Delete(name string, options *v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("canarydeployments").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *canaryDeployments) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("canarydeployments").
VersionedParams(&listOptions, scheme.ParameterCodec).
Body(options).
Do().
Error()
}
// Patch applies the patch and returns the patched canaryDeployment.
func (c *canaryDeployments) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CanaryDeployment, err error) {
result = &v1beta1.CanaryDeployment{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("canarydeployments").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}

View File

@@ -1,140 +0,0 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeCanaryDeployments implements CanaryDeploymentInterface
type FakeCanaryDeployments struct {
Fake *FakeFlaggerV1beta1
ns string
}
var canarydeploymentsResource = schema.GroupVersionResource{Group: "flagger.app", Version: "v1beta1", Resource: "canarydeployments"}
var canarydeploymentsKind = schema.GroupVersionKind{Group: "flagger.app", Version: "v1beta1", Kind: "CanaryDeployment"}
// Get takes name of the canaryDeployment, and returns the corresponding canaryDeployment object, and an error if there is any.
func (c *FakeCanaryDeployments) Get(name string, options v1.GetOptions) (result *v1beta1.CanaryDeployment, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(canarydeploymentsResource, c.ns, name), &v1beta1.CanaryDeployment{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.CanaryDeployment), err
}
// List takes label and field selectors, and returns the list of CanaryDeployments that match those selectors.
func (c *FakeCanaryDeployments) List(opts v1.ListOptions) (result *v1beta1.CanaryDeploymentList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(canarydeploymentsResource, canarydeploymentsKind, c.ns, opts), &v1beta1.CanaryDeploymentList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1beta1.CanaryDeploymentList{ListMeta: obj.(*v1beta1.CanaryDeploymentList).ListMeta}
for _, item := range obj.(*v1beta1.CanaryDeploymentList).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 canaryDeployments.
func (c *FakeCanaryDeployments) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(canarydeploymentsResource, c.ns, opts))
}
// Create takes the representation of a canaryDeployment and creates it. Returns the server's representation of the canaryDeployment, and an error, if there is any.
func (c *FakeCanaryDeployments) Create(canaryDeployment *v1beta1.CanaryDeployment) (result *v1beta1.CanaryDeployment, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(canarydeploymentsResource, c.ns, canaryDeployment), &v1beta1.CanaryDeployment{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.CanaryDeployment), err
}
// Update takes the representation of a canaryDeployment and updates it. Returns the server's representation of the canaryDeployment, and an error, if there is any.
func (c *FakeCanaryDeployments) Update(canaryDeployment *v1beta1.CanaryDeployment) (result *v1beta1.CanaryDeployment, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(canarydeploymentsResource, c.ns, canaryDeployment), &v1beta1.CanaryDeployment{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.CanaryDeployment), 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 *FakeCanaryDeployments) UpdateStatus(canaryDeployment *v1beta1.CanaryDeployment) (*v1beta1.CanaryDeployment, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(canarydeploymentsResource, "status", c.ns, canaryDeployment), &v1beta1.CanaryDeployment{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.CanaryDeployment), err
}
// Delete takes name of the canaryDeployment and deletes it. Returns an error if one occurs.
func (c *FakeCanaryDeployments) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(canarydeploymentsResource, c.ns, name), &v1beta1.CanaryDeployment{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeCanaryDeployments) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(canarydeploymentsResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &v1beta1.CanaryDeploymentList{})
return err
}
// Patch applies the patch and returns the patched canaryDeployment.
func (c *FakeCanaryDeployments) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CanaryDeployment, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(canarydeploymentsResource, c.ns, name, data, subresources...), &v1beta1.CanaryDeployment{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.CanaryDeployment), err
}

View File

@@ -19,14 +19,14 @@ limitations under the License.
package flagger
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha1"
internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1beta1 provides access to shared informers for resources in V1beta1.
V1beta1() v1beta1.Interface
// V1alpha1 provides access to shared informers for resources in V1alpha1.
V1alpha1() v1alpha1.Interface
}
type group struct {
@@ -40,7 +40,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1beta1 returns a new v1beta1.Interface.
func (g *group) V1beta1() v1beta1.Interface {
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
// V1alpha1 returns a new v1alpha1.Interface.
func (g *group) V1alpha1() v1alpha1.Interface {
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@@ -16,15 +16,15 @@ limitations under the License.
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
time "time"
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
versioned "github.com/stefanprodan/flagger/pkg/client/clientset/versioned"
internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces"
v1beta1 "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha1"
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() v1beta1.CanaryLister
Lister() v1alpha1.CanaryLister
}
type canaryInformer struct {
@@ -61,16 +61,16 @@ func NewFilteredCanaryInformer(client versioned.Interface, namespace string, res
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FlaggerV1beta1().Canaries(namespace).List(options)
return client.FlaggerV1alpha1().Canaries(namespace).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FlaggerV1beta1().Canaries(namespace).Watch(options)
return client.FlaggerV1alpha1().Canaries(namespace).Watch(options)
},
},
&flaggerv1beta1.Canary{},
&flaggerv1alpha1.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(&flaggerv1beta1.Canary{}, f.defaultInformer)
return f.factory.InformerFor(&flaggerv1alpha1.Canary{}, f.defaultInformer)
}
func (f *canaryInformer) Lister() v1beta1.CanaryLister {
return v1beta1.NewCanaryLister(f.Informer().GetIndexer())
func (f *canaryInformer) Lister() v1alpha1.CanaryLister {
return v1alpha1.NewCanaryLister(f.Informer().GetIndexer())
}

View File

@@ -16,7 +16,7 @@ limitations under the License.
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces"
@@ -26,8 +26,6 @@ import (
type Interface interface {
// Canaries returns a CanaryInformer.
Canaries() CanaryInformer
// CanaryDeployments returns a CanaryDeploymentInformer.
CanaryDeployments() CanaryDeploymentInformer
}
type version struct {
@@ -45,8 +43,3 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (v *version) Canaries() CanaryInformer {
return &canaryInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// CanaryDeployments returns a CanaryDeploymentInformer.
func (v *version) CanaryDeployments() CanaryDeploymentInformer {
return &canaryDeploymentInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,89 +0,0 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1beta1
import (
time "time"
flaggerv1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
versioned "github.com/stefanprodan/flagger/pkg/client/clientset/versioned"
internalinterfaces "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/internalinterfaces"
v1beta1 "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// CanaryDeploymentInformer provides access to a shared informer and lister for
// CanaryDeployments.
type CanaryDeploymentInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1beta1.CanaryDeploymentLister
}
type canaryDeploymentInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewCanaryDeploymentInformer constructs a new informer for CanaryDeployment 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 NewCanaryDeploymentInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredCanaryDeploymentInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredCanaryDeploymentInformer constructs a new informer for CanaryDeployment 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 NewFilteredCanaryDeploymentInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FlaggerV1beta1().CanaryDeployments(namespace).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.FlaggerV1beta1().CanaryDeployments(namespace).Watch(options)
},
},
&flaggerv1beta1.CanaryDeployment{},
resyncPeriod,
indexers,
)
}
func (f *canaryDeploymentInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredCanaryDeploymentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *canaryDeploymentInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&flaggerv1beta1.CanaryDeployment{}, f.defaultInformer)
}
func (f *canaryDeploymentInformer) Lister() v1beta1.CanaryDeploymentLister {
return v1beta1.NewCanaryDeploymentLister(f.Informer().GetIndexer())
}

View File

@@ -21,7 +21,7 @@ package externalversions
import (
"fmt"
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
)
@@ -52,11 +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=v1beta1
case v1beta1.SchemeGroupVersion.WithResource("canaries"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1beta1().Canaries().Informer()}, nil
case v1beta1.SchemeGroupVersion.WithResource("canarydeployments"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1beta1().CanaryDeployments().Informer()}, nil
// Group=flagger.app, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("canaries"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1alpha1().Canaries().Informer()}, nil
}

View File

@@ -16,10 +16,10 @@ limitations under the License.
// Code generated by lister-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
v1alpha1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
"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 []*v1beta1.Canary, err error)
List(selector labels.Selector) (ret []*v1alpha1.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 []*v1beta1.Canary, err error) {
func (s *canaryLister) List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1beta1.Canary))
ret = append(ret, m.(*v1alpha1.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 []*v1beta1.Canary, err error)
List(selector labels.Selector) (ret []*v1alpha1.Canary, err error)
// Get retrieves the Canary from the indexer for a given namespace and name.
Get(name string) (*v1beta1.Canary, error)
Get(name string) (*v1alpha1.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 []*v1beta1.Canary, err error) {
func (s canaryNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Canary, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1beta1.Canary))
ret = append(ret, m.(*v1alpha1.Canary))
})
return ret, err
}
// Get retrieves the Canary from the indexer for a given namespace and name.
func (s canaryNamespaceLister) Get(name string) (*v1beta1.Canary, error) {
func (s canaryNamespaceLister) Get(name string) (*v1alpha1.Canary, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1beta1.Resource("canary"), name)
return nil, errors.NewNotFound(v1alpha1.Resource("canary"), name)
}
return obj.(*v1beta1.Canary), nil
return obj.(*v1alpha1.Canary), nil
}

View File

@@ -16,7 +16,7 @@ limitations under the License.
// Code generated by lister-gen. DO NOT EDIT.
package v1beta1
package v1alpha1
// CanaryListerExpansion allows custom methods to be added to
// CanaryLister.
@@ -25,11 +25,3 @@ type CanaryListerExpansion interface{}
// CanaryNamespaceListerExpansion allows custom methods to be added to
// CanaryNamespaceLister.
type CanaryNamespaceListerExpansion interface{}
// CanaryDeploymentListerExpansion allows custom methods to be added to
// CanaryDeploymentLister.
type CanaryDeploymentListerExpansion interface{}
// CanaryDeploymentNamespaceListerExpansion allows custom methods to be added to
// CanaryDeploymentNamespaceLister.
type CanaryDeploymentNamespaceListerExpansion interface{}

View File

@@ -1,94 +0,0 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1beta1
import (
v1beta1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// CanaryDeploymentLister helps list CanaryDeployments.
type CanaryDeploymentLister interface {
// List lists all CanaryDeployments in the indexer.
List(selector labels.Selector) (ret []*v1beta1.CanaryDeployment, err error)
// CanaryDeployments returns an object that can list and get CanaryDeployments.
CanaryDeployments(namespace string) CanaryDeploymentNamespaceLister
CanaryDeploymentListerExpansion
}
// canaryDeploymentLister implements the CanaryDeploymentLister interface.
type canaryDeploymentLister struct {
indexer cache.Indexer
}
// NewCanaryDeploymentLister returns a new CanaryDeploymentLister.
func NewCanaryDeploymentLister(indexer cache.Indexer) CanaryDeploymentLister {
return &canaryDeploymentLister{indexer: indexer}
}
// List lists all CanaryDeployments in the indexer.
func (s *canaryDeploymentLister) List(selector labels.Selector) (ret []*v1beta1.CanaryDeployment, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1beta1.CanaryDeployment))
})
return ret, err
}
// CanaryDeployments returns an object that can list and get CanaryDeployments.
func (s *canaryDeploymentLister) CanaryDeployments(namespace string) CanaryDeploymentNamespaceLister {
return canaryDeploymentNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// CanaryDeploymentNamespaceLister helps list and get CanaryDeployments.
type CanaryDeploymentNamespaceLister interface {
// List lists all CanaryDeployments in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1beta1.CanaryDeployment, err error)
// Get retrieves the CanaryDeployment from the indexer for a given namespace and name.
Get(name string) (*v1beta1.CanaryDeployment, error)
CanaryDeploymentNamespaceListerExpansion
}
// canaryDeploymentNamespaceLister implements the CanaryDeploymentNamespaceLister
// interface.
type canaryDeploymentNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all CanaryDeployments in the indexer for a given namespace.
func (s canaryDeploymentNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.CanaryDeployment, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1beta1.CanaryDeployment))
})
return ret, err
}
// Get retrieves the CanaryDeployment from the indexer for a given namespace and name.
func (s canaryDeploymentNamespaceLister) Get(name string) (*v1beta1.CanaryDeployment, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1beta1.Resource("canarydeployment"), name)
}
return obj.(*v1beta1.CanaryDeployment), nil
}

View File

@@ -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/v1beta1"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
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/v1beta1"
flaggerlisters "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1beta1"
flaggerinformers "github.com/stefanprodan/flagger/pkg/client/informers/externalversions/flagger/v1alpha1"
flaggerlisters "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1alpha1"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@@ -76,7 +76,7 @@ func NewController(
}
rolloutInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: ctrl.enqueueRollout,
AddFunc: ctrl.enqueue,
UpdateFunc: func(old, new interface{}) {
oldRoll, ok := checkCustomResourceType(old, logger)
if !ok {
@@ -89,7 +89,7 @@ func NewController(
if diff := cmp.Diff(newRoll.Spec, oldRoll.Spec); diff != "" {
ctrl.logger.Debugf("Diff detected %s.%s %s", oldRoll.Name, oldRoll.Namespace, diff)
ctrl.enqueueRollout(new)
ctrl.enqueue(new)
}
},
DeleteFunc: func(old interface{}) {
@@ -108,7 +108,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
c.logger.Info("Starting controller")
c.logger.Info("Starting operator")
for i := 0; i < threadiness; i++ {
go wait.Until(func() {
@@ -117,7 +117,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
}, time.Second, stopCh)
}
c.logger.Info("Started workers")
c.logger.Info("Started operator workers")
tickChan := time.NewTicker(c.rolloutWindow).C
for {
@@ -125,7 +125,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
case <-tickChan:
c.doRollouts()
case <-stopCh:
c.logger.Info("Shutting down workers")
c.logger.Info("Shutting down operator workers")
return nil
}
}
@@ -174,19 +174,26 @@ func (c *Controller) syncHandler(key string) error {
utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
return nil
}
rollout, err := c.rolloutLister.Canaries(namespace).Get(name)
cd, err := c.rolloutLister.Canaries(namespace).Get(name)
if errors.IsNotFound(err) {
utilruntime.HandleError(fmt.Errorf("rollout '%s' in work queue no longer exists", key))
utilruntime.HandleError(fmt.Errorf("'%s' in work queue no longer exists", key))
return nil
}
c.rollouts.Store(fmt.Sprintf("%s.%s", rollout.Name, rollout.Namespace), rollout)
c.rollouts.Store(fmt.Sprintf("%s.%s", cd.Name, cd.Namespace), cd)
err = c.bootstrapDeployment(cd)
if err != nil {
c.logger.Warnf("%s.%s bootstrap error %v", cd.Name, cd.Namespace, err)
return err
}
c.logger.Infof("Synced %s", key)
return nil
}
func (c *Controller) enqueueRollout(obj interface{}) {
func (c *Controller) enqueue(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
@@ -196,6 +203,16 @@ func (c *Controller) enqueueRollout(obj interface{}) {
c.workqueue.AddRateLimited(key)
}
func checkCustomResourceType(obj interface{}, logger *zap.SugaredLogger) (flaggerv1.Canary, bool) {
var roll *flaggerv1.Canary
var ok bool
if roll, ok = obj.(*flaggerv1.Canary); !ok {
logger.Errorf("Event Watch received an invalid object: %#v", obj)
return flaggerv1.Canary{}, false
}
return *roll, true
}
func (c *Controller) recordEventInfof(r *flaggerv1.Canary, template string, args ...interface{}) {
c.logger.Infof(template, args...)
c.recorder.Event(r, corev1.EventTypeNormal, "Synced", fmt.Sprintf(template, args...))
@@ -210,13 +227,3 @@ func (c *Controller) recordEventWarningf(r *flaggerv1.Canary, template string, a
c.logger.Infof(template, args...)
c.recorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
}
func checkCustomResourceType(obj interface{}, logger *zap.SugaredLogger) (flaggerv1.Canary, bool) {
var roll *flaggerv1.Canary
var ok bool
if roll, ok = obj.(*flaggerv1.Canary); !ok {
logger.Errorf("Event Watch received an invalid object: %#v", obj)
return flaggerv1.Canary{}, false
}
return *roll, true
}

View File

@@ -1,10 +1,10 @@
package operator
package controller
import (
"fmt"
istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@@ -13,7 +13,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)
func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
func (c *Controller) bootstrapDeployment(cd *flaggerv1.Canary) error {
canaryName := cd.Spec.TargetRef.Name
primaryName := fmt.Sprintf("%s-primary", cd.Spec.TargetRef.Name)
@@ -39,7 +39,7 @@ func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
*metav1.NewControllerRef(cd, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryDeploymentKind,
Kind: flaggerv1.CanaryKind,
}),
},
},
@@ -83,7 +83,7 @@ func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
*metav1.NewControllerRef(cd, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryDeploymentKind,
Kind: flaggerv1.CanaryKind,
}),
},
},
@@ -122,7 +122,7 @@ func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
*metav1.NewControllerRef(cd, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryDeploymentKind,
Kind: flaggerv1.CanaryKind,
}),
},
},
@@ -160,7 +160,7 @@ func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
*metav1.NewControllerRef(cd, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryDeploymentKind,
Kind: flaggerv1.CanaryKind,
}),
},
},
@@ -201,7 +201,7 @@ func (c *Controller) bootstrapDeployment(cd *flaggerv1.CanaryDeployment) error {
*metav1.NewControllerRef(cd, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryDeploymentKind,
Kind: flaggerv1.CanaryKind,
}),
},
},

View File

@@ -5,7 +5,7 @@ import (
"time"
istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -13,7 +13,7 @@ import (
func (c *Controller) doRollouts() {
c.rollouts.Range(func(key interface{}, value interface{}) bool {
r := value.(*flaggerv1.Canary)
if r.Spec.TargetKind == "Deployment" {
if r.Spec.TargetRef.Kind == "Deployment" {
go c.advanceDeploymentRollout(r.Name, r.Namespace)
}
return true
@@ -27,6 +27,12 @@ func (c *Controller) advanceDeploymentRollout(name string, namespace string) {
return
}
err := c.bootstrapDeployment(r)
if err != nil {
c.recordEventWarningf(r, "%v", err)
return
}
// set max weight default value to 100%
maxWeight := 100
if r.Spec.CanaryAnalysis.MaxWeight > 0 {
@@ -34,13 +40,13 @@ func (c *Controller) advanceDeploymentRollout(name string, namespace string) {
}
// gate stage: check if canary deployment exists and is healthy
canary, ok := c.getCanaryDeployment(r, r.Spec.Canary.Name, r.Namespace)
canary, ok := c.getCanaryDeployment(r, r.Spec.TargetRef.Name, r.Namespace)
if !ok {
return
}
// gate stage: check if primary deployment exists and is healthy
primary, ok := c.getDeployment(r, r.Spec.Primary.Name, r.Namespace)
primary, ok := c.getDeployment(r, fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name), r.Namespace)
if !ok {
return
}
@@ -60,7 +66,7 @@ func (c *Controller) advanceDeploymentRollout(name string, namespace string) {
// gate stage: check if the number of failed checks reached the threshold
if r.Status.State == "running" && r.Status.FailedChecks >= r.Spec.CanaryAnalysis.Threshold {
c.recordEventWarningf(r, "Rolling back %s.%s failed checks threshold reached %v",
r.Spec.Canary.Name, r.Namespace, r.Status.FailedChecks)
r.Name, r.Namespace, r.Status.FailedChecks)
// route all traffic back to primary
primaryRoute.Weight = 100
@@ -136,7 +142,7 @@ func (c *Controller) advanceDeploymentRollout(name string, namespace string) {
}
func (c *Controller) getRollout(name string, namespace string) (*flaggerv1.Canary, bool) {
r, err := c.rolloutClient.FlaggerV1beta1().Canaries(namespace).Get(name, v1.GetOptions{})
r, err := c.rolloutClient.FlaggerV1alpha1().Canaries(namespace).Get(name, v1.GetOptions{})
if err != nil {
c.logger.Errorf("Canary %s.%s not found", name, namespace)
return nil, false
@@ -146,19 +152,26 @@ func (c *Controller) getRollout(name string, namespace string) (*flaggerv1.Canar
}
func (c *Controller) checkRolloutStatus(r *flaggerv1.Canary, canary *appsv1.Deployment) bool {
var err error
canaryRevision, err := c.getDeploymentSpecEnc(canary)
if err != nil {
c.logger.Errorf("Canary %s.%s not found: %v", r.Name, r.Namespace, err)
return false
}
if r.Status.State == "" {
r.Status = flaggerv1.CanaryStatus{
State: "running",
CanaryRevision: canary.ResourceVersion,
State: "initialized",
CanaryRevision: canaryRevision,
FailedChecks: 0,
}
r, err = c.rolloutClient.FlaggerV1beta1().Canaries(r.Namespace).Update(r)
r, err = c.rolloutClient.FlaggerV1alpha1().Canaries(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
}
return true
c.recordEventInfof(r, "Initialization done! %s.%s", canary.GetName(), canary.Namespace)
return false
}
if r.Status.State == "running" {
@@ -166,38 +179,31 @@ func (c *Controller) checkRolloutStatus(r *flaggerv1.Canary, canary *appsv1.Depl
}
if r.Status.State == "promotion-finished" {
c.setCanaryRevision(r, "finished")
c.logger.Infof("Promotion completed! %s.%s revision %s", r.Spec.Canary.Name, r.Namespace,
c.getDeploymentRevision(r.Spec.Canary.Name, r.Namespace))
c.setCanaryRevision(r, canary, "finished")
c.logger.Infof("Promotion completed! %s.%s", r.Name, r.Namespace)
return false
}
if r.Status.State == "promotion-failed" {
c.setCanaryRevision(r, "failed")
c.logger.Infof("Promotion failed! %s.%s revision %s", r.Spec.Canary.Name, r.Namespace,
c.getDeploymentRevision(r.Spec.Canary.Name, r.Namespace))
c.setCanaryRevision(r, canary, "failed")
c.logger.Infof("Promotion failed! %s.%s", r.Name, r.Namespace)
return false
}
if r.Status.CanaryRevision != canary.ResourceVersion {
c.recordEventInfof(r, "New revision detected %s.%s old %s new %s",
canary.GetName(), canary.Namespace, r.Status.CanaryRevision, canary.ResourceVersion)
if diff, err := c.diffDeploymentSpec(r, canary); diff {
c.recordEventInfof(r, "New revision detected %s.%s",
canary.GetName(), canary.Namespace)
canary.Spec.Replicas = int32p(1)
canary, err = c.kubeClient.AppsV1().Deployments(canary.Namespace).Update(canary)
if err != nil {
c.recordEventErrorf(r, "Scaling up %s.%s failed: %v", canary.GetName(), canary.Namespace, err)
return false
}
r.Status = flaggerv1.CanaryStatus{
State: "running",
CanaryRevision: canary.ResourceVersion,
FailedChecks: 0,
}
r, err = c.rolloutClient.FlaggerV1beta1().Canaries(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
FailedChecks: 0,
}
c.setCanaryRevision(r, canary, "running")
c.recordEventInfof(r, "Scaling up %s.%s", canary.GetName(), canary.Namespace)
return false
@@ -209,7 +215,7 @@ func (c *Controller) checkRolloutStatus(r *flaggerv1.Canary, canary *appsv1.Depl
func (c *Controller) updateRolloutStatus(r *flaggerv1.Canary, status string) bool {
var err error
r.Status.State = status
r, err = c.rolloutClient.FlaggerV1beta1().Canaries(r.Namespace).Update(r)
r, err = c.rolloutClient.FlaggerV1alpha1().Canaries(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
@@ -220,7 +226,7 @@ func (c *Controller) updateRolloutStatus(r *flaggerv1.Canary, status string) boo
func (c *Controller) updateRolloutFailedChecks(r *flaggerv1.Canary, val int) bool {
var err error
r.Status.FailedChecks = val
r, err = c.rolloutClient.FlaggerV1beta1().Canaries(r.Namespace).Update(r)
r, err = c.rolloutClient.FlaggerV1alpha1().Canaries(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
@@ -262,20 +268,10 @@ func (c *Controller) getCanaryDeployment(r *flaggerv1.Canary, name string, names
return dep, true
}
func (c *Controller) getDeploymentRevision(name string, namespace string) string {
dep, err := c.kubeClient.AppsV1().Deployments(namespace).Get(name, v1.GetOptions{})
if err != nil {
c.logger.Errorf("Deployment %s.%s not found", name, namespace)
return ""
}
return dep.ResourceVersion
}
func (c *Controller) checkDeploymentMetrics(r *flaggerv1.Canary) bool {
for _, metric := range r.Spec.CanaryAnalysis.Metrics {
if metric.Name == "istio_requests_total" {
val, err := c.getDeploymentCounter(r.Spec.Canary.Name, r.Namespace, metric.Name, metric.Interval)
val, err := c.getDeploymentCounter(r.Spec.TargetRef.Name, r.Namespace, metric.Name, metric.Interval)
if err != nil {
c.recordEventErrorf(r, "Metrics server %s query failed: %v", c.metricsServer, err)
return false
@@ -288,7 +284,7 @@ func (c *Controller) checkDeploymentMetrics(r *flaggerv1.Canary) bool {
}
if metric.Name == "istio_request_duration_seconds_bucket" {
val, err := c.GetDeploymentHistogram(r.Spec.Canary.Name, r.Namespace, metric.Name, metric.Interval)
val, err := c.GetDeploymentHistogram(r.Spec.TargetRef.Name, r.Namespace, metric.Name, metric.Interval)
if err != nil {
c.recordEventErrorf(r, "Metrics server %s query failed: %v", c.metricsServer, err)
return false
@@ -306,9 +302,9 @@ func (c *Controller) checkDeploymentMetrics(r *flaggerv1.Canary) bool {
}
func (c *Controller) scaleToZeroCanary(r *flaggerv1.Canary) {
canary, err := c.kubeClient.AppsV1().Deployments(r.Namespace).Get(r.Spec.Canary.Name, v1.GetOptions{})
canary, err := c.kubeClient.AppsV1().Deployments(r.Namespace).Get(r.Spec.TargetRef.Name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "Deployment %s.%s not found", r.Spec.Canary.Name, r.Namespace)
c.recordEventErrorf(r, "Deployment %s.%s not found", r.Spec.TargetRef.Name, r.Namespace)
return
}
//HPA https://github.com/kubernetes/kubernetes/pull/29212
@@ -320,22 +316,15 @@ func (c *Controller) scaleToZeroCanary(r *flaggerv1.Canary) {
}
}
func (c *Controller) setCanaryRevision(r *flaggerv1.Canary, status string) {
canaryRevision := c.getDeploymentRevision(r.Spec.Canary.Name, r.Namespace)
r, ok := c.getRollout(r.Name, r.Namespace)
if !ok {
return
}
func (c *Controller) setCanaryRevision(r *flaggerv1.Canary, canary *appsv1.Deployment, status string) {
r.Status = flaggerv1.CanaryStatus{
State: status,
CanaryRevision: canaryRevision,
FailedChecks: r.Status.FailedChecks,
State: status,
FailedChecks: r.Status.FailedChecks,
}
r, err := c.rolloutClient.FlaggerV1beta1().Canaries(r.Namespace).Update(r)
err := c.saveDeploymentSpec(r, canary)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
}
//c.logger.Infof("Canary %s.%s status %+v", r.Spec.Canary.Name, r.Namespace, r.Status)
}
func (c *Controller) getVirtualService(r *flaggerv1.Canary) (
@@ -345,18 +334,18 @@ func (c *Controller) getVirtualService(r *flaggerv1.Canary) (
ok bool,
) {
var err error
vs, err = c.istioClient.NetworkingV1alpha3().VirtualServices(r.Namespace).Get(r.Spec.VirtualService.Name, v1.GetOptions{})
vs, err = c.istioClient.NetworkingV1alpha3().VirtualServices(r.Namespace).Get(r.Name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "VirtualService %s.%s not found", r.Spec.VirtualService.Name, r.Namespace)
c.recordEventErrorf(r, "VirtualService %s.%s not found", r.Name, r.Namespace)
return
}
for _, http := range vs.Spec.Http {
for _, route := range http.Route {
if route.Destination.Host == r.Spec.Primary.Host {
if route.Destination.Host == fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name) {
primary = route
}
if route.Destination.Host == r.Spec.Canary.Host {
if route.Destination.Host == r.Spec.TargetRef.Name {
canary = route
}
}
@@ -364,7 +353,7 @@ func (c *Controller) getVirtualService(r *flaggerv1.Canary) (
if primary.Weight == 0 && canary.Weight == 0 {
c.recordEventErrorf(r, "VirtualService %s.%s does not contain routes for %s and %s",
r.Spec.VirtualService.Name, r.Namespace, r.Spec.Primary.Host, r.Spec.Canary.Host)
r.Name, r.Namespace, fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name), r.Spec.TargetRef.Name)
return
}
@@ -387,7 +376,7 @@ func (c *Controller) updateVirtualServiceRoutes(
var err error
vs, err = c.istioClient.NetworkingV1alpha3().VirtualServices(r.Namespace).Update(vs)
if err != nil {
c.recordEventErrorf(r, "VirtualService %s.%s update failed: %v", r.Spec.VirtualService.Name, r.Namespace, err)
c.recordEventErrorf(r, "VirtualService %s.%s update failed: %v", r.Name, r.Namespace, err)
return false
}
return true

View File

@@ -1,4 +1,4 @@
package operator
package controller
import (
"encoding/base64"
@@ -7,14 +7,14 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (c *Controller) saveDeploymentSpec(cd *flaggerv1.CanaryDeployment, dep *appsv1.Deployment) error {
func (c *Controller) saveDeploymentSpec(cd *flaggerv1.Canary, dep *appsv1.Deployment) error {
specJson, err := json.Marshal(dep.Spec.Template.Spec)
if err != nil {
return err
@@ -22,14 +22,14 @@ func (c *Controller) saveDeploymentSpec(cd *flaggerv1.CanaryDeployment, dep *app
specEnc := base64.StdEncoding.EncodeToString(specJson)
cd.Status.CanaryRevision = specEnc
cd, err = c.rolloutClient.FlaggerV1beta1().CanaryDeployments(cd.Namespace).Update(cd)
cd, err = c.rolloutClient.FlaggerV1alpha1().Canaries(cd.Namespace).Update(cd)
if err != nil {
return err
}
return nil
}
func (c *Controller) diffDeploymentSpec(cd *flaggerv1.CanaryDeployment, dep *appsv1.Deployment) (bool, error) {
func (c *Controller) diffDeploymentSpec(cd *flaggerv1.Canary, dep *appsv1.Deployment) (bool, error) {
if cd.Status.CanaryRevision == "" {
return true, nil
}

View File

@@ -1,422 +0,0 @@
package operator
import (
"fmt"
"time"
istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (c *Controller) doRollouts() {
c.rollouts.Range(func(key interface{}, value interface{}) bool {
r := value.(*flaggerv1.CanaryDeployment)
if r.Spec.TargetRef.Kind == "Deployment" {
go c.advanceDeploymentRollout(r.Name, r.Namespace)
}
return true
})
}
func (c *Controller) advanceDeploymentRollout(name string, namespace string) {
// gate stage: check if the rollout exists
r, ok := c.getRollout(name, namespace)
if !ok {
return
}
err := c.bootstrapDeployment(r)
if err != nil {
c.recordEventWarningf(r, "%v", err)
return
}
// set max weight default value to 100%
maxWeight := 100
if r.Spec.CanaryAnalysis.MaxWeight > 0 {
maxWeight = r.Spec.CanaryAnalysis.MaxWeight
}
// gate stage: check if canary deployment exists and is healthy
canary, ok := c.getCanaryDeployment(r, r.Spec.TargetRef.Name, r.Namespace)
if !ok {
return
}
// gate stage: check if primary deployment exists and is healthy
primary, ok := c.getDeployment(r, fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name), r.Namespace)
if !ok {
return
}
// gate stage: check if virtual service exists
// and if it contains weighted destination routes to the primary and canary services
vs, primaryRoute, canaryRoute, ok := c.getVirtualService(r)
if !ok {
return
}
// gate stage: check if rollout should start (canary revision has changes) or continue
if ok := c.checkRolloutStatus(r, canary); !ok {
return
}
// gate stage: check if the number of failed checks reached the threshold
if r.Status.State == "running" && r.Status.FailedChecks >= r.Spec.CanaryAnalysis.Threshold {
c.recordEventWarningf(r, "Rolling back %s.%s failed checks threshold reached %v",
r.Name, r.Namespace, r.Status.FailedChecks)
// route all traffic back to primary
primaryRoute.Weight = 100
canaryRoute.Weight = 0
if ok := c.updateVirtualServiceRoutes(r, vs, primaryRoute, canaryRoute); !ok {
return
}
c.recordEventWarningf(r, "Canary failed! Scaling down %s.%s",
canary.GetName(), canary.Namespace)
// shutdown canary
c.scaleToZeroCanary(r)
// mark rollout as failed
c.updateRolloutStatus(r, "promotion-failed")
return
}
// gate stage: check if the canary success rate is above the threshold
// skip check if no traffic is routed to canary
if canaryRoute.Weight == 0 {
c.recordEventInfof(r, "Starting canary deployment for %s.%s", r.Name, r.Namespace)
} else {
if ok := c.checkDeploymentMetrics(r); !ok {
c.updateRolloutFailedChecks(r, r.Status.FailedChecks+1)
return
}
}
// routing stage: increase canary traffic percentage
if canaryRoute.Weight < maxWeight {
primaryRoute.Weight -= r.Spec.CanaryAnalysis.StepWeight
if primaryRoute.Weight < 0 {
primaryRoute.Weight = 0
}
canaryRoute.Weight += r.Spec.CanaryAnalysis.StepWeight
if primaryRoute.Weight > 100 {
primaryRoute.Weight = 100
}
if ok := c.updateVirtualServiceRoutes(r, vs, primaryRoute, canaryRoute); !ok {
return
}
c.recordEventInfof(r, "Advance %s.%s canary weight %v", r.Name, r.Namespace, canaryRoute.Weight)
// promotion stage: override primary.template.spec with the canary spec
if canaryRoute.Weight == maxWeight {
c.recordEventInfof(r, "Copying %s.%s template spec to %s.%s",
canary.GetName(), canary.Namespace, primary.GetName(), primary.Namespace)
primary.Spec.Template.Spec = canary.Spec.Template.Spec
_, err := c.kubeClient.AppsV1().Deployments(primary.Namespace).Update(primary)
if err != nil {
c.recordEventErrorf(r, "Updating template spec %s.%s failed: %v", primary.GetName(), primary.Namespace, err)
return
}
}
} else {
// final stage: route all traffic back to primary
primaryRoute.Weight = 100
canaryRoute.Weight = 0
if ok := c.updateVirtualServiceRoutes(r, vs, primaryRoute, canaryRoute); !ok {
return
}
// final stage: mark rollout as finished and scale canary to zero replicas
c.recordEventInfof(r, "Scaling down %s.%s", canary.GetName(), canary.Namespace)
c.scaleToZeroCanary(r)
c.updateRolloutStatus(r, "promotion-finished")
}
}
func (c *Controller) getRollout(name string, namespace string) (*flaggerv1.CanaryDeployment, bool) {
r, err := c.rolloutClient.FlaggerV1beta1().CanaryDeployments(namespace).Get(name, v1.GetOptions{})
if err != nil {
c.logger.Errorf("CanaryDeployment %s.%s not found", name, namespace)
return nil, false
}
return r, true
}
func (c *Controller) checkRolloutStatus(r *flaggerv1.CanaryDeployment, canary *appsv1.Deployment) bool {
canaryRevision, err := c.getDeploymentSpecEnc(canary)
if err != nil {
c.logger.Errorf("Canary %s.%s not found: %v", r.Name, r.Namespace, err)
return false
}
if r.Status.State == "" {
r.Status = flaggerv1.CanaryDeploymentStatus{
State: "initialized",
CanaryRevision: canaryRevision,
FailedChecks: 0,
}
r, err = c.rolloutClient.FlaggerV1beta1().CanaryDeployments(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
}
c.recordEventInfof(r, "Initialization done! %s.%ss", canary.GetName(), canary.Namespace)
return false
}
if r.Status.State == "running" {
return true
}
if r.Status.State == "promotion-finished" {
c.setCanaryRevision(r, canary, "finished")
c.logger.Infof("Promotion completed! %s.%s", r.Name, r.Namespace)
return false
}
if r.Status.State == "promotion-failed" {
c.setCanaryRevision(r, canary, "failed")
c.logger.Infof("Promotion failed! %s.%s", r.Name, r.Namespace)
return false
}
if diff, err := c.diffDeploymentSpec(r, canary); diff {
c.recordEventInfof(r, "New revision detected %s.%s",
canary.GetName(), canary.Namespace)
canary.Spec.Replicas = int32p(1)
canary, err = c.kubeClient.AppsV1().Deployments(canary.Namespace).Update(canary)
if err != nil {
c.recordEventErrorf(r, "Scaling up %s.%s failed: %v", canary.GetName(), canary.Namespace, err)
return false
}
r.Status = flaggerv1.CanaryDeploymentStatus{
FailedChecks: 0,
}
c.setCanaryRevision(r, canary, "running")
c.recordEventInfof(r, "Scaling up %s.%s", canary.GetName(), canary.Namespace)
return false
}
return false
}
func (c *Controller) updateRolloutStatus(r *flaggerv1.CanaryDeployment, status string) bool {
var err error
r.Status.State = status
r, err = c.rolloutClient.FlaggerV1beta1().CanaryDeployments(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
}
return true
}
func (c *Controller) updateRolloutFailedChecks(r *flaggerv1.CanaryDeployment, val int) bool {
var err error
r.Status.FailedChecks = val
r, err = c.rolloutClient.FlaggerV1beta1().CanaryDeployments(r.Namespace).Update(r)
if err != nil {
c.logger.Errorf("Canary %s.%s status update failed: %v", r.Name, r.Namespace, err)
return false
}
return true
}
func (c *Controller) getDeployment(r *flaggerv1.CanaryDeployment, name string, namespace string) (*appsv1.Deployment, bool) {
dep, err := c.kubeClient.AppsV1().Deployments(namespace).Get(name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "Deployment %s.%s not found", name, namespace)
return nil, false
}
if msg, healthy := getDeploymentStatus(dep); !healthy {
c.recordEventWarningf(r, "Halt %s.%s advancement %s", dep.GetName(), dep.Namespace, msg)
return nil, false
}
if dep.Spec.Replicas == nil || *dep.Spec.Replicas == 0 {
return nil, false
}
return dep, true
}
func (c *Controller) getCanaryDeployment(r *flaggerv1.CanaryDeployment, name string, namespace string) (*appsv1.Deployment, bool) {
dep, err := c.kubeClient.AppsV1().Deployments(namespace).Get(name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "Deployment %s.%s not found", name, namespace)
return nil, false
}
if msg, healthy := getDeploymentStatus(dep); !healthy {
c.recordEventWarningf(r, "Halt %s.%s advancement %s", dep.GetName(), dep.Namespace, msg)
return nil, false
}
return dep, true
}
func (c *Controller) checkDeploymentMetrics(r *flaggerv1.CanaryDeployment) bool {
for _, metric := range r.Spec.CanaryAnalysis.Metrics {
if metric.Name == "istio_requests_total" {
val, err := c.getDeploymentCounter(r.Spec.TargetRef.Name, r.Namespace, metric.Name, metric.Interval)
if err != nil {
c.recordEventErrorf(r, "Metrics server %s query failed: %v", c.metricsServer, err)
return false
}
if float64(metric.Threshold) > val {
c.recordEventWarningf(r, "Halt %s.%s advancement success rate %.2f%% < %v%%",
r.Name, r.Namespace, val, metric.Threshold)
return false
}
}
if metric.Name == "istio_request_duration_seconds_bucket" {
val, err := c.GetDeploymentHistogram(r.Spec.TargetRef.Name, r.Namespace, metric.Name, metric.Interval)
if err != nil {
c.recordEventErrorf(r, "Metrics server %s query failed: %v", c.metricsServer, err)
return false
}
t := time.Duration(metric.Threshold) * time.Millisecond
if val > t {
c.recordEventWarningf(r, "Halt %s.%s advancement request duration %v > %v",
r.Name, r.Namespace, val, t)
return false
}
}
}
return true
}
func (c *Controller) scaleToZeroCanary(r *flaggerv1.CanaryDeployment) {
canary, err := c.kubeClient.AppsV1().Deployments(r.Namespace).Get(r.Spec.TargetRef.Name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "Deployment %s.%s not found", r.Spec.TargetRef.Name, r.Namespace)
return
}
//HPA https://github.com/kubernetes/kubernetes/pull/29212
canary.Spec.Replicas = int32p(0)
canary, err = c.kubeClient.AppsV1().Deployments(canary.Namespace).Update(canary)
if err != nil {
c.recordEventErrorf(r, "Scaling down %s.%s failed: %v", canary.GetName(), canary.Namespace, err)
return
}
}
func (c *Controller) setCanaryRevision(r *flaggerv1.CanaryDeployment, canary *appsv1.Deployment, status string) {
r.Status = flaggerv1.CanaryDeploymentStatus{
State: status,
FailedChecks: r.Status.FailedChecks,
}
err := c.saveDeploymentSpec(r, canary)
if err != nil {
c.logger.Errorf("CanaryDeployment %s.%s status update failed: %v", r.Name, r.Namespace, err)
}
}
func (c *Controller) getVirtualService(r *flaggerv1.CanaryDeployment) (
vs *istiov1alpha3.VirtualService,
primary istiov1alpha3.DestinationWeight,
canary istiov1alpha3.DestinationWeight,
ok bool,
) {
var err error
vs, err = c.istioClient.NetworkingV1alpha3().VirtualServices(r.Namespace).Get(r.Name, v1.GetOptions{})
if err != nil {
c.recordEventErrorf(r, "VirtualService %s.%s not found", r.Name, r.Namespace)
return
}
for _, http := range vs.Spec.Http {
for _, route := range http.Route {
if route.Destination.Host == fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name) {
primary = route
}
if route.Destination.Host == r.Spec.TargetRef.Name {
canary = route
}
}
}
if primary.Weight == 0 && canary.Weight == 0 {
c.recordEventErrorf(r, "VirtualService %s.%s does not contain routes for %s and %s",
r.Name, r.Namespace, fmt.Sprintf("%s-primary", r.Spec.TargetRef.Name), r.Spec.TargetRef.Name)
return
}
ok = true
return
}
func (c *Controller) updateVirtualServiceRoutes(
r *flaggerv1.CanaryDeployment,
vs *istiov1alpha3.VirtualService,
primary istiov1alpha3.DestinationWeight,
canary istiov1alpha3.DestinationWeight,
) bool {
vs.Spec.Http = []istiov1alpha3.HTTPRoute{
{
Route: []istiov1alpha3.DestinationWeight{primary, canary},
},
}
var err error
vs, err = c.istioClient.NetworkingV1alpha3().VirtualServices(r.Namespace).Update(vs)
if err != nil {
c.recordEventErrorf(r, "VirtualService %s.%s update failed: %v", r.Name, r.Namespace, err)
return false
}
return true
}
func getDeploymentStatus(deployment *appsv1.Deployment) (string, bool) {
if deployment.Generation <= deployment.Status.ObservedGeneration {
cond := getDeploymentCondition(deployment.Status, appsv1.DeploymentProgressing)
if cond != nil && cond.Reason == "ProgressDeadlineExceeded" {
return fmt.Sprintf("deployment %q exceeded its progress deadline", deployment.GetName()), false
} else if deployment.Spec.Replicas != nil && deployment.Status.UpdatedReplicas < *deployment.Spec.Replicas {
return fmt.Sprintf("waiting for rollout to finish: %d out of %d new replicas have been updated",
deployment.Status.UpdatedReplicas, *deployment.Spec.Replicas), false
} else if deployment.Status.Replicas > deployment.Status.UpdatedReplicas {
return fmt.Sprintf("waiting for rollout to finish: %d old replicas are pending termination",
deployment.Status.Replicas-deployment.Status.UpdatedReplicas), false
} else if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas {
return fmt.Sprintf("waiting for rollout to finish: %d of %d updated replicas are available",
deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas), false
}
} else {
return "waiting for rollout to finish: observed deployment generation less then desired generation", false
}
return "ready", true
}
func getDeploymentCondition(
status appsv1.DeploymentStatus,
conditionType appsv1.DeploymentConditionType,
) *appsv1.DeploymentCondition {
for i := range status.Conditions {
c := status.Conditions[i]
if c.Type == conditionType {
return &c
}
}
return nil
}
func int32p(i int32) *int32 {
return &i
}

View File

@@ -1,172 +0,0 @@
package operator
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"time"
)
type VectorQueryResponse struct {
Data struct {
Result []struct {
Metric struct {
Code string `json:"response_code"`
Name string `json:"destination_workload"`
}
Value []interface{} `json:"value"`
}
}
}
func (c *Controller) queryMetric(query string) (*VectorQueryResponse, error) {
promURL, err := url.Parse(c.metricsServer)
if err != nil {
return nil, err
}
u, err := url.Parse(fmt.Sprintf("./api/v1/query?query=%s", query))
if err != nil {
return nil, err
}
u = promURL.ResolveReference(u)
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
defer cancel()
r, err := http.DefaultClient.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}
defer r.Body.Close()
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, fmt.Errorf("error reading body: %s", err.Error())
}
if 400 <= r.StatusCode {
return nil, fmt.Errorf("error response: %s", string(b))
}
var values VectorQueryResponse
err = json.Unmarshal(b, &values)
if err != nil {
return nil, fmt.Errorf("error unmarshaling result: %s, '%s'", err.Error(), string(b))
}
return &values, nil
}
// istio_requests_total
func (c *Controller) getDeploymentCounter(name string, namespace string, metric string, interval string) (float64, error) {
var rate *float64
querySt := url.QueryEscape(`sum(rate(` +
metric + `{reporter="destination",destination_workload_namespace=~"` +
namespace + `",destination_workload=~"` +
name + `",response_code!~"5.*"}[1m])) / sum(rate(` +
metric + `{reporter="destination",destination_workload_namespace=~"` +
namespace + `",destination_workload=~"` +
name + `"}[` +
interval + `])) * 100 `)
result, err := c.queryMetric(querySt)
if err != nil {
return 0, err
}
for _, v := range result.Data.Result {
metricValue := v.Value[1]
switch metricValue.(type) {
case string:
f, err := strconv.ParseFloat(metricValue.(string), 64)
if err != nil {
return 0, err
}
rate = &f
}
}
if rate == nil {
return 0, fmt.Errorf("no values found for metric %s", metric)
}
return *rate, nil
}
// istio_request_duration_seconds_bucket
func (c *Controller) GetDeploymentHistogram(name string, namespace string, metric string, interval string) (time.Duration, error) {
var rate *float64
querySt := url.QueryEscape(`histogram_quantile(0.99, sum(rate(` +
metric + `{reporter="destination",destination_workload=~"` +
name + `", destination_workload_namespace=~"` +
namespace + `"}[` +
interval + `])) by (le))`)
result, err := c.queryMetric(querySt)
if err != nil {
return 0, err
}
for _, v := range result.Data.Result {
metricValue := v.Value[1]
switch metricValue.(type) {
case string:
f, err := strconv.ParseFloat(metricValue.(string), 64)
if err != nil {
return 0, err
}
rate = &f
}
}
if rate == nil {
return 0, fmt.Errorf("no values found for metric %s", metric)
}
ms := time.Duration(int64(*rate*1000)) * time.Millisecond
return ms, nil
}
func CheckMetricsServer(address string) (bool, error) {
promURL, err := url.Parse(address)
if err != nil {
return false, err
}
u, err := url.Parse("./api/v1/status/flags")
if err != nil {
return false, err
}
u = promURL.ResolveReference(u)
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return false, err
}
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
defer cancel()
r, err := http.DefaultClient.Do(req.WithContext(ctx))
if err != nil {
return false, err
}
defer r.Body.Close()
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return false, fmt.Errorf("error reading body: %s", err.Error())
}
if 400 <= r.StatusCode {
return false, fmt.Errorf("error response: %s", string(b))
}
return true, nil
}

View File

@@ -1,229 +0,0 @@
package operator
import (
"fmt"
"sync"
"time"
"github.com/google/go-cmp/cmp"
istioclientset "github.com/knative/pkg/client/clientset/versioned"
flaggerv1 "github.com/stefanprodan/flagger/pkg/apis/flagger/v1beta1"
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/v1beta1"
flaggerlisters "github.com/stefanprodan/flagger/pkg/client/listers/flagger/v1beta1"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
)
const controllerAgentName = "flagger"
type Controller struct {
kubeClient kubernetes.Interface
istioClient istioclientset.Interface
rolloutClient clientset.Interface
rolloutLister flaggerlisters.CanaryDeploymentLister
rolloutSynced cache.InformerSynced
rolloutWindow time.Duration
workqueue workqueue.RateLimitingInterface
recorder record.EventRecorder
logger *zap.SugaredLogger
metricsServer string
rollouts *sync.Map
}
func NewController(
kubeClient kubernetes.Interface,
istioClient istioclientset.Interface,
rolloutClient clientset.Interface,
rolloutInformer flaggerinformers.CanaryDeploymentInformer,
rolloutWindow time.Duration,
metricServer string,
logger *zap.SugaredLogger,
) *Controller {
logger.Debug("Creating event broadcaster")
flaggerscheme.AddToScheme(scheme.Scheme)
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Debugf)
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{
Interface: kubeClient.CoreV1().Events(""),
})
recorder := eventBroadcaster.NewRecorder(
scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
ctrl := &Controller{
kubeClient: kubeClient,
istioClient: istioClient,
rolloutClient: rolloutClient,
rolloutLister: rolloutInformer.Lister(),
rolloutSynced: rolloutInformer.Informer().HasSynced,
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), controllerAgentName),
recorder: recorder,
logger: logger,
rollouts: new(sync.Map),
metricsServer: metricServer,
rolloutWindow: rolloutWindow,
}
rolloutInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: ctrl.enqueue,
UpdateFunc: func(old, new interface{}) {
oldRoll, ok := checkCustomResourceType(old, logger)
if !ok {
return
}
newRoll, ok := checkCustomResourceType(new, logger)
if !ok {
return
}
if diff := cmp.Diff(newRoll.Spec, oldRoll.Spec); diff != "" {
ctrl.logger.Debugf("Diff detected %s.%s %s", oldRoll.Name, oldRoll.Namespace, diff)
ctrl.enqueue(new)
}
},
DeleteFunc: func(old interface{}) {
r, ok := checkCustomResourceType(old, logger)
if ok {
ctrl.logger.Infof("Deleting %s.%s from cache", r.Name, r.Namespace)
ctrl.rollouts.Delete(fmt.Sprintf("%s.%s", r.Name, r.Namespace))
}
},
})
return ctrl
}
func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
c.logger.Info("Starting operator")
for i := 0; i < threadiness; i++ {
go wait.Until(func() {
for c.processNextWorkItem() {
}
}, time.Second, stopCh)
}
c.logger.Info("Started operator workers")
tickChan := time.NewTicker(c.rolloutWindow).C
for {
select {
case <-tickChan:
c.doRollouts()
case <-stopCh:
c.logger.Info("Shutting down operator workers")
return nil
}
}
return nil
}
func (c *Controller) processNextWorkItem() bool {
obj, shutdown := c.workqueue.Get()
if shutdown {
return false
}
err := func(obj interface{}) error {
defer c.workqueue.Done(obj)
var key string
var ok bool
if key, ok = obj.(string); !ok {
c.workqueue.Forget(obj)
utilruntime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj))
return nil
}
// Run the syncHandler, passing it the namespace/name string of the
// Foo resource to be synced.
if err := c.syncHandler(key); err != nil {
return fmt.Errorf("error syncing '%s': %s", key, err.Error())
}
// Finally, if no error occurs we Forget this item so it does not
// get queued again until another change happens.
c.workqueue.Forget(obj)
return nil
}(obj)
if err != nil {
utilruntime.HandleError(err)
return true
}
return true
}
func (c *Controller) syncHandler(key string) error {
namespace, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", key))
return nil
}
cd, err := c.rolloutLister.CanaryDeployments(namespace).Get(name)
if errors.IsNotFound(err) {
utilruntime.HandleError(fmt.Errorf("'%s' in work queue no longer exists", key))
return nil
}
c.rollouts.Store(fmt.Sprintf("%s.%s", cd.Name, cd.Namespace), cd)
err = c.bootstrapDeployment(cd)
if err != nil {
c.logger.Warnf("%s.%s bootstrap error %v", cd.Name, cd.Namespace, err)
return err
}
c.logger.Infof("Synced %s", key)
return nil
}
func (c *Controller) enqueue(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
utilruntime.HandleError(err)
return
}
c.workqueue.AddRateLimited(key)
}
func checkCustomResourceType(obj interface{}, logger *zap.SugaredLogger) (flaggerv1.CanaryDeployment, bool) {
var roll *flaggerv1.CanaryDeployment
var ok bool
if roll, ok = obj.(*flaggerv1.CanaryDeployment); !ok {
logger.Errorf("Event Watch received an invalid object: %#v", obj)
return flaggerv1.CanaryDeployment{}, false
}
return *roll, true
}
func (c *Controller) recordEventInfof(r *flaggerv1.CanaryDeployment, template string, args ...interface{}) {
c.logger.Infof(template, args...)
c.recorder.Event(r, corev1.EventTypeNormal, "Synced", fmt.Sprintf(template, args...))
}
func (c *Controller) recordEventErrorf(r *flaggerv1.CanaryDeployment, template string, args ...interface{}) {
c.logger.Errorf(template, args...)
c.recorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
}
func (c *Controller) recordEventWarningf(r *flaggerv1.CanaryDeployment, template string, args ...interface{}) {
c.logger.Infof(template, args...)
c.recorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
}