-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Ticket https://github.com/crossplane/crossplane/issues/2435 was opened a due to a leak of resources in AWS.
Multiple reasons for the leak were found. One of the reasons is a caching/concurrency problem in controller-runtime.
In the above ticket the caching/concurrency problem involved an AWS route table managed resource. Reconcile created an additional one in AWS because after it had set the external name it was asked to Reconcile again when the cache had an out of date instance of the route table, one where external-name hasn't been set yet. This happened despite the use of HasSynced in specificInformersMap::Get.
These comments to the ticket give the details of how this is happening
https://github.com/crossplane/crossplane/issues/2435#issuecomment-891318989
https://github.com/crossplane/crossplane/issues/2435#issuecomment-890462636
https://github.com/crossplane/crossplane/issues/2435#issuecomment-890424587
A couple of 'band-aid' fixes would be to
- Get AWS to update their API so that the route table creation would allow the user to supply the unique id
- Update ResolveReferences to return an indication of whether the resources was updated or not in addition to returning an error.
The first would only solve the problem for AWS route tables which isn't ideal.
The second would only solve the problem when the additional Reconcile, the one where an additional resource in AWS is created, is the result of reference resolution. However since updates to the managed resource object in the API server could come from anywhere this also isn't ideal.
A write-back cache would provide a complete solution. Here is an outline of the changes I think are required.
== client-go ==
These changes just make it so cache mutation continues to work as expected.
- In
shared_informer.goaddindexerwhich embedsIndexer.
MovecacheMutationDetectorfromsharedIndexInformertoindexer.
indexerwill wrap calls toAdd,UpdateandReplace. The wrapper methods will forward the passed in object tocacheMutationDetectorbefore the object to the appropriate method of the embeddedIndexer.
NOTE: This plugs a gap in the current cache mutation detection that exists today. Today detection only is performed on objects added to the cache viasharedIndexInformer::HandleDeltas. - In
shared_informer.goremovecacheMutationDetectorfromsharedIndexInformer. Change construction ofsharedIndexInformerto useindexermentioned above.
== controller-runtime ==
- Add
CacheUpdaterwhich is similar toCacheReaderdefined incache_reader.go.
It only has anUpdatemethod which forwards its parameters toindexer.Update. - Add
Updatermethod toMapEntry. - Update
addInformerToMapin so it setsUpdaterofMapEntry. - Add
Updaterinterface tointerfaces.go. This just hasUpdatemethod identical to the one on theWriterinterface. - Add
Updatemethod toinformerCache. which will be similarGetetc. - Update interface
Cachein cache.go so it embeds aboveUpdater. - Add
cacheWriteBAckstruct similar todelegatingReader. It will embed Writer and it will have to the cache and theuncachedGVKs. It will forward calls toWriterfirst and if those succeed and, ifuncachedGVKsdoesn't indicate otherwise, callUpdateon thecache, passing the updated object from the server. - Update
NewDelegatingClientso that constructs adelegatingClientwith acacheWriteThroughfor the writer.