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:
parent
af105c2bc7
commit
905797b50f
59
controller/cluster_check.go
Normal file
59
controller/cluster_check.go
Normal 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:]...)
|
||||
}
|
@ -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)
|
||||
}
|
||||
`
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user