From 7a08b263d6e3c935edf401f661fade421ab670c4 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 11 Oct 2022 10:44:26 +0100 Subject: [PATCH 01/11] fix for reflector warning temporarily Signed-off-by: Alex Jones --- go.mod | 2 ++ go.sum | 1 + pkg/sync/kubernetes/featureflagconfiguration/clientset.go | 1 + 3 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index a4aea8c44..bf15c931c 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/open-feature/flagd go 1.18 +replace k8s.io/client-go@v0.25.2 => k8s.io/client-go v0.0.0-20221010195331-f515a4cb9fa9 + require ( github.com/bufbuild/connect-go v0.5.0 github.com/deepmap/oapi-codegen v1.11.0 diff --git a/go.sum b/go.sum index 605ff8d1d..e22907611 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,7 @@ github.com/bufbuild/connect-go v0.5.0 h1:JFbWPWpasBqzM5h/awoRhAXmLERZQlQ5xTn42uf github.com/bufbuild/connect-go v0.5.0/go.mod h1:ZEtBnQ7J/m7bvWOW+H8T/+hKQCzPVfhhhICuvtcnjlI= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/pkg/sync/kubernetes/featureflagconfiguration/clientset.go b/pkg/sync/kubernetes/featureflagconfiguration/clientset.go index 19636d5b7..5707a64a2 100644 --- a/pkg/sync/kubernetes/featureflagconfiguration/clientset.go +++ b/pkg/sync/kubernetes/featureflagconfiguration/clientset.go @@ -43,6 +43,7 @@ func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.I } func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { + if reflect.TypeOf(oldObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { return errors.New("old object is not a FeatureFlagConfiguration") } From 311c9e106a7c987b1af440afb4b0126c59be6eaf Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 11 Oct 2022 19:50:45 +0100 Subject: [PATCH 02/11] fixing the issue with warnings from the notifier, with a simpler impl Signed-off-by: Alex Jones --- .../featureflagconfiguration/clientset.go | 150 ------------------ .../featureflagconfiguration.go | 77 --------- pkg/sync/kubernetes/kubernetes_sync.go | 119 +++++++++++--- 3 files changed, 96 insertions(+), 250 deletions(-) delete mode 100644 pkg/sync/kubernetes/featureflagconfiguration/clientset.go delete mode 100644 pkg/sync/kubernetes/featureflagconfiguration/featureflagconfiguration.go diff --git a/pkg/sync/kubernetes/featureflagconfiguration/clientset.go b/pkg/sync/kubernetes/featureflagconfiguration/clientset.go deleted file mode 100644 index 5707a64a2..000000000 --- a/pkg/sync/kubernetes/featureflagconfiguration/clientset.go +++ /dev/null @@ -1,150 +0,0 @@ -package featureflagconfiguration - -import ( - "context" - "errors" - "reflect" - "time" - - "github.com/open-feature/flagd/pkg/sync" - ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type FFCInterface interface { - FeatureFlagConfigurations(namespace string) Interface -} - -type FFCClient struct { - restClient rest.Interface -} - -func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("object is not a FeatureFlagConfiguration") - } - if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { - c <- &sync.Notifier{ - Event: sync.Event[sync.DefaultEventType]{ - EventType: sync.DefaultEventTypeCreate, - }, - } - } - return nil -} - -func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - - if reflect.TypeOf(oldObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("old object is not a FeatureFlagConfiguration") - } - if reflect.TypeOf(newObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("new object is not a FeatureFlagConfiguration") - } - oldObjConfig := oldObj.(*ffv1alpha1.FeatureFlagConfiguration) - newObjConfig := newObj.(*ffv1alpha1.FeatureFlagConfiguration) - if object.Name == newObjConfig.Name && oldObjConfig.ResourceVersion != newObjConfig.ResourceVersion { - // Only update if there is an actual featureFlagSpec change - c <- &sync.Notifier{ - Event: sync.Event[sync.DefaultEventType]{ - EventType: sync.DefaultEventTypeModify, - }, - } - } - return nil -} - -func deleteFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("object is not a FeatureFlagConfiguration") - } - if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { - c <- &sync.Notifier{ - Event: sync.Event[sync.DefaultEventType]{ - EventType: sync.DefaultEventTypeDelete, - }, - } - } - return nil -} - -// WatchResources watches FeatureFlagConfigurations resources under the given namespace with the given name -// -// - resyncPeriod if non-zero, will re-list the resources this often (you will get OnUpdate -// calls, even if nothing changed). Otherwise, re-list will be delayed as long as possible -// (until the upstream source closes the watch or times out, or you stop the controller). -func WatchResources(ctx context.Context, l log.Entry, clientSet FFCInterface, resyncPeriod time.Duration, - object client.ObjectKey, c chan<- sync.INotify, -) { - ns := "*" - if object.Namespace != "" { - ns = object.Namespace - } - _, ffConfigController := cache.NewInformer( - &cache.ListWatch{ - ListFunc: func(lo metav1.ListOptions) (result runtime.Object, err error) { - return clientSet.FeatureFlagConfigurations(ns).List(lo) - }, - WatchFunc: func(lo metav1.ListOptions) (watch.Interface, error) { - return clientSet.FeatureFlagConfigurations(ns).Watch(lo) - }, - }, - &ffv1alpha1.FeatureFlagConfiguration{}, - resyncPeriod, - cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - if err := createFuncHandler(obj, object, c); err != nil { - l.Warn(err.Error()) - } - }, - DeleteFunc: func(obj interface{}) { - if err := deleteFuncHandler(obj, object, c); err != nil { - l.Warn(err.Error()) - } - }, - UpdateFunc: func(oldObj, newObj interface{}) { - // This indicates a change to the custom resource - if err := updateFuncHandler(oldObj, newObj, object, c); err != nil { - l.Warn(err.Error()) - } - }, - }, - ) - go ffConfigController.Run(ctx.Done()) -} - -func NewForConfig(config *rest.Config) (*FFCClient, error) { - if config == nil { - return nil, errors.New("rest config is nil") - } - config.ContentConfig.GroupVersion = &schema. - GroupVersion{ - Group: ffv1alpha1.GroupVersion.Group, - Version: ffv1alpha1.GroupVersion.Version, - } - config.APIPath = "/apis" - config.UserAgent = rest.DefaultKubernetesUserAgent() - config.NegotiatedSerializer = serializer.NewCodecFactory(scheme.Scheme) - client, err := rest.RESTClientFor(config) - if err != nil { - return nil, err - } - - return &FFCClient{restClient: client}, nil -} - -func (c *FFCClient) FeatureFlagConfigurations(namespace string) Interface { - return &FeatureFlagClient{ - restClient: c.restClient, - ns: namespace, - } -} diff --git a/pkg/sync/kubernetes/featureflagconfiguration/featureflagconfiguration.go b/pkg/sync/kubernetes/featureflagconfiguration/featureflagconfiguration.go deleted file mode 100644 index 21ac0d3a9..000000000 --- a/pkg/sync/kubernetes/featureflagconfiguration/featureflagconfiguration.go +++ /dev/null @@ -1,77 +0,0 @@ -package featureflagconfiguration - -import ( - "context" - - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" -) - -const ( - featureFlagConfigurationName = "featureflagconfigurations" -) - -type Interface interface { - List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) - Get(name string, options metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) - Create(*v1alpha1.FeatureFlagConfiguration) (*v1alpha1.FeatureFlagConfiguration, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) -} - -type FeatureFlagClient struct { - restClient rest.Interface - ns string -} - -func (c *FeatureFlagClient) List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) { - result := v1alpha1.FeatureFlagConfigurationList{} - err := c.restClient. - Get(). - Resource(featureFlagConfigurationName). - Do(context.Background()). - Into(&result) - - return &result, err -} - -func (c *FeatureFlagClient) Get(name string, opts metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) { - result := v1alpha1.FeatureFlagConfiguration{} - err := c.restClient. - Get(). - Namespace(c.ns). - Resource(featureFlagConfigurationName). - Name(name). - VersionedParams(&opts, scheme.ParameterCodec). - Do(context.Background()). - Into(&result) - - return &result, err -} - -func (c *FeatureFlagClient) Create(project *v1alpha1.FeatureFlagConfiguration) (*v1alpha1. - FeatureFlagConfiguration, error, -) { - result := v1alpha1.FeatureFlagConfiguration{} - err := c.restClient. - Post(). - Namespace(c.ns). - Resource(featureFlagConfigurationName). - Body(project). - Do(context.Background()). - Into(&result) - - return &result, err -} - -func (c *FeatureFlagClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.restClient. - Get(). - Namespace(c.ns). - Resource(featureFlagConfigurationName). - VersionedParams(&opts, scheme.ParameterCodec). - Watch(context.Background()) -} diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index ade18b9ce..881c4fb29 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -2,17 +2,24 @@ package kubernetes import ( "context" + "errors" "os" + "os/signal" + "reflect" "time" "github.com/open-feature/flagd/pkg/sync" "github.com/open-feature/flagd/pkg/sync/kubernetes/featureflagconfiguration" ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" - controllerClient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -74,34 +81,100 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { k.Logger.Infof("Starting kubernetes sync notifier for resource %s", k.ProviderArgs["featureflagconfiguration"]) kubeconfig := os.Getenv("KUBECONFIG") - // Create the client configuration - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - k.Logger.Panic(err.Error()) + var clusterConfig *rest.Config + var err error + if kubeconfig != "" { + clusterConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + } else { + clusterConfig, err = rest.InClusterConfig() } - - if k.ProviderArgs["resyncperiod"] != "" { - hr, err := time.ParseDuration(k.ProviderArgs["resyncperiod"]) - if err != nil { - k.Logger.Panic(err.Error()) - } - resyncPeriod = hr + if err != nil { + log.Fatalln(err) } - k.client, err = featureflagconfiguration.NewForConfig(config) + clusterClient, err := dynamic.NewForConfig(clusterConfig) if err != nil { - k.Logger.Panic(err.Error()) + log.Fatalln(err) } - if err := ffv1alpha1.AddToScheme(scheme.Scheme); err != nil { - k.Logger.Panic(err.Error()) - } + resource := ffv1alpha1.GroupVersion.WithResource("featureflagconfigurations") + factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient, time.Minute, corev1.NamespaceAll, nil) + informer := factory.ForResource(resource).Informer() - go featureflagconfiguration.WatchResources(ctx, *k.Logger.WithFields(log.Fields{ - "sync": "kubernetes", - "component": "watchresources", - }), k.client, resyncPeriod, controllerClient.ObjectKey{ + objectKey := client.ObjectKey{ Name: k.ProviderArgs[featureFlagConfigurationName], Namespace: k.ProviderArgs[featureFlagNamespaceName], - }, c) + } + informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + if err := createFuncHandler(obj, objectKey, c); err != nil { + k.Logger.Warn(err.Error()) + } + }, + UpdateFunc: func(oldObj, newObj interface{}) { + if err := updateFuncHandler(oldObj, newObj, objectKey, c); err != nil { + k.Logger.Warn(err.Error()) + } + }, + DeleteFunc: func(obj interface{}) { + if err := deleteFuncHandler(obj, objectKey, c); err != nil { + k.Logger.Warn(err.Error()) + } + }, + }) + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + + informer.Run(ctx.Done()) + +} + +func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { + if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + return errors.New("object is not a FeatureFlagConfiguration") + } + if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { + c <- &sync.Notifier{ + Event: sync.Event[sync.DefaultEventType]{ + EventType: sync.DefaultEventTypeCreate, + }, + } + } + return nil +} + +func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { + + if reflect.TypeOf(oldObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + return errors.New("old object is not a FeatureFlagConfiguration") + } + if reflect.TypeOf(newObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + return errors.New("new object is not a FeatureFlagConfiguration") + } + oldObjConfig := oldObj.(*ffv1alpha1.FeatureFlagConfiguration) + newObjConfig := newObj.(*ffv1alpha1.FeatureFlagConfiguration) + if object.Name == newObjConfig.Name && oldObjConfig.ResourceVersion != newObjConfig.ResourceVersion { + // Only update if there is an actual featureFlagSpec change + c <- &sync.Notifier{ + Event: sync.Event[sync.DefaultEventType]{ + EventType: sync.DefaultEventTypeModify, + }, + } + } + return nil +} + +func deleteFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { + if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + return errors.New("object is not a FeatureFlagConfiguration") + } + if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { + c <- &sync.Notifier{ + Event: sync.Event[sync.DefaultEventType]{ + EventType: sync.DefaultEventTypeDelete, + }, + } + } + return nil } From 57cf43cc03f8b4006bcee017f472e3dd554067a3 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 11 Oct 2022 20:00:40 +0100 Subject: [PATCH 03/11] fixing the issue with warnings from the notifier, with a simpler impl Signed-off-by: Alex Jones --- go.mod | 2 - pkg/sync/kubernetes/kubernetes_sync.go | 79 +++++++++++++++++--------- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index bf15c931c..a4aea8c44 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/open-feature/flagd go 1.18 -replace k8s.io/client-go@v0.25.2 => k8s.io/client-go v0.0.0-20221010195331-f515a4cb9fa9 - require ( github.com/bufbuild/connect-go v0.5.0 github.com/deepmap/oapi-codegen v1.11.0 diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index 881c4fb29..26214220a 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -9,11 +9,11 @@ import ( "time" "github.com/open-feature/flagd/pkg/sync" - "github.com/open-feature/flagd/pkg/sync/kubernetes/featureflagconfiguration" ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/rest" @@ -32,7 +32,6 @@ var resyncPeriod time.Duration // default of 0 type Sync struct { Logger *log.Entry ProviderArgs sync.ProviderArgs - client *featureflagconfiguration.FFCClient } func (k *Sync) Source() string { @@ -50,23 +49,23 @@ func (k *Sync) Fetch(ctx context.Context) (string, error) { return "{}", nil } - if k.client == nil { - k.Logger.Warn("Client not initialised") - return "{}", nil - } + // if k.client == nil { + // k.Logger.Warn("Client not initialised") + // return "{}", nil + // } - config, err := k.client.FeatureFlagConfigurations(k.ProviderArgs[featureFlagNamespaceName]). - Get(k.ProviderArgs[featureFlagConfigurationName], metav1.GetOptions{ - TypeMeta: metav1.TypeMeta{ - Kind: "FeatureFlagConfiguration", - APIVersion: "featureflag.open-feature.io/v1alpha1", - }, - }) - if err != nil { - return "{}", err - } + // config, err := k.client.FeatureFlagConfigurations(k.ProviderArgs[featureFlagNamespaceName]). + // Get(k.ProviderArgs[featureFlagConfigurationName], metav1.GetOptions{ + // TypeMeta: metav1.TypeMeta{ + // Kind: "FeatureFlagConfiguration", + // APIVersion: "featureflag.open-feature.io/v1alpha1", + // }, + // }) + // if err != nil { + // return "{}", err + // } - return config.Spec.FeatureFlagSpec, nil + return "{}", nil } func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { @@ -131,10 +130,17 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { } func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + + var ffObj ffv1alpha1.FeatureFlagConfiguration + u := obj.(*unstructured.Unstructured) + err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffObj) + if err != nil { + return err + } + if reflect.TypeOf(ffObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { return errors.New("object is not a FeatureFlagConfiguration") } - if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { + if ffObj.Name == object.Name { c <- &sync.Notifier{ Event: sync.Event[sync.DefaultEventType]{ EventType: sync.DefaultEventTypeCreate, @@ -146,15 +152,26 @@ func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.I func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - if reflect.TypeOf(oldObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("old object is not a FeatureFlagConfiguration") + var ffOldObj ffv1alpha1.FeatureFlagConfiguration + u := oldObj.(*unstructured.Unstructured) + err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffOldObj) + if err != nil { + return err + } + if reflect.TypeOf(ffOldObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { + return errors.New("object is not a FeatureFlagConfiguration") + } + var ffNewObj ffv1alpha1.FeatureFlagConfiguration + u = newObj.(*unstructured.Unstructured) + err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffNewObj) + if err != nil { + return err } - if reflect.TypeOf(newObj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + if reflect.TypeOf(newObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { return errors.New("new object is not a FeatureFlagConfiguration") } - oldObjConfig := oldObj.(*ffv1alpha1.FeatureFlagConfiguration) - newObjConfig := newObj.(*ffv1alpha1.FeatureFlagConfiguration) - if object.Name == newObjConfig.Name && oldObjConfig.ResourceVersion != newObjConfig.ResourceVersion { + + if object.Name == ffNewObj.Name && ffOldObj.ResourceVersion != ffNewObj.ResourceVersion { // Only update if there is an actual featureFlagSpec change c <- &sync.Notifier{ Event: sync.Event[sync.DefaultEventType]{ @@ -166,10 +183,16 @@ func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.Obj } func deleteFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - if reflect.TypeOf(obj) != reflect.TypeOf(&ffv1alpha1.FeatureFlagConfiguration{}) { + var ffObj ffv1alpha1.FeatureFlagConfiguration + u := obj.(*unstructured.Unstructured) + err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffObj) + if err != nil { + return err + } + if reflect.TypeOf(ffObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { return errors.New("object is not a FeatureFlagConfiguration") } - if obj.(*ffv1alpha1.FeatureFlagConfiguration).Name == object.Name { + if ffObj.Name == object.Name { c <- &sync.Notifier{ Event: sync.Event[sync.DefaultEventType]{ EventType: sync.DefaultEventTypeDelete, From 640ff91253eba2d630c5aa026616e3b1d610a17c Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 11 Oct 2022 20:25:31 +0100 Subject: [PATCH 04/11] fixed the get Signed-off-by: Alex Jones --- 1 | 67 +++++++++++++++ pkg/sync/kubernetes/ffclientset.go | 112 +++++++++++++++++++++++++ pkg/sync/kubernetes/kubernetes_sync.go | 40 +++++---- 3 files changed, 202 insertions(+), 17 deletions(-) create mode 100644 1 create mode 100644 pkg/sync/kubernetes/ffclientset.go diff --git a/1 b/1 new file mode 100644 index 000000000..4dc523196 --- /dev/null +++ b/1 @@ -0,0 +1,67 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: core.openfeature.dev/v1alpha1 +kind: FeatureFlagConfiguration +metadata: + annotations: + foo: bar2 + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"core.openfeature.dev/v1alpha1","kind":"FeatureFlagConfiguration","metadata":{"annotations":{},"name":"end-to-end","namespace":"default"},"spec":{"featureFlagSpec":"{\n \"flags\": {\n \"new-welcome-message\": {\n \"state\": \"ENABLED\",\n \"variants\": {\n \"on\": true,\n \"off\": false\n },\n \"defaultVariant\": \"on\"\n },\n \"hex-color\": {\n \"variants\": {\n \"red\": \"CC0000\",\n \"green\": \"00CC00\",\n \"blue\": \"0000CC\",\n \"yellow\": \"yellow\"\n },\n \"defaultVariant\": \"red\",\n \"state\": \"ENABLED\"\n },\n \"fib-algo\": {\n \"variants\": {\n \"recursive\": \"recursive\",\n \"memo\": \"memo\",\n \"loop\": \"loop\",\n \"binet\": \"binet\"\n },\n \"defaultVariant\": \"recursive\",\n \"state\": \"ENABLED\",\n \"targeting\": {\n \"if\": [\n {\n \"in\": [\"@faas.com\", {\n \"var\": [\"email\"]\n }]\n }, \"binet\", null\n ]\n }\n }\n }\n}\n"}} + creationTimestamp: "2022-10-04T13:21:39Z" + finalizers: + - featureflagconfiguration.core.openfeature.dev/finalizer + generation: 5 + name: end-to-end + namespace: default + resourceVersion: "2301482" + uid: b5f57e47-9093-4300-a6f3-21cfa1c4cba6 +spec: + featureFlagSpec: | + { + "flags": { + "new-welcome-message": { + "state": "ENABLED", + "variants": { + "on": true, + "off": false + }, + "defaultVariant": "on" + }, + "hex-color": { + "variants": { + "red": "CC0000", + "green": "00CC00", + "blue": "0000CC", + "yellow": "yellow" + }, + "defaultVariant": "green", + "state": "ENABLED" + }, + "fib-algo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "targeting": { + "if": [ + { + "in": ["@faas.com", { + "var": ["email"] + }] + }, "binet", null + ] + } + } + } + } + flagDSpec: null + serviceProvider: + credentials: null + name: flagd + syncProvider: null diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go new file mode 100644 index 000000000..9441f67b3 --- /dev/null +++ b/pkg/sync/kubernetes/ffclientset.go @@ -0,0 +1,112 @@ +package kubernetes + +import ( + "context" + "errors" + + "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" + ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" +) + +type Interface interface { + List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) + Get(name string, options metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) + Create(*v1alpha1.FeatureFlagConfiguration) (*v1alpha1.FeatureFlagConfiguration, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) +} + +type FeatureFlagClient struct { + restClient rest.Interface + ns string +} + +type FFCInterface interface { + FeatureFlagConfigurations(namespace string) Interface +} + +type FFCClient struct { + restClient rest.Interface +} + +func (c *FeatureFlagClient) List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) { + result := v1alpha1.FeatureFlagConfigurationList{} + err := c.restClient. + Get(). + Resource(featureFlagConfigurationName). + Do(context.Background()). + Into(&result) + + return &result, err +} + +func (c *FeatureFlagClient) Get(name string, opts metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) { + result := v1alpha1.FeatureFlagConfiguration{} + err := c.restClient. + Get(). + Namespace(c.ns). + Resource(featureFlagConfigurationName). + Name(name). + VersionedParams(&opts, scheme.ParameterCodec). + Do(context.Background()). + Into(&result) + + return &result, err +} + +func (c *FeatureFlagClient) Create(project *v1alpha1.FeatureFlagConfiguration) (*v1alpha1. + FeatureFlagConfiguration, error, +) { + result := v1alpha1.FeatureFlagConfiguration{} + err := c.restClient. + Post(). + Namespace(c.ns). + Resource(featureFlagConfigurationName). + Body(project). + Do(context.Background()). + Into(&result) + + return &result, err +} + +func (c *FeatureFlagClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.restClient. + Get(). + Namespace(c.ns). + Resource(featureFlagConfigurationName). + VersionedParams(&opts, scheme.ParameterCodec). + Watch(context.Background()) +} + +func NewForConfig(config *rest.Config) (*FFCClient, error) { + if config == nil { + return nil, errors.New("rest config is nil") + } + config.ContentConfig.GroupVersion = &schema. + GroupVersion{ + Group: ffv1alpha1.GroupVersion.Group, + Version: ffv1alpha1.GroupVersion.Version, + } + config.APIPath = "/apis" + config.UserAgent = rest.DefaultKubernetesUserAgent() + config.NegotiatedSerializer = serializer.NewCodecFactory(scheme.Scheme) + client, err := rest.RESTClientFor(config) + if err != nil { + return nil, err + } + + return &FFCClient{restClient: client}, nil +} + +func (c *FFCClient) FeatureFlagConfigurations(namespace string) Interface { + return &FeatureFlagClient{ + restClient: c.restClient, + ns: namespace, + } +} diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index 26214220a..0dfd71e2a 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -16,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" @@ -32,6 +33,7 @@ var resyncPeriod time.Duration // default of 0 type Sync struct { Logger *log.Entry ProviderArgs sync.ProviderArgs + client client.Client } func (k *Sync) Source() string { @@ -49,23 +51,18 @@ func (k *Sync) Fetch(ctx context.Context) (string, error) { return "{}", nil } - // if k.client == nil { - // k.Logger.Warn("Client not initialised") - // return "{}", nil - // } + if k.client == nil { + k.Logger.Warn("Client not initialised") + return "{}", nil + } - // config, err := k.client.FeatureFlagConfigurations(k.ProviderArgs[featureFlagNamespaceName]). - // Get(k.ProviderArgs[featureFlagConfigurationName], metav1.GetOptions{ - // TypeMeta: metav1.TypeMeta{ - // Kind: "FeatureFlagConfiguration", - // APIVersion: "featureflag.open-feature.io/v1alpha1", - // }, - // }) - // if err != nil { - // return "{}", err - // } + var ff ffv1alpha1.FeatureFlagConfiguration + err := k.client.Get(ctx, client.ObjectKey{ + Name: k.ProviderArgs[featureFlagConfigurationName], + Namespace: k.ProviderArgs[featureFlagNamespaceName], + }, &ff) - return "{}", nil + return ff.Spec.FeatureFlagSpec, err } func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { @@ -88,7 +85,16 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { clusterConfig, err = rest.InClusterConfig() } if err != nil { - log.Fatalln(err) + k.Logger.Fatalln(err) + } + + if err := ffv1alpha1.AddToScheme(scheme.Scheme); err != nil { + k.Logger.Panic(err.Error()) + } + + k.client, err = client.New(clusterConfig, client.Options{Scheme: scheme.Scheme}) + if err != nil { + k.Logger.Fatalln(err) } clusterClient, err := dynamic.NewForConfig(clusterConfig) @@ -167,7 +173,7 @@ func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.Obj if err != nil { return err } - if reflect.TypeOf(newObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { + if reflect.TypeOf(ffNewObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { return errors.New("new object is not a FeatureFlagConfiguration") } From 8d363bb13810b7e45866a0f4f92440eba603b744 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 11 Oct 2022 20:26:39 +0100 Subject: [PATCH 05/11] fumpt Signed-off-by: Alex Jones --- 1 | 67 -------------------------- pkg/sync/kubernetes/kubernetes_sync.go | 3 -- 2 files changed, 70 deletions(-) delete mode 100644 1 diff --git a/1 b/1 deleted file mode 100644 index 4dc523196..000000000 --- a/1 +++ /dev/null @@ -1,67 +0,0 @@ -# Please edit the object below. Lines beginning with a '#' will be ignored, -# and an empty file will abort the edit. If an error occurs while saving this file will be -# reopened with the relevant failures. -# -apiVersion: core.openfeature.dev/v1alpha1 -kind: FeatureFlagConfiguration -metadata: - annotations: - foo: bar2 - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"core.openfeature.dev/v1alpha1","kind":"FeatureFlagConfiguration","metadata":{"annotations":{},"name":"end-to-end","namespace":"default"},"spec":{"featureFlagSpec":"{\n \"flags\": {\n \"new-welcome-message\": {\n \"state\": \"ENABLED\",\n \"variants\": {\n \"on\": true,\n \"off\": false\n },\n \"defaultVariant\": \"on\"\n },\n \"hex-color\": {\n \"variants\": {\n \"red\": \"CC0000\",\n \"green\": \"00CC00\",\n \"blue\": \"0000CC\",\n \"yellow\": \"yellow\"\n },\n \"defaultVariant\": \"red\",\n \"state\": \"ENABLED\"\n },\n \"fib-algo\": {\n \"variants\": {\n \"recursive\": \"recursive\",\n \"memo\": \"memo\",\n \"loop\": \"loop\",\n \"binet\": \"binet\"\n },\n \"defaultVariant\": \"recursive\",\n \"state\": \"ENABLED\",\n \"targeting\": {\n \"if\": [\n {\n \"in\": [\"@faas.com\", {\n \"var\": [\"email\"]\n }]\n }, \"binet\", null\n ]\n }\n }\n }\n}\n"}} - creationTimestamp: "2022-10-04T13:21:39Z" - finalizers: - - featureflagconfiguration.core.openfeature.dev/finalizer - generation: 5 - name: end-to-end - namespace: default - resourceVersion: "2301482" - uid: b5f57e47-9093-4300-a6f3-21cfa1c4cba6 -spec: - featureFlagSpec: | - { - "flags": { - "new-welcome-message": { - "state": "ENABLED", - "variants": { - "on": true, - "off": false - }, - "defaultVariant": "on" - }, - "hex-color": { - "variants": { - "red": "CC0000", - "green": "00CC00", - "blue": "0000CC", - "yellow": "yellow" - }, - "defaultVariant": "green", - "state": "ENABLED" - }, - "fib-algo": { - "variants": { - "recursive": "recursive", - "memo": "memo", - "loop": "loop", - "binet": "binet" - }, - "defaultVariant": "recursive", - "state": "ENABLED", - "targeting": { - "if": [ - { - "in": ["@faas.com", { - "var": ["email"] - }] - }, "binet", null - ] - } - } - } - } - flagDSpec: null - serviceProvider: - credentials: null - name: flagd - syncProvider: null diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index 0dfd71e2a..7403d6ff3 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -132,11 +132,9 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { defer cancel() informer.Run(ctx.Done()) - } func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - var ffObj ffv1alpha1.FeatureFlagConfiguration u := obj.(*unstructured.Unstructured) err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffObj) @@ -157,7 +155,6 @@ func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.I } func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - var ffOldObj ffv1alpha1.FeatureFlagConfiguration u := oldObj.(*unstructured.Unstructured) err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffOldObj) From 615b79665afbbc2e188b48acb07e7e9c4ff9e1f8 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Wed, 12 Oct 2022 10:58:11 +0100 Subject: [PATCH 06/11] updated linting and comment feedback Signed-off-by: Alex Jones --- pkg/sync/kubernetes/ffclientset.go | 5 +- pkg/sync/kubernetes/kubernetes_sync.go | 68 +++++++++++++------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go index 9441f67b3..2f49100b1 100644 --- a/pkg/sync/kubernetes/ffclientset.go +++ b/pkg/sync/kubernetes/ffclientset.go @@ -5,7 +5,6 @@ import ( "errors" "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" @@ -90,8 +89,8 @@ func NewForConfig(config *rest.Config) (*FFCClient, error) { } config.ContentConfig.GroupVersion = &schema. GroupVersion{ - Group: ffv1alpha1.GroupVersion.Group, - Version: ffv1alpha1.GroupVersion.Version, + Group: v1alpha1.GroupVersion.Group, + Version: v1alpha1.GroupVersion.Version, } config.APIPath = "/apis" config.UserAgent = rest.DefaultKubernetesUserAgent() diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index 7403d6ff3..c6365ed30 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -4,12 +4,11 @@ import ( "context" "errors" "os" - "os/signal" "reflect" "time" "github.com/open-feature/flagd/pkg/sync" - ffv1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" + "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -28,8 +27,6 @@ const ( featureFlagNamespaceName = "namespace" ) -var resyncPeriod time.Duration // default of 0 - type Sync struct { Logger *log.Entry ProviderArgs sync.ProviderArgs @@ -56,7 +53,7 @@ func (k *Sync) Fetch(ctx context.Context) (string, error) { return "{}", nil } - var ff ffv1alpha1.FeatureFlagConfiguration + var ff v1alpha1.FeatureFlagConfiguration err := k.client.Get(ctx, client.ObjectKey{ Name: k.ProviderArgs[featureFlagConfigurationName], Namespace: k.ProviderArgs[featureFlagNamespaceName], @@ -65,6 +62,22 @@ func (k *Sync) Fetch(ctx context.Context) (string, error) { return ff.Spec.FeatureFlagSpec, err } +func (k *Sync) buildConfiguration() (*rest.Config, error) { + kubeconfig := os.Getenv("KUBECONFIG") + var clusterConfig *rest.Config + var err error + if kubeconfig != "" { + clusterConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + } else { + clusterConfig, err = rest.InClusterConfig() + } + if err != nil { + return nil, err + } + + return clusterConfig, nil +} + func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { if k.ProviderArgs[featureFlagConfigurationName] == "" { k.Logger.Info("No target feature flag configuration set") @@ -75,20 +88,12 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { return } k.Logger.Infof("Starting kubernetes sync notifier for resource %s", k.ProviderArgs["featureflagconfiguration"]) - kubeconfig := os.Getenv("KUBECONFIG") - var clusterConfig *rest.Config - var err error - if kubeconfig != "" { - clusterConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig) - } else { - clusterConfig, err = rest.InClusterConfig() - } + clusterConfig, err := k.buildConfiguration() if err != nil { - k.Logger.Fatalln(err) + k.Logger.Errorf("Error building configuration: %s", err) } - - if err := ffv1alpha1.AddToScheme(scheme.Scheme); err != nil { + if err := v1alpha1.AddToScheme(scheme.Scheme); err != nil { k.Logger.Panic(err.Error()) } @@ -102,8 +107,9 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { log.Fatalln(err) } - resource := ffv1alpha1.GroupVersion.WithResource("featureflagconfigurations") - factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient, time.Minute, corev1.NamespaceAll, nil) + resource := v1alpha1.GroupVersion.WithResource("featureflagconfigurations") + factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient, + time.Minute, corev1.NamespaceAll, nil) informer := factory.ForResource(resource).Informer() objectKey := client.ObjectKey{ @@ -128,21 +134,18 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { }, }) - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - defer cancel() - informer.Run(ctx.Done()) } func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - var ffObj ffv1alpha1.FeatureFlagConfiguration + var ffObj v1alpha1.FeatureFlagConfiguration u := obj.(*unstructured.Unstructured) err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffObj) if err != nil { return err } - if reflect.TypeOf(ffObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("object is not a FeatureFlagConfiguration") + if ffObj.APIVersion != v1alpha1.GroupVersion.Version { + return errors.New("invalid api version") } if ffObj.Name == object.Name { c <- &sync.Notifier{ @@ -155,25 +158,24 @@ func createFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.I } func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - var ffOldObj ffv1alpha1.FeatureFlagConfiguration + var ffOldObj v1alpha1.FeatureFlagConfiguration u := oldObj.(*unstructured.Unstructured) err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffOldObj) if err != nil { return err } - if reflect.TypeOf(ffOldObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("object is not a FeatureFlagConfiguration") + if ffOldObj.APIVersion != v1alpha1.GroupVersion.Version { + return errors.New("invalid api version") } - var ffNewObj ffv1alpha1.FeatureFlagConfiguration + var ffNewObj v1alpha1.FeatureFlagConfiguration u = newObj.(*unstructured.Unstructured) err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffNewObj) if err != nil { return err } - if reflect.TypeOf(ffNewObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { - return errors.New("new object is not a FeatureFlagConfiguration") + if ffNewObj.APIVersion != v1alpha1.GroupVersion.Version { + return errors.New("invalid api version") } - if object.Name == ffNewObj.Name && ffOldObj.ResourceVersion != ffNewObj.ResourceVersion { // Only update if there is an actual featureFlagSpec change c <- &sync.Notifier{ @@ -186,13 +188,13 @@ func updateFuncHandler(oldObj interface{}, newObj interface{}, object client.Obj } func deleteFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.INotify) error { - var ffObj ffv1alpha1.FeatureFlagConfiguration + var ffObj v1alpha1.FeatureFlagConfiguration u := obj.(*unstructured.Unstructured) err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &ffObj) if err != nil { return err } - if reflect.TypeOf(ffObj) != reflect.TypeOf(ffv1alpha1.FeatureFlagConfiguration{}) { + if reflect.TypeOf(ffObj) != reflect.TypeOf(v1alpha1.FeatureFlagConfiguration{}) { return errors.New("object is not a FeatureFlagConfiguration") } if ffObj.Name == object.Name { From c434382afd0080c7b1830884a90327d4ee5eb347 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 13 Oct 2022 09:56:07 +0100 Subject: [PATCH 07/11] addressing comments Signed-off-by: Alex Jones --- pkg/sync/kubernetes/ffclientset.go | 22 +++++++++++----------- pkg/sync/kubernetes/kubernetes_sync.go | 5 ++--- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go index 2f49100b1..be9a6d57c 100644 --- a/pkg/sync/kubernetes/ffclientset.go +++ b/pkg/sync/kubernetes/ffclientset.go @@ -20,20 +20,20 @@ type Interface interface { Watch(opts metav1.ListOptions) (watch.Interface, error) } -type FeatureFlagClient struct { +type FeatureFlagConfigurationImpl struct { restClient rest.Interface ns string } -type FFCInterface interface { +type FeatureFlagConfigurationInterface interface { FeatureFlagConfigurations(namespace string) Interface } -type FFCClient struct { +type FeatureFlagConfigurationRestClient struct { restClient rest.Interface } -func (c *FeatureFlagClient) List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) { +func (c *FeatureFlagConfigurationImpl) List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) { result := v1alpha1.FeatureFlagConfigurationList{} err := c.restClient. Get(). @@ -44,7 +44,7 @@ func (c *FeatureFlagClient) List(opts metav1.ListOptions) (*v1alpha1.FeatureFlag return &result, err } -func (c *FeatureFlagClient) Get(name string, opts metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) { +func (c *FeatureFlagConfigurationImpl) Get(name string, opts metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) { result := v1alpha1.FeatureFlagConfiguration{} err := c.restClient. Get(). @@ -58,7 +58,7 @@ func (c *FeatureFlagClient) Get(name string, opts metav1.GetOptions) (*v1alpha1. return &result, err } -func (c *FeatureFlagClient) Create(project *v1alpha1.FeatureFlagConfiguration) (*v1alpha1. +func (c *FeatureFlagConfigurationImpl) Create(project *v1alpha1.FeatureFlagConfiguration) (*v1alpha1. FeatureFlagConfiguration, error, ) { result := v1alpha1.FeatureFlagConfiguration{} @@ -73,7 +73,7 @@ func (c *FeatureFlagClient) Create(project *v1alpha1.FeatureFlagConfiguration) ( return &result, err } -func (c *FeatureFlagClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { +func (c *FeatureFlagConfigurationImpl) Watch(opts metav1.ListOptions) (watch.Interface, error) { opts.Watch = true return c.restClient. Get(). @@ -83,7 +83,7 @@ func (c *FeatureFlagClient) Watch(opts metav1.ListOptions) (watch.Interface, err Watch(context.Background()) } -func NewForConfig(config *rest.Config) (*FFCClient, error) { +func NewForConfig(config *rest.Config) (*FeatureFlagConfigurationRestClient, error) { if config == nil { return nil, errors.New("rest config is nil") } @@ -100,11 +100,11 @@ func NewForConfig(config *rest.Config) (*FFCClient, error) { return nil, err } - return &FFCClient{restClient: client}, nil + return &FeatureFlagConfigurationRestClient{restClient: client}, nil } -func (c *FFCClient) FeatureFlagConfigurations(namespace string) Interface { - return &FeatureFlagClient{ +func (c *FeatureFlagConfigurationRestClient) FeatureFlagConfigurations(namespace string) Interface { + return &FeatureFlagConfigurationImpl{ restClient: c.restClient, ns: namespace, } diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index c6365ed30..ff7a4e157 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -4,7 +4,6 @@ import ( "context" "errors" "os" - "reflect" "time" "github.com/open-feature/flagd/pkg/sync" @@ -194,8 +193,8 @@ func deleteFuncHandler(obj interface{}, object client.ObjectKey, c chan<- sync.I if err != nil { return err } - if reflect.TypeOf(ffObj) != reflect.TypeOf(v1alpha1.FeatureFlagConfiguration{}) { - return errors.New("object is not a FeatureFlagConfiguration") + if ffObj.APIVersion != v1alpha1.GroupVersion.Version { + return errors.New("invalid api version") } if ffObj.Name == object.Name { c <- &sync.Notifier{ From 2fa5ae57a1deceefc8e4b5c6d3c95d514f4e789e Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 13 Oct 2022 09:59:36 +0100 Subject: [PATCH 08/11] addressing comments Signed-off-by: Alex Jones --- pkg/sync/kubernetes/kubernetes_sync.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index ff7a4e157..9ffd1f4ae 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -26,6 +26,8 @@ const ( featureFlagNamespaceName = "namespace" ) +var resyncPeriod = 1 * time.Minute + type Sync struct { Logger *log.Entry ProviderArgs sync.ProviderArgs @@ -107,8 +109,15 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { } resource := v1alpha1.GroupVersion.WithResource("featureflagconfigurations") + // The created informer will not do resyncs if the given + // defaultEventHandlerResyncPeriod is zero. Otherwise: for each + // handler that with a non-zero requested resync period, whether added + // before or after the informer starts, the nominal resync period is + // the requested resync period rounded up to a multiple of the + // informer's resync checking period. + // For more details on resync implications refer to tools/cache/shared_informer.go factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient, - time.Minute, corev1.NamespaceAll, nil) + resyncPeriod, corev1.NamespaceAll, nil) informer := factory.ForResource(resource).Informer() objectKey := client.ObjectKey{ From 72c0cb5eacf8fdc6f2fe554a0b46cc99f75f9945 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 13 Oct 2022 11:17:01 +0100 Subject: [PATCH 09/11] addressing comments Signed-off-by: Alex Jones --- pkg/sync/kubernetes/ffclientset.go | 4 +++- pkg/sync/kubernetes/kubernetes_sync.go | 9 +-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go index be9a6d57c..15d114504 100644 --- a/pkg/sync/kubernetes/ffclientset.go +++ b/pkg/sync/kubernetes/ffclientset.go @@ -44,7 +44,9 @@ func (c *FeatureFlagConfigurationImpl) List(opts metav1.ListOptions) (*v1alpha1. return &result, err } -func (c *FeatureFlagConfigurationImpl) Get(name string, opts metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) { +func (c *FeatureFlagConfigurationImpl) Get(name string, + opts metav1.GetOptions, +) (*v1alpha1.FeatureFlagConfiguration, error) { result := v1alpha1.FeatureFlagConfiguration{} err := c.restClient. Get(). diff --git a/pkg/sync/kubernetes/kubernetes_sync.go b/pkg/sync/kubernetes/kubernetes_sync.go index 9ffd1f4ae..6ecdb0741 100644 --- a/pkg/sync/kubernetes/kubernetes_sync.go +++ b/pkg/sync/kubernetes/kubernetes_sync.go @@ -97,24 +97,17 @@ func (k *Sync) Notify(ctx context.Context, c chan<- sync.INotify) { if err := v1alpha1.AddToScheme(scheme.Scheme); err != nil { k.Logger.Panic(err.Error()) } - k.client, err = client.New(clusterConfig, client.Options{Scheme: scheme.Scheme}) if err != nil { k.Logger.Fatalln(err) } - clusterClient, err := dynamic.NewForConfig(clusterConfig) if err != nil { log.Fatalln(err) } - resource := v1alpha1.GroupVersion.WithResource("featureflagconfigurations") // The created informer will not do resyncs if the given - // defaultEventHandlerResyncPeriod is zero. Otherwise: for each - // handler that with a non-zero requested resync period, whether added - // before or after the informer starts, the nominal resync period is - // the requested resync period rounded up to a multiple of the - // informer's resync checking period. + // defaultEventHandlerResyncPeriod is zero. // For more details on resync implications refer to tools/cache/shared_informer.go factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient, resyncPeriod, corev1.NamespaceAll, nil) From 088129e3e60e23b004c96e4d21b06e8b0cd153f3 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 13 Oct 2022 11:17:59 +0100 Subject: [PATCH 10/11] addressing comments Signed-off-by: Alex Jones --- pkg/sync/kubernetes/ffclientset.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go index 15d114504..7a77ca999 100644 --- a/pkg/sync/kubernetes/ffclientset.go +++ b/pkg/sync/kubernetes/ffclientset.go @@ -13,7 +13,7 @@ import ( "k8s.io/client-go/rest" ) -type Interface interface { +type KubernetesClientInterface interface { List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) Get(name string, options metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) Create(*v1alpha1.FeatureFlagConfiguration) (*v1alpha1.FeatureFlagConfiguration, error) @@ -26,7 +26,7 @@ type FeatureFlagConfigurationImpl struct { } type FeatureFlagConfigurationInterface interface { - FeatureFlagConfigurations(namespace string) Interface + FeatureFlagConfigurations(namespace string) KubernetesClientInterface } type FeatureFlagConfigurationRestClient struct { @@ -105,7 +105,7 @@ func NewForConfig(config *rest.Config) (*FeatureFlagConfigurationRestClient, err return &FeatureFlagConfigurationRestClient{restClient: client}, nil } -func (c *FeatureFlagConfigurationRestClient) FeatureFlagConfigurations(namespace string) Interface { +func (c *FeatureFlagConfigurationRestClient) FeatureFlagConfigurations(namespace string) KubernetesClientInterface { return &FeatureFlagConfigurationImpl{ restClient: c.restClient, ns: namespace, From 93389ccfaf170fabeaf07e0f992c4a5f2b78c677 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 13 Oct 2022 11:23:14 +0100 Subject: [PATCH 11/11] addressing comments Signed-off-by: Alex Jones --- pkg/sync/kubernetes/ffclientset.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/sync/kubernetes/ffclientset.go b/pkg/sync/kubernetes/ffclientset.go index 7a77ca999..53527bc0c 100644 --- a/pkg/sync/kubernetes/ffclientset.go +++ b/pkg/sync/kubernetes/ffclientset.go @@ -13,22 +13,22 @@ import ( "k8s.io/client-go/rest" ) -type KubernetesClientInterface interface { +type ClientInterface interface { List(opts metav1.ListOptions) (*v1alpha1.FeatureFlagConfigurationList, error) Get(name string, options metav1.GetOptions) (*v1alpha1.FeatureFlagConfiguration, error) Create(*v1alpha1.FeatureFlagConfiguration) (*v1alpha1.FeatureFlagConfiguration, error) Watch(opts metav1.ListOptions) (watch.Interface, error) } +type FeatureFlagConfigurationInterface interface { + FeatureFlagConfigurations(namespace string) ClientInterface +} + type FeatureFlagConfigurationImpl struct { restClient rest.Interface ns string } -type FeatureFlagConfigurationInterface interface { - FeatureFlagConfigurations(namespace string) KubernetesClientInterface -} - type FeatureFlagConfigurationRestClient struct { restClient rest.Interface } @@ -105,7 +105,7 @@ func NewForConfig(config *rest.Config) (*FeatureFlagConfigurationRestClient, err return &FeatureFlagConfigurationRestClient{restClient: client}, nil } -func (c *FeatureFlagConfigurationRestClient) FeatureFlagConfigurations(namespace string) KubernetesClientInterface { +func (c *FeatureFlagConfigurationRestClient) FeatureFlagConfigurations(namespace string) ClientInterface { return &FeatureFlagConfigurationImpl{ restClient: c.restClient, ns: namespace,