garbagecollector.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package garbagecollector
  14. import (
  15. "fmt"
  16. "sync"
  17. "time"
  18. "github.com/golang/glog"
  19. "k8s.io/kubernetes/pkg/api"
  20. "k8s.io/kubernetes/pkg/api/errors"
  21. "k8s.io/kubernetes/pkg/api/meta"
  22. "k8s.io/kubernetes/pkg/api/meta/metatypes"
  23. "k8s.io/kubernetes/pkg/api/unversioned"
  24. "k8s.io/kubernetes/pkg/api/v1"
  25. "k8s.io/kubernetes/pkg/apimachinery/registered"
  26. "k8s.io/kubernetes/pkg/client/cache"
  27. "k8s.io/kubernetes/pkg/client/typed/dynamic"
  28. "k8s.io/kubernetes/pkg/controller/framework"
  29. "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
  30. "k8s.io/kubernetes/pkg/runtime"
  31. "k8s.io/kubernetes/pkg/types"
  32. "k8s.io/kubernetes/pkg/util/clock"
  33. utilerrors "k8s.io/kubernetes/pkg/util/errors"
  34. utilruntime "k8s.io/kubernetes/pkg/util/runtime"
  35. "k8s.io/kubernetes/pkg/util/sets"
  36. "k8s.io/kubernetes/pkg/util/wait"
  37. "k8s.io/kubernetes/pkg/util/workqueue"
  38. "k8s.io/kubernetes/pkg/watch"
  39. )
  40. const ResourceResyncTime time.Duration = 0
  41. type monitor struct {
  42. store cache.Store
  43. controller *framework.Controller
  44. }
  45. type objectReference struct {
  46. metatypes.OwnerReference
  47. // This is needed by the dynamic client
  48. Namespace string
  49. }
  50. func (s objectReference) String() string {
  51. return fmt.Sprintf("[%s/%s, namespace: %s, name: %s, uid: %s]", s.APIVersion, s.Kind, s.Namespace, s.Name, s.UID)
  52. }
  53. // node does not require a lock to protect. The single-threaded
  54. // Propagator.processEvent() is the sole writer of the nodes. The multi-threaded
  55. // GarbageCollector.processItem() reads the nodes, but it only reads the fields
  56. // that never get changed by Propagator.processEvent().
  57. type node struct {
  58. identity objectReference
  59. // dependents will be read by the orphan() routine, we need to protect it with a lock.
  60. dependentsLock sync.RWMutex
  61. dependents map[*node]struct{}
  62. // When processing an Update event, we need to compare the updated
  63. // ownerReferences with the owners recorded in the graph.
  64. owners []metatypes.OwnerReference
  65. }
  66. func (ownerNode *node) addDependent(dependent *node) {
  67. ownerNode.dependentsLock.Lock()
  68. defer ownerNode.dependentsLock.Unlock()
  69. ownerNode.dependents[dependent] = struct{}{}
  70. }
  71. func (ownerNode *node) deleteDependent(dependent *node) {
  72. ownerNode.dependentsLock.Lock()
  73. defer ownerNode.dependentsLock.Unlock()
  74. delete(ownerNode.dependents, dependent)
  75. }
  76. type eventType int
  77. const (
  78. addEvent eventType = iota
  79. updateEvent
  80. deleteEvent
  81. )
  82. type event struct {
  83. eventType eventType
  84. obj interface{}
  85. // the update event comes with an old object, but it's not used by the garbage collector.
  86. oldObj interface{}
  87. }
  88. type concurrentUIDToNode struct {
  89. *sync.RWMutex
  90. uidToNode map[types.UID]*node
  91. }
  92. func (m *concurrentUIDToNode) Write(node *node) {
  93. m.Lock()
  94. defer m.Unlock()
  95. m.uidToNode[node.identity.UID] = node
  96. }
  97. func (m *concurrentUIDToNode) Read(uid types.UID) (*node, bool) {
  98. m.RLock()
  99. defer m.RUnlock()
  100. n, ok := m.uidToNode[uid]
  101. return n, ok
  102. }
  103. func (m *concurrentUIDToNode) Delete(uid types.UID) {
  104. m.Lock()
  105. defer m.Unlock()
  106. delete(m.uidToNode, uid)
  107. }
  108. type Propagator struct {
  109. eventQueue *workqueue.TimedWorkQueue
  110. // uidToNode doesn't require a lock to protect, because only the
  111. // single-threaded Propagator.processEvent() reads/writes it.
  112. uidToNode *concurrentUIDToNode
  113. gc *GarbageCollector
  114. }
  115. // addDependentToOwners adds n to owners' dependents list. If the owner does not
  116. // exist in the p.uidToNode yet, a "virtual" node will be created to represent
  117. // the owner. The "virtual" node will be enqueued to the dirtyQueue, so that
  118. // processItem() will verify if the owner exists according to the API server.
  119. func (p *Propagator) addDependentToOwners(n *node, owners []metatypes.OwnerReference) {
  120. for _, owner := range owners {
  121. ownerNode, ok := p.uidToNode.Read(owner.UID)
  122. if !ok {
  123. // Create a "virtual" node in the graph for the owner if it doesn't
  124. // exist in the graph yet. Then enqueue the virtual node into the
  125. // dirtyQueue. The garbage processor will enqueue a virtual delete
  126. // event to delete it from the graph if API server confirms this
  127. // owner doesn't exist.
  128. ownerNode = &node{
  129. identity: objectReference{
  130. OwnerReference: owner,
  131. Namespace: n.identity.Namespace,
  132. },
  133. dependents: make(map[*node]struct{}),
  134. }
  135. glog.V(6).Infof("add virtual node.identity: %s\n\n", ownerNode.identity)
  136. p.uidToNode.Write(ownerNode)
  137. p.gc.dirtyQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: p.gc.clock.Now(), Object: ownerNode})
  138. }
  139. ownerNode.addDependent(n)
  140. }
  141. }
  142. // insertNode insert the node to p.uidToNode; then it finds all owners as listed
  143. // in n.owners, and adds the node to their dependents list.
  144. func (p *Propagator) insertNode(n *node) {
  145. p.uidToNode.Write(n)
  146. p.addDependentToOwners(n, n.owners)
  147. }
  148. // removeDependentFromOwners remove n from owners' dependents list.
  149. func (p *Propagator) removeDependentFromOwners(n *node, owners []metatypes.OwnerReference) {
  150. for _, owner := range owners {
  151. ownerNode, ok := p.uidToNode.Read(owner.UID)
  152. if !ok {
  153. continue
  154. }
  155. ownerNode.deleteDependent(n)
  156. }
  157. }
  158. // removeNode removes the node from p.uidToNode, then finds all
  159. // owners as listed in n.owners, and removes n from their dependents list.
  160. func (p *Propagator) removeNode(n *node) {
  161. p.uidToNode.Delete(n.identity.UID)
  162. p.removeDependentFromOwners(n, n.owners)
  163. }
  164. // TODO: profile this function to see if a naive N^2 algorithm performs better
  165. // when the number of references is small.
  166. func referencesDiffs(old []metatypes.OwnerReference, new []metatypes.OwnerReference) (added []metatypes.OwnerReference, removed []metatypes.OwnerReference) {
  167. oldUIDToRef := make(map[string]metatypes.OwnerReference)
  168. for i := 0; i < len(old); i++ {
  169. oldUIDToRef[string(old[i].UID)] = old[i]
  170. }
  171. oldUIDSet := sets.StringKeySet(oldUIDToRef)
  172. newUIDToRef := make(map[string]metatypes.OwnerReference)
  173. for i := 0; i < len(new); i++ {
  174. newUIDToRef[string(new[i].UID)] = new[i]
  175. }
  176. newUIDSet := sets.StringKeySet(newUIDToRef)
  177. addedUID := newUIDSet.Difference(oldUIDSet)
  178. removedUID := oldUIDSet.Difference(newUIDSet)
  179. for uid := range addedUID {
  180. added = append(added, newUIDToRef[uid])
  181. }
  182. for uid := range removedUID {
  183. removed = append(removed, oldUIDToRef[uid])
  184. }
  185. return added, removed
  186. }
  187. func shouldOrphanDependents(e *event, accessor meta.Object) bool {
  188. // The delta_fifo may combine the creation and update of the object into one
  189. // event, so we need to check AddEvent as well.
  190. if e.oldObj == nil {
  191. if accessor.GetDeletionTimestamp() == nil {
  192. return false
  193. }
  194. } else {
  195. oldAccessor, err := meta.Accessor(e.oldObj)
  196. if err != nil {
  197. utilruntime.HandleError(fmt.Errorf("cannot access oldObj: %v", err))
  198. return false
  199. }
  200. // ignore the event if it's not updating DeletionTimestamp from non-nil to nil.
  201. if accessor.GetDeletionTimestamp() == nil || oldAccessor.GetDeletionTimestamp() != nil {
  202. return false
  203. }
  204. }
  205. finalizers := accessor.GetFinalizers()
  206. for _, finalizer := range finalizers {
  207. if finalizer == api.FinalizerOrphan {
  208. return true
  209. }
  210. }
  211. return false
  212. }
  213. // dependents are copies of pointers to the owner's dependents, they don't need to be locked.
  214. func (gc *GarbageCollector) orhpanDependents(owner objectReference, dependents []*node) error {
  215. var failedDependents []objectReference
  216. var errorsSlice []error
  217. for _, dependent := range dependents {
  218. // the dependent.identity.UID is used as precondition
  219. deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, owner.UID, dependent.identity.UID)
  220. _, err := gc.patchObject(dependent.identity, []byte(deleteOwnerRefPatch))
  221. // note that if the target ownerReference doesn't exist in the
  222. // dependent, strategic merge patch will NOT return an error.
  223. if err != nil && !errors.IsNotFound(err) {
  224. errorsSlice = append(errorsSlice, fmt.Errorf("orphaning %s failed with %v", dependent.identity, err))
  225. }
  226. }
  227. if len(failedDependents) != 0 {
  228. return fmt.Errorf("failed to orphan dependents of owner %s, got errors: %s", owner, utilerrors.NewAggregate(errorsSlice).Error())
  229. }
  230. glog.V(6).Infof("successfully updated all dependents")
  231. return nil
  232. }
  233. // TODO: Using Patch when strategicmerge supports deleting an entry from a
  234. // slice of a base type.
  235. func (gc *GarbageCollector) removeOrphanFinalizer(owner *node) error {
  236. const retries = 5
  237. for count := 0; count < retries; count++ {
  238. ownerObject, err := gc.getObject(owner.identity)
  239. if err != nil {
  240. return fmt.Errorf("cannot finalize owner %s, because cannot get it. The garbage collector will retry later.", owner.identity)
  241. }
  242. accessor, err := meta.Accessor(ownerObject)
  243. if err != nil {
  244. return fmt.Errorf("cannot access the owner object: %v. The garbage collector will retry later.", err)
  245. }
  246. finalizers := accessor.GetFinalizers()
  247. var newFinalizers []string
  248. found := false
  249. for _, f := range finalizers {
  250. if f == api.FinalizerOrphan {
  251. found = true
  252. break
  253. } else {
  254. newFinalizers = append(newFinalizers, f)
  255. }
  256. }
  257. if !found {
  258. glog.V(6).Infof("the orphan finalizer is already removed from object %s", owner.identity)
  259. return nil
  260. }
  261. // remove the owner from dependent's OwnerReferences
  262. ownerObject.SetFinalizers(newFinalizers)
  263. _, err = gc.updateObject(owner.identity, ownerObject)
  264. if err == nil {
  265. return nil
  266. }
  267. if err != nil && !errors.IsConflict(err) {
  268. return fmt.Errorf("cannot update the finalizers of owner %s, with error: %v, tried %d times", owner.identity, err, count+1)
  269. }
  270. // retry if it's a conflict
  271. glog.V(6).Infof("got conflict updating the owner object %s, tried %d times", owner.identity, count+1)
  272. }
  273. return fmt.Errorf("updateMaxRetries(%d) has reached. The garbage collector will retry later for owner %v.", retries, owner.identity)
  274. }
  275. // orphanFinalizer dequeues a node from the orphanQueue, then finds its dependents
  276. // based on the graph maintained by the GC, then removes it from the
  277. // OwnerReferences of its dependents, and finally updates the owner to remove
  278. // the "Orphan" finalizer. The node is add back into the orphanQueue if any of
  279. // these steps fail.
  280. func (gc *GarbageCollector) orphanFinalizer() {
  281. timedItem, quit := gc.orphanQueue.Get()
  282. if quit {
  283. return
  284. }
  285. defer gc.orphanQueue.Done(timedItem)
  286. owner, ok := timedItem.Object.(*node)
  287. if !ok {
  288. utilruntime.HandleError(fmt.Errorf("expect *node, got %#v", timedItem.Object))
  289. }
  290. // we don't need to lock each element, because they never get updated
  291. owner.dependentsLock.RLock()
  292. dependents := make([]*node, 0, len(owner.dependents))
  293. for dependent := range owner.dependents {
  294. dependents = append(dependents, dependent)
  295. }
  296. owner.dependentsLock.RUnlock()
  297. err := gc.orhpanDependents(owner.identity, dependents)
  298. if err != nil {
  299. glog.V(6).Infof("orphanDependents for %s failed with %v", owner.identity, err)
  300. gc.orphanQueue.Add(timedItem)
  301. return
  302. }
  303. // update the owner, remove "orphaningFinalizer" from its finalizers list
  304. err = gc.removeOrphanFinalizer(owner)
  305. if err != nil {
  306. glog.V(6).Infof("removeOrphanFinalizer for %s failed with %v", owner.identity, err)
  307. gc.orphanQueue.Add(timedItem)
  308. }
  309. OrphanProcessingLatency.Observe(sinceInMicroseconds(gc.clock, timedItem.StartTime))
  310. }
  311. // Dequeueing an event from eventQueue, updating graph, populating dirty_queue.
  312. func (p *Propagator) processEvent() {
  313. timedItem, quit := p.eventQueue.Get()
  314. if quit {
  315. return
  316. }
  317. defer p.eventQueue.Done(timedItem)
  318. event, ok := timedItem.Object.(*event)
  319. if !ok {
  320. utilruntime.HandleError(fmt.Errorf("expect a *event, got %v", timedItem.Object))
  321. return
  322. }
  323. obj := event.obj
  324. accessor, err := meta.Accessor(obj)
  325. if err != nil {
  326. utilruntime.HandleError(fmt.Errorf("cannot access obj: %v", err))
  327. return
  328. }
  329. typeAccessor, err := meta.TypeAccessor(obj)
  330. if err != nil {
  331. utilruntime.HandleError(fmt.Errorf("cannot access obj: %v", err))
  332. return
  333. }
  334. glog.V(6).Infof("Propagator process object: %s/%s, namespace %s, name %s, event type %s", typeAccessor.GetAPIVersion(), typeAccessor.GetKind(), accessor.GetNamespace(), accessor.GetName(), event.eventType)
  335. // Check if the node already exsits
  336. existingNode, found := p.uidToNode.Read(accessor.GetUID())
  337. switch {
  338. case (event.eventType == addEvent || event.eventType == updateEvent) && !found:
  339. newNode := &node{
  340. identity: objectReference{
  341. OwnerReference: metatypes.OwnerReference{
  342. APIVersion: typeAccessor.GetAPIVersion(),
  343. Kind: typeAccessor.GetKind(),
  344. UID: accessor.GetUID(),
  345. Name: accessor.GetName(),
  346. },
  347. Namespace: accessor.GetNamespace(),
  348. },
  349. dependents: make(map[*node]struct{}),
  350. owners: accessor.GetOwnerReferences(),
  351. }
  352. p.insertNode(newNode)
  353. // the underlying delta_fifo may combine a creation and deletion into one event
  354. if shouldOrphanDependents(event, accessor) {
  355. glog.V(6).Infof("add %s to the orphanQueue", newNode.identity)
  356. p.gc.orphanQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: p.gc.clock.Now(), Object: newNode})
  357. }
  358. case (event.eventType == addEvent || event.eventType == updateEvent) && found:
  359. // caveat: if GC observes the creation of the dependents later than the
  360. // deletion of the owner, then the orphaning finalizer won't be effective.
  361. if shouldOrphanDependents(event, accessor) {
  362. glog.V(6).Infof("add %s to the orphanQueue", existingNode.identity)
  363. p.gc.orphanQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: p.gc.clock.Now(), Object: existingNode})
  364. }
  365. // add/remove owner refs
  366. added, removed := referencesDiffs(existingNode.owners, accessor.GetOwnerReferences())
  367. if len(added) == 0 && len(removed) == 0 {
  368. glog.V(6).Infof("The updateEvent %#v doesn't change node references, ignore", event)
  369. return
  370. }
  371. // update the node itself
  372. existingNode.owners = accessor.GetOwnerReferences()
  373. // Add the node to its new owners' dependent lists.
  374. p.addDependentToOwners(existingNode, added)
  375. // remove the node from the dependent list of node that are no long in
  376. // the node's owners list.
  377. p.removeDependentFromOwners(existingNode, removed)
  378. case event.eventType == deleteEvent:
  379. if !found {
  380. glog.V(6).Infof("%v doesn't exist in the graph, this shouldn't happen", accessor.GetUID())
  381. return
  382. }
  383. p.removeNode(existingNode)
  384. existingNode.dependentsLock.RLock()
  385. defer existingNode.dependentsLock.RUnlock()
  386. for dep := range existingNode.dependents {
  387. p.gc.dirtyQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: p.gc.clock.Now(), Object: dep})
  388. }
  389. }
  390. EventProcessingLatency.Observe(sinceInMicroseconds(p.gc.clock, timedItem.StartTime))
  391. }
  392. // GarbageCollector is responsible for carrying out cascading deletion, and
  393. // removing ownerReferences from the dependents if the owner is deleted with
  394. // DeleteOptions.OrphanDependents=true.
  395. type GarbageCollector struct {
  396. restMapper meta.RESTMapper
  397. // metaOnlyClientPool uses a special codec, which removes fields except for
  398. // apiVersion, kind, and metadata during decoding.
  399. metaOnlyClientPool dynamic.ClientPool
  400. // clientPool uses the regular dynamicCodec. We need it to update
  401. // finalizers. It can be removed if we support patching finalizers.
  402. clientPool dynamic.ClientPool
  403. dirtyQueue *workqueue.TimedWorkQueue
  404. orphanQueue *workqueue.TimedWorkQueue
  405. monitors []monitor
  406. propagator *Propagator
  407. clock clock.Clock
  408. registeredRateLimiter *RegisteredRateLimiter
  409. registeredRateLimiterForMonitors *RegisteredRateLimiter
  410. // GC caches the owners that do not exist according to the API server.
  411. absentOwnerCache *UIDCache
  412. }
  413. func gcListWatcher(client *dynamic.Client, resource unversioned.GroupVersionResource) *cache.ListWatch {
  414. return &cache.ListWatch{
  415. ListFunc: func(options api.ListOptions) (runtime.Object, error) {
  416. // APIResource.Kind is not used by the dynamic client, so
  417. // leave it empty. We want to list this resource in all
  418. // namespaces if it's namespace scoped, so leave
  419. // APIResource.Namespaced as false is all right.
  420. apiResource := unversioned.APIResource{Name: resource.Resource}
  421. return client.ParameterCodec(dynamic.VersionedParameterEncoderWithV1Fallback).
  422. Resource(&apiResource, api.NamespaceAll).
  423. List(&options)
  424. },
  425. WatchFunc: func(options api.ListOptions) (watch.Interface, error) {
  426. // APIResource.Kind is not used by the dynamic client, so
  427. // leave it empty. We want to list this resource in all
  428. // namespaces if it's namespace scoped, so leave
  429. // APIResource.Namespaced as false is all right.
  430. apiResource := unversioned.APIResource{Name: resource.Resource}
  431. return client.ParameterCodec(dynamic.VersionedParameterEncoderWithV1Fallback).
  432. Resource(&apiResource, api.NamespaceAll).
  433. Watch(&options)
  434. },
  435. }
  436. }
  437. func (gc *GarbageCollector) monitorFor(resource unversioned.GroupVersionResource, kind unversioned.GroupVersionKind) (monitor, error) {
  438. // TODO: consider store in one storage.
  439. glog.V(6).Infof("create storage for resource %s", resource)
  440. var monitor monitor
  441. client, err := gc.metaOnlyClientPool.ClientForGroupVersion(resource.GroupVersion())
  442. if err != nil {
  443. return monitor, err
  444. }
  445. gc.registeredRateLimiterForMonitors.registerIfNotPresent(resource.GroupVersion(), client, "garbage_collector_monitoring")
  446. setObjectTypeMeta := func(obj interface{}) {
  447. runtimeObject, ok := obj.(runtime.Object)
  448. if !ok {
  449. utilruntime.HandleError(fmt.Errorf("expected runtime.Object, got %#v", obj))
  450. }
  451. runtimeObject.GetObjectKind().SetGroupVersionKind(kind)
  452. }
  453. monitor.store, monitor.controller = framework.NewInformer(
  454. gcListWatcher(client, resource),
  455. nil,
  456. ResourceResyncTime,
  457. framework.ResourceEventHandlerFuncs{
  458. // add the event to the propagator's eventQueue.
  459. AddFunc: func(obj interface{}) {
  460. setObjectTypeMeta(obj)
  461. event := &event{
  462. eventType: addEvent,
  463. obj: obj,
  464. }
  465. gc.propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: event})
  466. },
  467. UpdateFunc: func(oldObj, newObj interface{}) {
  468. setObjectTypeMeta(newObj)
  469. event := &event{updateEvent, newObj, oldObj}
  470. gc.propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: event})
  471. },
  472. DeleteFunc: func(obj interface{}) {
  473. // delta fifo may wrap the object in a cache.DeletedFinalStateUnknown, unwrap it
  474. if deletedFinalStateUnknown, ok := obj.(cache.DeletedFinalStateUnknown); ok {
  475. obj = deletedFinalStateUnknown.Obj
  476. }
  477. setObjectTypeMeta(obj)
  478. event := &event{
  479. eventType: deleteEvent,
  480. obj: obj,
  481. }
  482. gc.propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: event})
  483. },
  484. },
  485. )
  486. return monitor, nil
  487. }
  488. var ignoredResources = map[unversioned.GroupVersionResource]struct{}{
  489. unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
  490. unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
  491. unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
  492. unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
  493. unversioned.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {},
  494. unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {},
  495. }
  496. func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) {
  497. gc := &GarbageCollector{
  498. metaOnlyClientPool: metaOnlyClientPool,
  499. clientPool: clientPool,
  500. // TODO: should use a dynamic RESTMapper built from the discovery results.
  501. restMapper: registered.RESTMapper(),
  502. clock: clock.RealClock{},
  503. dirtyQueue: workqueue.NewTimedWorkQueue(),
  504. orphanQueue: workqueue.NewTimedWorkQueue(),
  505. registeredRateLimiter: NewRegisteredRateLimiter(resources),
  506. registeredRateLimiterForMonitors: NewRegisteredRateLimiter(resources),
  507. absentOwnerCache: NewUIDCache(100),
  508. }
  509. gc.propagator = &Propagator{
  510. eventQueue: workqueue.NewTimedWorkQueue(),
  511. uidToNode: &concurrentUIDToNode{
  512. RWMutex: &sync.RWMutex{},
  513. uidToNode: make(map[types.UID]*node),
  514. },
  515. gc: gc,
  516. }
  517. for _, resource := range resources {
  518. if _, ok := ignoredResources[resource]; ok {
  519. glog.V(6).Infof("ignore resource %#v", resource)
  520. continue
  521. }
  522. kind, err := gc.restMapper.KindFor(resource)
  523. if err != nil {
  524. return nil, err
  525. }
  526. monitor, err := gc.monitorFor(resource, kind)
  527. if err != nil {
  528. return nil, err
  529. }
  530. gc.monitors = append(gc.monitors, monitor)
  531. }
  532. return gc, nil
  533. }
  534. func (gc *GarbageCollector) worker() {
  535. timedItem, quit := gc.dirtyQueue.Get()
  536. if quit {
  537. return
  538. }
  539. defer gc.dirtyQueue.Done(timedItem)
  540. err := gc.processItem(timedItem.Object.(*node))
  541. if err != nil {
  542. utilruntime.HandleError(fmt.Errorf("Error syncing item %#v: %v", timedItem.Object, err))
  543. }
  544. DirtyProcessingLatency.Observe(sinceInMicroseconds(gc.clock, timedItem.StartTime))
  545. }
  546. // apiResource consults the REST mapper to translate an <apiVersion, kind,
  547. // namespace> tuple to a unversioned.APIResource struct.
  548. func (gc *GarbageCollector) apiResource(apiVersion, kind string, namespaced bool) (*unversioned.APIResource, error) {
  549. fqKind := unversioned.FromAPIVersionAndKind(apiVersion, kind)
  550. mapping, err := gc.restMapper.RESTMapping(fqKind.GroupKind(), apiVersion)
  551. if err != nil {
  552. return nil, fmt.Errorf("unable to get REST mapping for kind: %s, version: %s", kind, apiVersion)
  553. }
  554. glog.V(6).Infof("map kind %s, version %s to resource %s", kind, apiVersion, mapping.Resource)
  555. resource := unversioned.APIResource{
  556. Name: mapping.Resource,
  557. Namespaced: namespaced,
  558. Kind: kind,
  559. }
  560. return &resource, nil
  561. }
  562. func (gc *GarbageCollector) deleteObject(item objectReference) error {
  563. fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind)
  564. client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion())
  565. gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation")
  566. resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0)
  567. if err != nil {
  568. return err
  569. }
  570. uid := item.UID
  571. preconditions := v1.Preconditions{UID: &uid}
  572. deleteOptions := v1.DeleteOptions{Preconditions: &preconditions}
  573. return client.Resource(resource, item.Namespace).Delete(item.Name, &deleteOptions)
  574. }
  575. func (gc *GarbageCollector) getObject(item objectReference) (*runtime.Unstructured, error) {
  576. fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind)
  577. client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion())
  578. gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation")
  579. resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0)
  580. if err != nil {
  581. return nil, err
  582. }
  583. return client.Resource(resource, item.Namespace).Get(item.Name)
  584. }
  585. func (gc *GarbageCollector) updateObject(item objectReference, obj *runtime.Unstructured) (*runtime.Unstructured, error) {
  586. fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind)
  587. client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion())
  588. gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation")
  589. resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0)
  590. if err != nil {
  591. return nil, err
  592. }
  593. return client.Resource(resource, item.Namespace).Update(obj)
  594. }
  595. func (gc *GarbageCollector) patchObject(item objectReference, patch []byte) (*runtime.Unstructured, error) {
  596. fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind)
  597. client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion())
  598. gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation")
  599. resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0)
  600. if err != nil {
  601. return nil, err
  602. }
  603. return client.Resource(resource, item.Namespace).Patch(item.Name, api.StrategicMergePatchType, patch)
  604. }
  605. func objectReferenceToUnstructured(ref objectReference) *runtime.Unstructured {
  606. ret := &runtime.Unstructured{}
  607. ret.SetKind(ref.Kind)
  608. ret.SetAPIVersion(ref.APIVersion)
  609. ret.SetUID(ref.UID)
  610. ret.SetNamespace(ref.Namespace)
  611. ret.SetName(ref.Name)
  612. return ret
  613. }
  614. func objectReferenceToMetadataOnlyObject(ref objectReference) *metaonly.MetadataOnlyObject {
  615. return &metaonly.MetadataOnlyObject{
  616. TypeMeta: unversioned.TypeMeta{
  617. APIVersion: ref.APIVersion,
  618. Kind: ref.Kind,
  619. },
  620. ObjectMeta: v1.ObjectMeta{
  621. Namespace: ref.Namespace,
  622. UID: ref.UID,
  623. Name: ref.Name,
  624. },
  625. }
  626. }
  627. func (gc *GarbageCollector) processItem(item *node) error {
  628. // Get the latest item from the API server
  629. latest, err := gc.getObject(item.identity)
  630. if err != nil {
  631. if errors.IsNotFound(err) {
  632. // the Propagator can add "virtual" node for an owner that doesn't
  633. // exist yet, so we need to enqueue a virtual Delete event to remove
  634. // the virtual node from Propagator.uidToNode.
  635. glog.V(6).Infof("item %v not found, generating a virtual delete event", item.identity)
  636. event := &event{
  637. eventType: deleteEvent,
  638. obj: objectReferenceToMetadataOnlyObject(item.identity),
  639. }
  640. glog.V(6).Infof("generating virtual delete event for %s\n\n", event.obj)
  641. gc.propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: event})
  642. return nil
  643. }
  644. return err
  645. }
  646. if latest.GetUID() != item.identity.UID {
  647. glog.V(6).Infof("UID doesn't match, item %v not found, generating a virtual delete event", item.identity)
  648. event := &event{
  649. eventType: deleteEvent,
  650. obj: objectReferenceToMetadataOnlyObject(item.identity),
  651. }
  652. glog.V(6).Infof("generating virtual delete event for %s\n\n", event.obj)
  653. gc.propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: event})
  654. return nil
  655. }
  656. ownerReferences := latest.GetOwnerReferences()
  657. if len(ownerReferences) == 0 {
  658. glog.V(6).Infof("object %s's doesn't have an owner, continue on next item", item.identity)
  659. return nil
  660. }
  661. // TODO: we need to remove dangling references if the object is not to be
  662. // deleted.
  663. for _, reference := range ownerReferences {
  664. if gc.absentOwnerCache.Has(reference.UID) {
  665. glog.V(6).Infof("according to the absentOwnerCache, object %s's owner %s/%s, %s does not exist", item.identity.UID, reference.APIVersion, reference.Kind, reference.Name)
  666. continue
  667. }
  668. // TODO: we need to verify the reference resource is supported by the
  669. // system. If it's not a valid resource, the garbage collector should i)
  670. // ignore the reference when decide if the object should be deleted, and
  671. // ii) should update the object to remove such references. This is to
  672. // prevent objects having references to an old resource from being
  673. // deleted during a cluster upgrade.
  674. fqKind := unversioned.FromAPIVersionAndKind(reference.APIVersion, reference.Kind)
  675. client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion())
  676. if err != nil {
  677. return err
  678. }
  679. resource, err := gc.apiResource(reference.APIVersion, reference.Kind, len(item.identity.Namespace) != 0)
  680. if err != nil {
  681. return err
  682. }
  683. owner, err := client.Resource(resource, item.identity.Namespace).Get(reference.Name)
  684. if err == nil {
  685. if owner.GetUID() != reference.UID {
  686. glog.V(6).Infof("object %s's owner %s/%s, %s is not found, UID mismatch", item.identity.UID, reference.APIVersion, reference.Kind, reference.Name)
  687. gc.absentOwnerCache.Add(reference.UID)
  688. continue
  689. }
  690. glog.V(6).Infof("object %s has at least an existing owner, will not garbage collect", item.identity.UID)
  691. return nil
  692. } else if errors.IsNotFound(err) {
  693. gc.absentOwnerCache.Add(reference.UID)
  694. glog.V(6).Infof("object %s's owner %s/%s, %s is not found", item.identity.UID, reference.APIVersion, reference.Kind, reference.Name)
  695. } else {
  696. return err
  697. }
  698. }
  699. glog.V(2).Infof("none of object %s's owners exist any more, will garbage collect it", item.identity)
  700. return gc.deleteObject(item.identity)
  701. }
  702. func (gc *GarbageCollector) Run(workers int, stopCh <-chan struct{}) {
  703. glog.Infof("Garbage Collector: Initializing")
  704. for _, monitor := range gc.monitors {
  705. go monitor.controller.Run(stopCh)
  706. }
  707. wait.PollInfinite(10*time.Second, func() (bool, error) {
  708. for _, monitor := range gc.monitors {
  709. if !monitor.controller.HasSynced() {
  710. glog.Infof("Garbage Collector: Waiting for resource monitors to be synced...")
  711. return false, nil
  712. }
  713. }
  714. return true, nil
  715. })
  716. glog.Infof("Garbage Collector: All monitored resources synced. Proceeding to collect garbage")
  717. // worker
  718. go wait.Until(gc.propagator.processEvent, 0, stopCh)
  719. for i := 0; i < workers; i++ {
  720. go wait.Until(gc.worker, 0, stopCh)
  721. go wait.Until(gc.orphanFinalizer, 0, stopCh)
  722. }
  723. Register()
  724. <-stopCh
  725. glog.Infof("Garbage Collector: Shutting down")
  726. gc.dirtyQueue.ShutDown()
  727. gc.orphanQueue.ShutDown()
  728. gc.propagator.eventQueue.ShutDown()
  729. }
  730. // QueueDrained returns if the dirtyQueue and eventQueue are drained. It's
  731. // useful for debugging. Note that it doesn't guarantee the workers are idle.
  732. func (gc *GarbageCollector) QueuesDrained() bool {
  733. return gc.dirtyQueue.Len() == 0 && gc.propagator.eventQueue.Len() == 0 && gc.orphanQueue.Len() == 0
  734. }
  735. // *FOR TEST USE ONLY* It's not safe to call this function when the GC is still
  736. // busy.
  737. // GraphHasUID returns if the Propagator has a particular UID store in its
  738. // uidToNode graph. It's useful for debugging.
  739. func (gc *GarbageCollector) GraphHasUID(UIDs []types.UID) bool {
  740. for _, u := range UIDs {
  741. if _, ok := gc.propagator.uidToNode.Read(u); ok {
  742. return true
  743. }
  744. }
  745. return false
  746. }