1
0
mirror of https://github.com/rancher/norman.git synced 2025-05-11 01:25:54 +00:00

Add suport for cluster scoped controllers

Some worload controllers need to watch resoruces in the mangement plane
and react to them. But, they should only react to resources that
correspond to their cluster. This adds framework support for that.
This commit is contained in:
Craig Jellick 2018-01-15 13:38:10 -07:00
parent af105c2bc7
commit 905797b50f
4 changed files with 107 additions and 12 deletions

View File

@ -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:]...)
}

View File

@ -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)
}
`

View File

@ -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)

View File

@ -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
}