-
Notifications
You must be signed in to change notification settings - Fork 41.5k
[GarbageCollector] only store typeMeta and objectMeta in the gc store #28480
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
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 |
---|---|---|
|
@@ -33,6 +33,7 @@ import ( | |
"k8s.io/kubernetes/pkg/client/cache" | ||
"k8s.io/kubernetes/pkg/client/typed/dynamic" | ||
"k8s.io/kubernetes/pkg/controller/framework" | ||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly" | ||
"k8s.io/kubernetes/pkg/runtime" | ||
"k8s.io/kubernetes/pkg/types" | ||
utilerrors "k8s.io/kubernetes/pkg/util/errors" | ||
|
@@ -154,6 +155,7 @@ func (p *Propagator) addDependentToOwners(n *node, owners []metatypes.OwnerRefer | |
dependentsLock: &sync.RWMutex{}, | ||
dependents: make(map[*node]struct{}), | ||
} | ||
glog.V(6).Infof("add virtual node.identity: %s\n\n", ownerNode.identity) | ||
p.uidToNode.Write(ownerNode) | ||
p.gc.dirtyQueue.Add(ownerNode) | ||
} | ||
|
@@ -426,16 +428,19 @@ func (p *Propagator) processEvent() { | |
// removing ownerReferences from the dependents if the owner is deleted with | ||
// DeleteOptions.OrphanDependents=true. | ||
type GarbageCollector struct { | ||
restMapper meta.RESTMapper | ||
restMapper meta.RESTMapper | ||
// metaOnlyClientPool uses a special codec, which removes fields except for | ||
// apiVersion, kind, and metadata during decoding. | ||
metaOnlyClientPool dynamic.ClientPool | ||
// clientPool uses the regular dynamicCodec. We need it to update | ||
// finalizers. It can be removed if we support patching finalizers. | ||
clientPool dynamic.ClientPool | ||
dirtyQueue *workqueue.Type | ||
orphanQueue *workqueue.Type | ||
monitors []monitor | ||
propagator *Propagator | ||
} | ||
|
||
// TODO: make special List and Watch function that removes fields other than | ||
// ObjectMeta. | ||
func gcListWatcher(client *dynamic.Client, resource unversioned.GroupVersionResource) *cache.ListWatch { | ||
return &cache.ListWatch{ | ||
ListFunc: func(options api.ListOptions) (runtime.Object, error) { | ||
|
@@ -461,28 +466,38 @@ func gcListWatcher(client *dynamic.Client, resource unversioned.GroupVersionReso | |
} | ||
} | ||
|
||
func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversioned.GroupVersionResource) (monitor, error) { | ||
func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversioned.GroupVersionResource, kind unversioned.GroupVersionKind) (monitor, error) { | ||
// TODO: consider store in one storage. | ||
glog.V(6).Infof("create storage for resource %s", resource) | ||
var monitor monitor | ||
client, err := clientPool.ClientForGroupVersion(resource.GroupVersion()) | ||
client, err := p.gc.metaOnlyClientPool.ClientForGroupVersion(resource.GroupVersion()) | ||
if err != nil { | ||
return monitor, err | ||
} | ||
setObjectTypeMeta := func(obj interface{}) { | ||
runtimeObject, ok := obj.(runtime.Object) | ||
if !ok { | ||
utilruntime.HandleError(fmt.Errorf("expected runtime.Object, got %#v", obj)) | ||
} | ||
runtimeObject.GetObjectKind().SetGroupVersionKind(kind) | ||
} | ||
monitor.store, monitor.controller = framework.NewInformer( | ||
gcListWatcher(client, resource), | ||
nil, | ||
ResourceResyncTime, | ||
framework.ResourceEventHandlerFuncs{ | ||
// add the event to the propagator's eventQueue. | ||
AddFunc: func(obj interface{}) { | ||
setObjectTypeMeta(obj) | ||
event := event{ | ||
eventType: addEvent, | ||
obj: obj, | ||
} | ||
p.eventQueue.Add(event) | ||
}, | ||
UpdateFunc: func(oldObj, newObj interface{}) { | ||
setObjectTypeMeta(newObj) | ||
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 suggest just making your new codec do this step? 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 don't have a codec. One benefit of registering the MetaOnly to the scheme is utilizing the existing codecs, like the DirectCodec. I think it's neater to do it here unless we see other use cases then we can put a generalized codec. [edit] Also our a List doesn't set the gvk of items, we would need special decoder to workaround that as well. 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. Chao convinced me IRL :( On Thu, Aug 4, 2016 at 2:26 PM, Chao Xu notifications@github.com wrote:
|
||
setObjectTypeMeta(oldObj) | ||
event := event{updateEvent, newObj, oldObj} | ||
p.eventQueue.Add(event) | ||
}, | ||
|
@@ -491,6 +506,7 @@ func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversion | |
if deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown); ok { | ||
obj = deletedFinalStateUnknown.Obj | ||
} | ||
setObjectTypeMeta(obj) | ||
event := event{ | ||
eventType: deleteEvent, | ||
obj: obj, | ||
|
@@ -511,11 +527,12 @@ var ignoredResources = map[unversioned.GroupVersionResource]struct{}{ | |
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {}, | ||
} | ||
|
||
func NewGarbageCollector(clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) { | ||
func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) { | ||
gc := &GarbageCollector{ | ||
clientPool: clientPool, | ||
dirtyQueue: workqueue.New(), | ||
orphanQueue: workqueue.New(), | ||
metaOnlyClientPool: metaOnlyClientPool, | ||
clientPool: clientPool, | ||
dirtyQueue: workqueue.New(), | ||
orphanQueue: workqueue.New(), | ||
// TODO: should use a dynamic RESTMapper built from the discovery results. | ||
restMapper: registered.RESTMapper(), | ||
} | ||
|
@@ -532,7 +549,11 @@ func NewGarbageCollector(clientPool dynamic.ClientPool, resources []unversioned. | |
glog.V(6).Infof("ignore resource %#v", resource) | ||
continue | ||
} | ||
monitor, err := monitorFor(gc.propagator, gc.clientPool, resource) | ||
kind, err := gc.restMapper.KindFor(resource) | ||
if err != nil { | ||
return nil, err | ||
} | ||
monitor, err := monitorFor(gc.propagator, gc.clientPool, resource, kind) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -549,7 +570,7 @@ func (gc *GarbageCollector) worker() { | |
defer gc.dirtyQueue.Done(key) | ||
err := gc.processItem(key.(*node)) | ||
if err != nil { | ||
utilruntime.HandleError(fmt.Errorf("Error syncing item %v: %v", key, err)) | ||
utilruntime.HandleError(fmt.Errorf("Error syncing item %#v: %v", key, err)) | ||
} | ||
} | ||
|
||
|
@@ -623,6 +644,20 @@ func objectReferenceToUnstructured(ref objectReference) *runtime.Unstructured { | |
return ret | ||
} | ||
|
||
func objectReferenceToMetadataOnlyObject(ref objectReference) *metaonly.MetadataOnlyObject { | ||
return &metaonly.MetadataOnlyObject{ | ||
TypeMeta: unversioned.TypeMeta{ | ||
APIVersion: ref.APIVersion, | ||
Kind: ref.Kind, | ||
}, | ||
ObjectMeta: v1.ObjectMeta{ | ||
Namespace: ref.Namespace, | ||
UID: ref.UID, | ||
Name: ref.Name, | ||
}, | ||
} | ||
} | ||
|
||
func (gc *GarbageCollector) processItem(item *node) error { | ||
// G 684D et the latest item from the API server | ||
latest, err := gc.getObject(item.identity) | ||
|
@@ -634,15 +669,22 @@ func (gc *GarbageCollector) processItem(item *node) error { | |
glog.V(6).Infof("item %v not found, generating a virtual delete event", item.identity) | ||
event := event{ | ||
eventType: deleteEvent, | ||
obj: objectReferenceToUnstructured(item.identity), | ||
obj: objectReferenceToMetadataOnlyObject(item.identity), | ||
} | ||
glog.V(6).Infof("generating virtual delete event for %s\n\n", event.obj) | ||
gc.propagator.eventQueue.Add(event) | ||
return nil | ||
} | ||
return err | ||
} | ||
if latest.GetUID() != item.identity.UID { | ||
glog.V(6).Infof("UID doesn't match, item %v not found, ignore it", item.identity) | ||
glog.V(6).Infof("UID doesn't match, item %v not found, generating a virtual delete event", item.identity) | ||
event := event{ | ||
eventType: deleteEvent, | ||
obj: objectReferenceToMetadataOnlyObject(item.identity), | ||
} | ||
glog.V(6).Infof("generating virtual delete event for %s\n\n", event.obj) | ||
gc.propagator.eventQueue.Add(event) | ||
return nil | ||
} | ||
ownerReferences := latest.GetOwnerReferences() | ||
|
Uh oh!
There was an error while loading. Please reload this page.
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.
These changes are needed because I change the
UseOrCreateObject
. The decoder uses the passed ininto
object instead of creating a new one. In turn the versioning decoder skips the conversion so the gvk is kept. I think this behavior is an innocuous bug.