-
Notifications
You must be signed in to change notification settings - Fork 40k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GarbageCollector] Adding garbage collector controller #24509
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ import ( | |
"fmt" | ||
"reflect" | ||
|
||
"k8s.io/kubernetes/pkg/api/meta/metatypes" | ||
"k8s.io/kubernetes/pkg/api/unversioned" | ||
"k8s.io/kubernetes/pkg/conversion" | ||
"k8s.io/kubernetes/pkg/runtime" | ||
|
@@ -28,19 +29,53 @@ import ( | |
"github.com/golang/glog" | ||
) | ||
|
||
func ListAccessor(obj interface{}) (List, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ListAccessor to meta.List is what Accessor to meta.Object. The UnstructuredList doesn't have a |
||
if listMetaAccessor, ok := obj.(ListMetaAccessor); ok { | ||
if om := listMetaAccessor.GetListMeta(); om != nil { | ||
return om, nil | ||
} | ||
} | ||
// we may get passed an object that is directly portable to List | ||
if list, ok := obj.(List); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check for this first, since the object could support this and the list meta accessor? |
||
return list, nil | ||
} | ||
glog.V(4).Infof("Calling ListAccessor on non-internal object: %v", reflect.TypeOf(obj)) | ||
// legacy path for objects that do not implement List and ListMetaAccessor via | ||
// reflection - very slow code path. | ||
v, err := conversion.EnforcePtr(obj) | ||
if err != nil { | ||
return nil, err | ||
} | ||
t := v.Type() | ||
if v.Kind() != reflect.Struct { | ||
return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface()) | ||
} | ||
a := &genericAccessor{} | ||
listMeta := v.FieldByName("ListMeta") | ||
if listMeta.IsValid() { | ||
// look for the ListMeta fields | ||
if err := extractFromListMeta(listMeta, a); err != nil { | ||
return nil, fmt.Errorf("unable to find list fields on %#v: %v", listMeta, err) | ||
} | ||
} else { | ||
return nil, fmt.Errorf("unable to find listMeta on %#v", v) | ||
} | ||
return a, nil | ||
} | ||
|
||
// Accessor takes an arbitrary object pointer and returns meta.Interface. | ||
// obj must be a pointer to an API type. An error is returned if the minimum | ||
// required fields are missing. Fields that are not required return the default | ||
// value and are a no-op if set. | ||
func Accessor(obj interface{}) (Object, error) { | ||
if oi, ok := obj.(ObjectMetaAccessor); ok { | ||
if om := oi.GetObjectMeta(); om != nil { | ||
if objectMetaAccessor, ok := obj.(ObjectMetaAccessor); ok { | ||
if om := objectMetaAccessor.GetObjectMeta(); om != nil { | ||
return om, nil | ||
} | ||
} | ||
// we may get passed an object that is directly portable to Object | ||
if oi, ok := obj.(Object); ok { | ||
return oi, nil | ||
if object, ok := obj.(Object); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check first? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I replied to you in the old commits but I it's lost after rebase. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, sorry, didn't realize this was preexisting code :) |
||
return object, nil | ||
} | ||
|
||
glog.V(4).Infof("Calling Accessor on non-internal object: %v", reflect.TypeOf(obj)) | ||
|
@@ -310,6 +345,40 @@ func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) e | |
return nil | ||
} | ||
|
||
// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object. | ||
func extractFromOwnerReference(v reflect.Value, o *metatypes.OwnerReference) error { | ||
if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil { | ||
return err | ||
} | ||
if err := runtime.Field(v, "Kind", &o.Kind); err != nil { | ||
return err | ||
} | ||
if err := runtime.Field(v, "Name", &o.Name); err != nil { | ||
return err | ||
} | ||
if err := runtime.Field(v, "UID", &o.UID); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// setOwnerReference sets v to o. v is the OwnerReferences field of an object. | ||
func setOwnerReference(v reflect.Value, o *metatypes.OwnerReference) error { | ||
if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil { | ||
return err | ||
} | ||
if err := runtime.SetField(o.Kind, v, "Kind"); err != nil { | ||
return err | ||
} | ||
if err := runtime.SetField(o.Name, v, "Name"); err != nil { | ||
return err | ||
} | ||
if err := runtime.SetField(o.UID, v, "UID"); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// genericAccessor contains pointers to strings that can modify an arbitrary | ||
// struct and implements the Accessor interface. | ||
type genericAccessor struct { | ||
|
@@ -325,6 +394,7 @@ type genericAccessor struct { | |
deletionTimestamp **unversioned.Time | ||
labels *map[string]string | ||
annotations *map[string]string | ||
ownerReferences reflect.Value | ||
} | ||
|
||
func (a genericAccessor) GetNamespace() string { | ||
|
@@ -457,6 +527,41 @@ func (a genericAccessor) SetAnnotations(annotations map[string]string) { | |
*a.annotations = annotations | ||
} | ||
|
||
func (a genericAccessor) GetOwnerReferences() []metatypes.OwnerReference { | ||
var ret []metatypes.OwnerReference | ||
s := a.ownerReferences | ||
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice { | ||
glog.Errorf("expect %v to be a pointer to slice", s) | ||
return ret | ||
} | ||
s = s.Elem() | ||
// Set the capacity to one element greater to avoid copy if the caller later append an element. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I won't complain but this seems like the sort of thing you only do after measuring. |
||
ret = make([]metatypes.OwnerReference, s.Len(), s.Len()+1) | ||
for i := 0; i < s.Len(); i++ { | ||
if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nit: It would look slightly better if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current way saves one copy so I'll keep it as it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you measured it, I'd be willing to bet the cost of the copy is lost in the noise. But I don't have a terribly strong preference either way. |
||
glog.Errorf("extractFromOwnerReference failed: %v", err) | ||
return ret | ||
} | ||
} | ||
return ret | ||
} | ||
|
||
func (a genericAccessor) SetOwnerReferences(references []metatypes.OwnerReference) { | ||
s := a.ownerReferences | ||
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice { | ||
glog.Errorf("expect %v to be a pointer to slice", s) | ||
} | ||
s = s.Elem() | ||
newReferences := reflect.MakeSlice(s.Type(), len(references), len(references)) | ||
for i := 0; i < len(references); i++ { | ||
if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil { | ||
glog.Errorf("setOwnerReference failed: %v", err) | ||
return | ||
} | ||
} | ||
s.Set(newReferences) | ||
} | ||
|
||
// extractFromTypeMeta extracts pointers to version and kind fields from an object | ||
func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error { | ||
if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil { | ||
|
@@ -494,6 +599,14 @@ func extractFromObjectMeta(v reflect.Value, a *genericAccessor) error { | |
if err := runtime.FieldPtr(v, "Annotations", &a.annotations); err != nil { | ||
return err | ||
} | ||
ownerReferences := v.FieldByName("OwnerReferences") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lavalamp this is still WIP, but would be great if you can take a look if this is the way we want to go. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I left some comments on one of the commits. |
||
if !ownerReferences.IsValid() { | ||
return fmt.Errorf("struct %#v lacks OwnerReferences type", v) | ||
} | ||
if ownerReferences.Kind() != reflect.Slice { | ||
return fmt.Errorf("expect %v to be a slice", ownerReferences.Kind()) | ||
} | ||
a.ownerReferences = ownerReferences.Addr() | ||
return nil | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weird place for this assertion. I guess runtime can't import meta?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.