1
0
mirror of https://github.com/rancher/norman.git synced 2025-04-29 11:54:44 +00:00
norman/lifecycle/object.go

268 lines
6.3 KiB
Go
Raw Permalink Normal View History

2017-12-05 16:21:12 +00:00
package lifecycle
import (
2018-04-02 11:26:22 +00:00
"fmt"
"reflect"
2018-04-03 19:49:20 +00:00
"github.com/rancher/norman/objectclient"
2017-12-05 16:21:12 +00:00
"github.com/rancher/norman/types/slice"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
var (
created = "lifecycle.cattle.io/create"
finalizerKey = "controller.cattle.io/"
ScopedFinalizerKey = "clusterscoped.controller.cattle.io/"
2017-12-05 16:21:12 +00:00
)
type ObjectLifecycle interface {
Create(obj runtime.Object) (runtime.Object, error)
Finalize(obj runtime.Object) (runtime.Object, error)
Updated(obj runtime.Object) (runtime.Object, error)
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
type ObjectLifecycleCondition interface {
HasCreate() bool
HasFinalize() bool
}
2017-12-05 16:21:12 +00:00
type objectLifecycleAdapter struct {
name string
clusterScoped bool
lifecycle ObjectLifecycle
2018-04-03 19:49:20 +00:00
objectClient *objectclient.ObjectClient
2017-12-05 16:21:12 +00:00
}
2018-10-30 16:54:49 +00:00
func NewObjectLifecycleAdapter(name string, clusterScoped bool, lifecycle ObjectLifecycle, objectClient *objectclient.ObjectClient) func(key string, obj interface{}) (interface{}, error) {
2017-12-05 16:21:12 +00:00
o := objectLifecycleAdapter{
name: name,
clusterScoped: clusterScoped,
lifecycle: lifecycle,
objectClient: objectClient,
2017-12-05 16:21:12 +00:00
}
return o.sync
}
2018-10-30 16:54:49 +00:00
func (o *objectLifecycleAdapter) sync(key string, in interface{}) (interface{}, error) {
if in == nil || reflect.ValueOf(in).IsNil() {
return nil, nil
}
obj, ok := in.(runtime.Object)
if !ok {
return nil, nil
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
if newObj, cont, err := o.finalize(obj); err != nil || !cont {
2018-10-30 16:54:49 +00:00
return nil, err
} else if newObj != nil {
obj = newObj
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
if newObj, cont, err := o.create(obj); err != nil || !cont {
2018-10-30 16:54:49 +00:00
return nil, err
} else if newObj != nil {
obj = newObj
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
return o.record(obj, o.lifecycle.Updated)
}
func (o *objectLifecycleAdapter) update(name string, orig, obj runtime.Object) (runtime.Object, error) {
2018-11-19 23:30:00 +00:00
if obj != nil && orig != nil && !reflect.DeepEqual(orig, obj) {
newObj, err := o.objectClient.Update(name, obj)
if newObj != nil {
return newObj, err
}
return obj, err
}
if obj == nil {
return orig, nil
}
return obj, nil
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
func (o *objectLifecycleAdapter) finalize(obj runtime.Object) (runtime.Object, bool, error) {
2018-11-26 17:46:11 +00:00
if !o.hasFinalize() {
return obj, true, nil
}
2018-11-19 23:30:00 +00:00
metadata, err := meta.Accessor(obj)
if err != nil {
return obj, false, err
}
2017-12-05 16:21:12 +00:00
// Check finalize
if metadata.GetDeletionTimestamp() == nil {
2018-10-30 16:54:49 +00:00
return nil, true, nil
2017-12-05 16:21:12 +00:00
}
2018-01-03 21:50:43 +00:00
if !slice.ContainsString(metadata.GetFinalizers(), o.constructFinalizerKey()) {
2018-10-30 16:54:49 +00:00
return nil, false, nil
2017-12-05 16:21:12 +00:00
}
2018-11-19 23:30:00 +00:00
newObj, err := o.record(obj, o.lifecycle.Finalize)
if err != nil {
return obj, false, err
2017-12-16 08:22:48 +00:00
}
2018-11-19 23:30:00 +00:00
obj, err = o.removeFinalizer(o.constructFinalizerKey(), maybeDeepCopy(obj, newObj))
return obj, false, err
}
func maybeDeepCopy(old, newObj runtime.Object) runtime.Object {
if old == newObj {
return old.DeepCopyObject()
}
return newObj
2017-12-16 08:22:48 +00:00
}
2018-10-30 16:54:49 +00:00
func (o *objectLifecycleAdapter) removeFinalizer(name string, obj runtime.Object) (runtime.Object, error) {
for i := 0; i < 3; i++ {
metadata, err := meta.Accessor(obj)
if err != nil {
2018-10-30 16:54:49 +00:00
return nil, err
}
2017-12-05 16:21:12 +00:00
var finalizers []string
for _, finalizer := range metadata.GetFinalizers() {
if finalizer == name {
continue
}
finalizers = append(finalizers, finalizer)
2017-12-05 16:21:12 +00:00
}
metadata.SetFinalizers(finalizers)
2017-12-05 16:21:12 +00:00
2018-10-30 16:54:49 +00:00
newObj, err := o.objectClient.Update(metadata.GetName(), obj)
2018-04-02 11:26:22 +00:00
if err == nil {
2018-10-30 16:54:49 +00:00
return newObj, nil
2018-04-02 11:26:22 +00:00
}
obj, err = o.objectClient.GetNamespaced(metadata.GetNamespace(), metadata.GetName(), metav1.GetOptions{})
if err != nil {
2018-10-30 16:54:49 +00:00
return nil, err
2018-04-02 11:26:22 +00:00
}
}
2018-10-30 16:54:49 +00:00
return nil, fmt.Errorf("failed to remove finalizer on %s", name)
2017-12-05 16:21:12 +00:00
}
2017-12-05 21:15:52 +00:00
func (o *objectLifecycleAdapter) createKey() string {
return created + "." + o.name
2017-12-05 16:21:12 +00:00
}
2018-01-03 21:50:43 +00:00
func (o *objectLifecycleAdapter) constructFinalizerKey() string {
if o.clusterScoped {
return ScopedFinalizerKey + o.name
}
2018-01-03 21:50:43 +00:00
return finalizerKey + o.name
}
2018-11-19 23:30:00 +00:00
func (o *objectLifecycleAdapter) hasFinalize() bool {
cond, ok := o.lifecycle.(ObjectLifecycleCondition)
return !ok || cond.HasFinalize()
}
2017-12-05 16:21:12 +00:00
2018-11-19 23:30:00 +00:00
func (o *objectLifecycleAdapter) hasCreate() bool {
cond, ok := o.lifecycle.(ObjectLifecycleCondition)
return !ok || cond.HasCreate()
}
func (o *objectLifecycleAdapter) record(obj runtime.Object, f func(runtime.Object) (runtime.Object, error)) (runtime.Object, error) {
metadata, err := meta.Accessor(obj)
if err != nil {
2018-11-19 23:30:00 +00:00
return obj, err
}
2018-11-26 17:46:11 +00:00
origObj := obj
obj = origObj.DeepCopyObject()
2018-12-04 05:02:25 +00:00
if newObj, err := checkNil(obj, f); err != nil {
2018-11-26 17:46:11 +00:00
newObj, _ = o.update(metadata.GetName(), origObj, newObj)
2018-11-19 23:30:00 +00:00
return newObj, err
2017-12-16 08:22:48 +00:00
} else if newObj != nil {
return o.update(metadata.GetName(), origObj, newObj)
2018-11-19 23:30:00 +00:00
}
return obj, nil
}
2018-12-04 05:02:25 +00:00
func checkNil(obj runtime.Object, f func(runtime.Object) (runtime.Object, error)) (runtime.Object, error) {
obj, err := f(obj)
if obj == nil || reflect.ValueOf(obj).IsNil() {
return nil, err
}
return obj, err
}
2018-11-19 23:30:00 +00:00
func (o *objectLifecycleAdapter) create(obj runtime.Object) (runtime.Object, bool, error) {
metadata, err := meta.Accessor(obj)
if err != nil {
return obj, false, err
}
if o.isInitialized(metadata) {
return nil, true, nil
}
if o.hasFinalize() {
obj, err = o.addFinalizer(obj)
if err != nil {
return obj, false, err
}
2017-12-16 08:22:48 +00:00
}
2018-11-19 23:30:00 +00:00
if !o.hasCreate() {
return obj, true, err
}
obj, err = o.record(obj, o.lifecycle.Create)
2018-11-26 17:46:11 +00:00
if err != nil {
return obj, false, err
}
obj, err = o.setInitialized(obj)
2018-11-19 23:30:00 +00:00
return obj, false, err
}
func (o *objectLifecycleAdapter) isInitialized(metadata metav1.Object) bool {
initialized := o.createKey()
return metadata.GetAnnotations()[initialized] == "true"
}
2018-10-30 16:54:49 +00:00
func (o *objectLifecycleAdapter) setInitialized(obj runtime.Object) (runtime.Object, error) {
2017-12-05 16:21:12 +00:00
metadata, err := meta.Accessor(obj)
if err != nil {
2018-10-30 16:54:49 +00:00
return nil, err
2017-12-05 16:21:12 +00:00
}
initialized := o.createKey()
2017-12-16 08:22:48 +00:00
if metadata.GetAnnotations() == nil {
metadata.SetAnnotations(map[string]string{})
2017-12-05 16:21:12 +00:00
}
2017-12-16 08:22:48 +00:00
metadata.GetAnnotations()[initialized] = "true"
2017-12-05 16:21:12 +00:00
2018-10-30 16:54:49 +00:00
return o.objectClient.Update(metadata.GetName(), obj)
}
func (o *objectLifecycleAdapter) addFinalizer(obj runtime.Object) (runtime.Object, error) {
metadata, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
if slice.ContainsString(metadata.GetFinalizers(), o.constructFinalizerKey()) {
return obj, nil
}
2018-11-19 23:30:00 +00:00
obj = obj.DeepCopyObject()
metadata, err = meta.Accessor(obj)
if err != nil {
return nil, err
}
metadata.SetFinalizers(append(metadata.GetFinalizers(), o.constructFinalizerKey()))
return o.objectClient.Update(metadata.GetName(), obj)
2017-12-05 16:21:12 +00:00
}