diff --git a/controller/cluster_check.go b/controller/cluster_check.go new file mode 100644 index 00000000..6d5f2d58 --- /dev/null +++ b/controller/cluster_check.go @@ -0,0 +1,59 @@ +package controller + +import ( + "reflect" + "strings" +) + +func ObjectInCluster(cluster string, obj interface{}) bool { + var clusterName string + if c := getValue(obj, "ClusterName"); c.IsValid() { + clusterName = c.String() + } + if clusterName == "" { + if c := getValue(obj, "Spec", "ClusterName"); c.IsValid() { + clusterName = c.String() + } + + } + if clusterName == "" { + if c := getValue(obj, "ProjectName"); c.IsValid() { + if parts := strings.SplitN(c.String(), ":", 2); len(parts) == 2 { + clusterName = parts[0] + } + } + } + if clusterName == "" { + if c := getValue(obj, "Spec", "ProjectName"); c.IsValid() { + if parts := strings.SplitN(c.String(), ":", 2); len(parts) == 2 { + clusterName = parts[0] + } + } + } + + return clusterName == cluster +} + +func getValue(obj interface{}, name ...string) reflect.Value { + v := reflect.ValueOf(obj) + t := v.Type() + if t.Kind() == reflect.Ptr { + v = v.Elem() + t = v.Type() + } + + field := v.FieldByName(name[0]) + if !field.IsValid() || len(name) == 1 { + return field + } + + return getFieldValue(field, name[1:]...) +} + +func getFieldValue(v reflect.Value, name ...string) reflect.Value { + field := v.FieldByName(name[0]) + if len(name) == 1 { + return field + } + return getFieldValue(field, name[1:]...) +} diff --git a/generator/controller_template.go b/generator/controller_template.go index 21481378..12132e00 100644 --- a/generator/controller_template.go +++ b/generator/controller_template.go @@ -52,6 +52,7 @@ type {{.schema.CodeName}}Controller interface { Informer() cache.SharedIndexInformer Lister() {{.schema.CodeName}}Lister AddHandler(name string, handler {{.schema.CodeName}}HandlerFunc) + AddClusterScopedHandler(name, clusterName string, handler {{.schema.CodeName}}HandlerFunc) Enqueue(namespace, name string) Sync(ctx context.Context) error Start(ctx context.Context, threadiness int) error @@ -71,6 +72,8 @@ type {{.schema.CodeName}}Interface interface { Controller() {{.schema.CodeName}}Controller AddHandler(name string, sync {{.schema.CodeName}}HandlerFunc) AddLifecycle(name string, lifecycle {{.schema.CodeName}}Lifecycle) + AddClusterScopedHandler(name, clusterName string, sync {{.schema.CodeName}}HandlerFunc) + AddClusterScopedLifecycle(name, clusterName string, lifecycle {{.schema.CodeName}}Lifecycle) } type {{.schema.ID}}Lister struct { @@ -128,6 +131,24 @@ func (c *{{.schema.ID}}Controller) AddHandler(name string, handler {{.schema.Cod }) } +func (c *{{.schema.ID}}Controller) AddClusterScopedHandler(name, cluster string, handler {{.schema.CodeName}}HandlerFunc) { + c.GenericController.AddHandler(name, func(key string) error { + obj, exists, err := c.Informer().GetStore().GetByKey(key) + if err != nil { + return err + } + if !exists { + return handler(key, nil) + } + + if !controller.ObjectInCluster(cluster, obj) { + return nil + } + + return handler(key, obj.(*{{.prefix}}{{.schema.CodeName}})) + }) +} + type {{.schema.ID}}Factory struct { } @@ -224,7 +245,16 @@ func (s *{{.schema.ID}}Client) AddHandler(name string, sync {{.schema.CodeName}} } func (s *{{.schema.ID}}Client) AddLifecycle(name string, lifecycle {{.schema.CodeName}}Lifecycle) { - sync := New{{.schema.CodeName}}LifecycleAdapter(name, s, lifecycle) + sync := New{{.schema.CodeName}}LifecycleAdapter(name, false, s, lifecycle) s.AddHandler(name, sync) } + +func (s *{{.schema.ID}}Client) AddClusterScopedHandler(name, clusterName string, sync {{.schema.CodeName}}HandlerFunc) { + s.Controller().AddClusterScopedHandler(name, clusterName, sync) +} + +func (s *{{.schema.ID}}Client) AddClusterScopedLifecycle(name, clusterName string, lifecycle {{.schema.CodeName}}Lifecycle) { + sync := New{{.schema.CodeName}}LifecycleAdapter(name+"_"+clusterName, true, s, lifecycle) + s.AddClusterScopedHandler(name, clusterName, sync) +} ` diff --git a/generator/lifecycle_template.go b/generator/lifecycle_template.go index 67a76c5f..b67b450f 100644 --- a/generator/lifecycle_template.go +++ b/generator/lifecycle_template.go @@ -42,9 +42,9 @@ func (w *{{.schema.ID}}LifecycleAdapter) Updated(obj runtime.Object) (runtime.Ob return o, err } -func New{{.schema.CodeName}}LifecycleAdapter(name string, client {{.schema.CodeName}}Interface, l {{.schema.CodeName}}Lifecycle) {{.schema.CodeName}}HandlerFunc { +func New{{.schema.CodeName}}LifecycleAdapter(name string, clusterScoped bool, client {{.schema.CodeName}}Interface, l {{.schema.CodeName}}Lifecycle) {{.schema.CodeName}}HandlerFunc { adapter := &{{.schema.ID}}LifecycleAdapter{lifecycle: l} - syncFn := lifecycle.NewObjectLifecycleAdapter(name, adapter, client.ObjectClient()) + syncFn := lifecycle.NewObjectLifecycleAdapter(name, clusterScoped, adapter, client.ObjectClient()) return func(key string, obj *{{.prefix}}{{.schema.CodeName}}) error { if obj == nil { return syncFn(key, nil) diff --git a/lifecycle/object.go b/lifecycle/object.go index 9b5b2276..43b92f31 100644 --- a/lifecycle/object.go +++ b/lifecycle/object.go @@ -11,8 +11,9 @@ import ( ) var ( - created = "lifecycle.cattle.io/create" - finalizerKey = "controller.cattle.io/" + created = "lifecycle.cattle.io/create" + finalizerKey = "controller.cattle.io/" + ScopedFinalizerKey = "clusterscoped.controller.cattle.io/" ) type ObjectLifecycle interface { @@ -22,16 +23,18 @@ type ObjectLifecycle interface { } type objectLifecycleAdapter struct { - name string - lifecycle ObjectLifecycle - objectClient *clientbase.ObjectClient + name string + clusterScoped bool + lifecycle ObjectLifecycle + objectClient *clientbase.ObjectClient } -func NewObjectLifecycleAdapter(name string, lifecycle ObjectLifecycle, objectClient *clientbase.ObjectClient) func(key string, obj runtime.Object) error { +func NewObjectLifecycleAdapter(name string, clusterScoped bool, lifecycle ObjectLifecycle, objectClient *clientbase.ObjectClient) func(key string, obj runtime.Object) error { o := objectLifecycleAdapter{ - name: name, - lifecycle: lifecycle, - objectClient: objectClient, + name: name, + clusterScoped: clusterScoped, + lifecycle: lifecycle, + objectClient: objectClient, } return o.sync } @@ -116,6 +119,9 @@ func (o *objectLifecycleAdapter) createKey() string { } func (o *objectLifecycleAdapter) constructFinalizerKey() string { + if o.clusterScoped { + return ScopedFinalizerKey + o.name + } return finalizerKey + o.name }