garbage_collector_test.go 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /*
  2. Copyright 2015 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. "context"
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. "sync"
  20. "testing"
  21. "time"
  22. v1 "k8s.io/api/core/v1"
  23. apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
  24. apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
  25. apiextensionstestserver "k8s.io/apiextensions-apiserver/test/integration/fixtures"
  26. apierrors "k8s.io/apimachinery/pkg/api/errors"
  27. "k8s.io/apimachinery/pkg/api/meta"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  29. "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  30. "k8s.io/apimachinery/pkg/runtime/schema"
  31. "k8s.io/apimachinery/pkg/types"
  32. "k8s.io/apimachinery/pkg/util/wait"
  33. "k8s.io/apiserver/pkg/storage/names"
  34. cacheddiscovery "k8s.io/client-go/discovery/cached/memory"
  35. "k8s.io/client-go/dynamic"
  36. "k8s.io/client-go/informers"
  37. clientset "k8s.io/client-go/kubernetes"
  38. "k8s.io/client-go/metadata"
  39. "k8s.io/client-go/metadata/metadatainformer"
  40. "k8s.io/client-go/restmapper"
  41. "k8s.io/client-go/tools/cache"
  42. kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
  43. "k8s.io/kubernetes/pkg/controller"
  44. "k8s.io/kubernetes/pkg/controller/garbagecollector"
  45. "k8s.io/kubernetes/test/integration"
  46. "k8s.io/kubernetes/test/integration/framework"
  47. )
  48. func getForegroundOptions() *metav1.DeleteOptions {
  49. policy := metav1.DeletePropagationForeground
  50. return &metav1.DeleteOptions{PropagationPolicy: &policy}
  51. }
  52. func getOrphanOptions() *metav1.DeleteOptions {
  53. var trueVar = true
  54. return &metav1.DeleteOptions{OrphanDependents: &trueVar}
  55. }
  56. func getPropagateOrphanOptions() *metav1.DeleteOptions {
  57. policy := metav1.DeletePropagationOrphan
  58. return &metav1.DeleteOptions{PropagationPolicy: &policy}
  59. }
  60. func getNonOrphanOptions() *metav1.DeleteOptions {
  61. var falseVar = false
  62. return &metav1.DeleteOptions{OrphanDependents: &falseVar}
  63. }
  64. const garbageCollectedPodName = "test.pod.1"
  65. const independentPodName = "test.pod.2"
  66. const oneValidOwnerPodName = "test.pod.3"
  67. const toBeDeletedRCName = "test.rc.1"
  68. const remainingRCName = "test.rc.2"
  69. func newPod(podName, podNamespace string, ownerReferences []metav1.OwnerReference) *v1.Pod {
  70. for i := 0; i < len(ownerReferences); i++ {
  71. if len(ownerReferences[i].Kind) == 0 {
  72. ownerReferences[i].Kind = "ReplicationController"
  73. }
  74. ownerReferences[i].APIVersion = "v1"
  75. }
  76. return &v1.Pod{
  77. TypeMeta: metav1.TypeMeta{
  78. Kind: "Pod",
  79. APIVersion: "v1",
  80. },
  81. ObjectMeta: metav1.ObjectMeta{
  82. Name: podName,
  83. Namespace: podNamespace,
  84. OwnerReferences: ownerReferences,
  85. },
  86. Spec: v1.PodSpec{
  87. Containers: []v1.Container{
  88. {
  89. Name: "fake-name",
  90. Image: "fakeimage",
  91. },
  92. },
  93. },
  94. }
  95. }
  96. func newOwnerRC(name, namespace string) *v1.ReplicationController {
  97. return &v1.ReplicationController{
  98. TypeMeta: metav1.TypeMeta{
  99. Kind: "ReplicationController",
  100. APIVersion: "v1",
  101. },
  102. ObjectMeta: metav1.ObjectMeta{
  103. Namespace: namespace,
  104. Name: name,
  105. },
  106. Spec: v1.ReplicationControllerSpec{
  107. Selector: map[string]string{"name": "test"},
  108. Template: &v1.PodTemplateSpec{
  109. ObjectMeta: metav1.ObjectMeta{
  110. Labels: map[string]string{"name": "test"},
  111. },
  112. Spec: v1.PodSpec{
  113. Containers: []v1.Container{
  114. {
  115. Name: "fake-name",
  116. Image: "fakeimage",
  117. },
  118. },
  119. },
  120. },
  121. },
  122. }
  123. }
  124. func newCRDInstance(definition *apiextensionsv1beta1.CustomResourceDefinition, namespace, name string) *unstructured.Unstructured {
  125. return &unstructured.Unstructured{
  126. Object: map[string]interface{}{
  127. "kind": definition.Spec.Names.Kind,
  128. "apiVersion": definition.Spec.Group + "/" + definition.Spec.Version,
  129. "metadata": map[string]interface{}{
  130. "name": name,
  131. "namespace": namespace,
  132. },
  133. },
  134. }
  135. }
  136. func newConfigMap(namespace, name string) *v1.ConfigMap {
  137. return &v1.ConfigMap{
  138. TypeMeta: metav1.TypeMeta{
  139. Kind: "ConfigMap",
  140. APIVersion: "v1",
  141. },
  142. ObjectMeta: metav1.ObjectMeta{
  143. Namespace: namespace,
  144. Name: name,
  145. },
  146. }
  147. }
  148. func link(t *testing.T, owner, dependent metav1.Object) {
  149. ownerType, err := meta.TypeAccessor(owner)
  150. if err != nil {
  151. t.Fatalf("failed to get type info for %#v: %v", owner, err)
  152. }
  153. ref := metav1.OwnerReference{
  154. Kind: ownerType.GetKind(),
  155. APIVersion: ownerType.GetAPIVersion(),
  156. Name: owner.GetName(),
  157. UID: owner.GetUID(),
  158. }
  159. dependent.SetOwnerReferences(append(dependent.GetOwnerReferences(), ref))
  160. }
  161. func createRandomCustomResourceDefinition(
  162. t *testing.T, apiExtensionClient apiextensionsclientset.Interface,
  163. dynamicClient dynamic.Interface,
  164. namespace string,
  165. ) (*apiextensionsv1beta1.CustomResourceDefinition, dynamic.ResourceInterface) {
  166. // Create a random custom resource definition and ensure it's available for
  167. // use.
  168. definition := apiextensionstestserver.NewRandomNameCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
  169. definition, err := apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
  170. if err != nil {
  171. t.Fatalf("failed to create CustomResourceDefinition: %v", err)
  172. }
  173. // Get a client for the custom resource.
  174. gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: definition.Spec.Version, Resource: definition.Spec.Names.Plural}
  175. resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
  176. return definition, resourceClient
  177. }
  178. type testContext struct {
  179. tearDown func()
  180. gc *garbagecollector.GarbageCollector
  181. clientSet clientset.Interface
  182. apiExtensionClient apiextensionsclientset.Interface
  183. dynamicClient dynamic.Interface
  184. metadataClient metadata.Interface
  185. startGC func(workers int)
  186. // syncPeriod is how often the GC started with startGC will be resynced.
  187. syncPeriod time.Duration
  188. }
  189. // if workerCount > 0, will start the GC, otherwise it's up to the caller to Run() the GC.
  190. func setup(t *testing.T, workerCount int) *testContext {
  191. return setupWithServer(t, kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd()), workerCount)
  192. }
  193. func setupWithServer(t *testing.T, result *kubeapiservertesting.TestServer, workerCount int) *testContext {
  194. clientSet, err := clientset.NewForConfig(result.ClientConfig)
  195. if err != nil {
  196. t.Fatalf("error creating clientset: %v", err)
  197. }
  198. // Helpful stuff for testing CRD.
  199. apiExtensionClient, err := apiextensionsclientset.NewForConfig(result.ClientConfig)
  200. if err != nil {
  201. t.Fatalf("error creating extension clientset: %v", err)
  202. }
  203. // CreateNewCustomResourceDefinition wants to use this namespace for verifying
  204. // namespace-scoped CRD creation.
  205. createNamespaceOrDie("aval", clientSet, t)
  206. discoveryClient := cacheddiscovery.NewMemCacheClient(clientSet.Discovery())
  207. restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
  208. restMapper.Reset()
  209. deletableResources := garbagecollector.GetDeletableResources(discoveryClient)
  210. config := *result.ClientConfig
  211. metadataClient, err := metadata.NewForConfig(&config)
  212. if err != nil {
  213. t.Fatalf("failed to create metadataClient: %v", err)
  214. }
  215. dynamicClient, err := dynamic.NewForConfig(&config)
  216. if err != nil {
  217. t.Fatalf("failed to create dynamicClient: %v", err)
  218. }
  219. sharedInformers := informers.NewSharedInformerFactory(clientSet, 0)
  220. metadataInformers := metadatainformer.NewSharedInformerFactory(metadataClient, 0)
  221. alwaysStarted := make(chan struct{})
  222. close(alwaysStarted)
  223. gc, err := garbagecollector.NewGarbageCollector(
  224. metadataClient,
  225. restMapper,
  226. deletableResources,
  227. garbagecollector.DefaultIgnoredResources(),
  228. controller.NewInformerFactory(sharedInformers, metadataInformers),
  229. alwaysStarted,
  230. )
  231. if err != nil {
  232. t.Fatalf("failed to create garbage collector: %v", err)
  233. }
  234. stopCh := make(chan struct{})
  235. tearDown := func() {
  236. close(stopCh)
  237. result.TearDownFn()
  238. }
  239. syncPeriod := 5 * time.Second
  240. startGC := func(workers int) {
  241. go wait.Until(func() {
  242. // Resetting the REST mapper will also invalidate the underlying discovery
  243. // client. This is a leaky abstraction and assumes behavior about the REST
  244. // mapper, but we'll deal with it for now.
  245. restMapper.Reset()
  246. }, syncPeriod, stopCh)
  247. go gc.Run(workers, stopCh)
  248. go gc.Sync(clientSet.Discovery(), syncPeriod, stopCh)
  249. }
  250. if workerCount > 0 {
  251. startGC(workerCount)
  252. }
  253. return &testContext{
  254. tearDown: tearDown,
  255. gc: gc,
  256. clientSet: clientSet,
  257. apiExtensionClient: apiExtensionClient,
  258. dynamicClient: dynamicClient,
  259. metadataClient: metadataClient,
  260. startGC: startGC,
  261. syncPeriod: syncPeriod,
  262. }
  263. }
  264. func createNamespaceOrDie(name string, c clientset.Interface, t *testing.T) *v1.Namespace {
  265. ns := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}}
  266. if _, err := c.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}); err != nil {
  267. t.Fatalf("failed to create namespace: %v", err)
  268. }
  269. falseVar := false
  270. _, err := c.CoreV1().ServiceAccounts(ns.Name).Create(context.TODO(), &v1.ServiceAccount{
  271. ObjectMeta: metav1.ObjectMeta{Name: "default"},
  272. AutomountServiceAccountToken: &falseVar,
  273. }, metav1.CreateOptions{})
  274. if err != nil {
  275. t.Fatalf("failed to create service account: %v", err)
  276. }
  277. return ns
  278. }
  279. func deleteNamespaceOrDie(name string, c clientset.Interface, t *testing.T) {
  280. zero := int64(0)
  281. background := metav1.DeletePropagationBackground
  282. err := c.CoreV1().Namespaces().Delete(context.TODO(), name, &metav1.DeleteOptions{GracePeriodSeconds: &zero, PropagationPolicy: &background})
  283. if err != nil {
  284. t.Fatalf("failed to delete namespace %q: %v", name, err)
  285. }
  286. }
  287. // This test simulates the cascading deletion.
  288. func TestCascadingDeletion(t *testing.T) {
  289. ctx := setup(t, 5)
  290. defer ctx.tearDown()
  291. gc, clientSet := ctx.gc, ctx.clientSet
  292. ns := createNamespaceOrDie("gc-cascading-deletion", clientSet, t)
  293. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  294. rcClient := clientSet.CoreV1().ReplicationControllers(ns.Name)
  295. podClient := clientSet.CoreV1().Pods(ns.Name)
  296. toBeDeletedRC, err := rcClient.Create(context.TODO(), newOwnerRC(toBeDeletedRCName, ns.Name), metav1.CreateOptions{})
  297. if err != nil {
  298. t.Fatalf("Failed to create replication controller: %v", err)
  299. }
  300. remainingRC, err := rcClient.Create(context.TODO(), newOwnerRC(remainingRCName, ns.Name), metav1.CreateOptions{})
  301. if err != nil {
  302. t.Fatalf("Failed to create replication controller: %v", err)
  303. }
  304. rcs, err := rcClient.List(context.TODO(), metav1.ListOptions{})
  305. if err != nil {
  306. t.Fatalf("Failed to list replication controllers: %v", err)
  307. }
  308. if len(rcs.Items) != 2 {
  309. t.Fatalf("Expect only 2 replication controller")
  310. }
  311. // this pod should be cascadingly deleted.
  312. pod := newPod(garbageCollectedPodName, ns.Name, []metav1.OwnerReference{{UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRCName}})
  313. _, err = podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  314. if err != nil {
  315. t.Fatalf("Failed to create Pod: %v", err)
  316. }
  317. // this pod shouldn't be cascadingly deleted, because it has a valid reference.
  318. pod = newPod(oneValidOwnerPodName, ns.Name, []metav1.OwnerReference{
  319. {UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRCName},
  320. {UID: remainingRC.ObjectMeta.UID, Name: remainingRCName},
  321. })
  322. _, err = podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  323. if err != nil {
  324. t.Fatalf("Failed to create Pod: %v", err)
  325. }
  326. // this pod shouldn't be cascadingly deleted, because it doesn't have an owner.
  327. pod = newPod(independentPodName, ns.Name, []metav1.OwnerReference{})
  328. _, err = podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  329. if err != nil {
  330. t.Fatalf("Failed to create Pod: %v", err)
  331. }
  332. // set up watch
  333. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  334. if err != nil {
  335. t.Fatalf("Failed to list pods: %v", err)
  336. }
  337. if len(pods.Items) != 3 {
  338. t.Fatalf("Expect only 3 pods")
  339. }
  340. // delete one of the replication controller
  341. if err := rcClient.Delete(context.TODO(), toBeDeletedRCName, getNonOrphanOptions()); err != nil {
  342. t.Fatalf("failed to delete replication controller: %v", err)
  343. }
  344. // sometimes the deletion of the RC takes long time to be observed by
  345. // the gc, so wait for the garbage collector to observe the deletion of
  346. // the toBeDeletedRC
  347. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  348. return !gc.GraphHasUID(toBeDeletedRC.ObjectMeta.UID), nil
  349. }); err != nil {
  350. t.Fatal(err)
  351. }
  352. if err := integration.WaitForPodToDisappear(podClient, garbageCollectedPodName, 1*time.Second, 30*time.Second); err != nil {
  353. t.Fatalf("expect pod %s to be garbage collected, got err= %v", garbageCollectedPodName, err)
  354. }
  355. // checks the garbage collect doesn't delete pods it shouldn't delete.
  356. if _, err := podClient.Get(context.TODO(), independentPodName, metav1.GetOptions{}); err != nil {
  357. t.Fatal(err)
  358. }
  359. if _, err := podClient.Get(context.TODO(), oneValidOwnerPodName, metav1.GetOptions{}); err != nil {
  360. t.Fatal(err)
  361. }
  362. }
  363. // This test simulates the case where an object is created with an owner that
  364. // doesn't exist. It verifies the GC will delete such an object.
  365. func TestCreateWithNonExistentOwner(t *testing.T) {
  366. ctx := setup(t, 5)
  367. defer ctx.tearDown()
  368. clientSet := ctx.clientSet
  369. ns := createNamespaceOrDie("gc-non-existing-owner", clientSet, t)
  370. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  371. podClient := clientSet.CoreV1().Pods(ns.Name)
  372. pod := newPod(garbageCollectedPodName, ns.Name, []metav1.OwnerReference{{UID: "doesn't matter", Name: toBeDeletedRCName}})
  373. _, err := podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  374. if err != nil {
  375. t.Fatalf("Failed to create Pod: %v", err)
  376. }
  377. // set up watch
  378. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  379. if err != nil {
  380. t.Fatalf("Failed to list pods: %v", err)
  381. }
  382. if len(pods.Items) > 1 {
  383. t.Fatalf("Unexpected pod list: %v", pods.Items)
  384. }
  385. // wait for the garbage collector to delete the pod
  386. if err := integration.WaitForPodToDisappear(podClient, garbageCollectedPodName, 1*time.Second, 30*time.Second); err != nil {
  387. t.Fatalf("expect pod %s to be garbage collected, got err= %v", garbageCollectedPodName, err)
  388. }
  389. }
  390. func setupRCsPods(t *testing.T, gc *garbagecollector.GarbageCollector, clientSet clientset.Interface, nameSuffix, namespace string, initialFinalizers []string, options *metav1.DeleteOptions, wg *sync.WaitGroup, rcUIDs chan types.UID) {
  391. defer wg.Done()
  392. rcClient := clientSet.CoreV1().ReplicationControllers(namespace)
  393. podClient := clientSet.CoreV1().Pods(namespace)
  394. // create rc.
  395. rcName := "test.rc." + nameSuffix
  396. rc := newOwnerRC(rcName, namespace)
  397. rc.ObjectMeta.Finalizers = initialFinalizers
  398. rc, err := rcClient.Create(context.TODO(), rc, metav1.CreateOptions{})
  399. if err != nil {
  400. t.Fatalf("Failed to create replication controller: %v", err)
  401. }
  402. rcUIDs <- rc.ObjectMeta.UID
  403. // create pods.
  404. var podUIDs []types.UID
  405. for j := 0; j < 3; j++ {
  406. podName := "test.pod." + nameSuffix + "-" + strconv.Itoa(j)
  407. pod := newPod(podName, namespace, []metav1.OwnerReference{{UID: rc.ObjectMeta.UID, Name: rc.ObjectMeta.Name}})
  408. createdPod, err := podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  409. if err != nil {
  410. t.Fatalf("Failed to create Pod: %v", err)
  411. }
  412. podUIDs = append(podUIDs, createdPod.ObjectMeta.UID)
  413. }
  414. orphan := false
  415. switch {
  416. case options == nil:
  417. // if there are no deletion options, the default policy for replication controllers is orphan
  418. orphan = true
  419. case options.OrphanDependents != nil:
  420. // if the deletion options explicitly specify whether to orphan, that controls
  421. orphan = *options.OrphanDependents
  422. case options.PropagationPolicy != nil:
  423. // if the deletion options explicitly specify whether to orphan, that controls
  424. orphan = *options.PropagationPolicy == metav1.DeletePropagationOrphan
  425. case len(initialFinalizers) != 0 && initialFinalizers[0] == metav1.FinalizerOrphanDependents:
  426. // if the orphan finalizer is explicitly added, we orphan
  427. orphan = true
  428. }
  429. // if we intend to orphan the pods, we need wait for the gc to observe the
  430. // creation of the pods, otherwise if the deletion of RC is observed before
  431. // the creation of the pods, the pods will not be orphaned.
  432. if orphan {
  433. err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  434. for _, u := range podUIDs {
  435. if !gc.GraphHasUID(u) {
  436. return false, nil
  437. }
  438. }
  439. return true, nil
  440. })
  441. if err != nil {
  442. t.Fatalf("failed to observe the expected pods in the GC graph for rc %s", rcName)
  443. }
  444. }
  445. // delete the rc
  446. if err := rcClient.Delete(context.TODO(), rc.ObjectMeta.Name, options); err != nil {
  447. t.Fatalf("failed to delete replication controller: %v", err)
  448. }
  449. }
  450. func verifyRemainingObjects(t *testing.T, clientSet clientset.Interface, namespace string, rcNum, podNum int) (bool, error) {
  451. rcClient := clientSet.CoreV1().ReplicationControllers(namespace)
  452. podClient := clientSet.CoreV1().Pods(namespace)
  453. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  454. if err != nil {
  455. return false, fmt.Errorf("Failed to list pods: %v", err)
  456. }
  457. var ret = true
  458. if len(pods.Items) != podNum {
  459. ret = false
  460. t.Logf("expect %d pods, got %d pods", podNum, len(pods.Items))
  461. }
  462. rcs, err := rcClient.List(context.TODO(), metav1.ListOptions{})
  463. if err != nil {
  464. return false, fmt.Errorf("Failed to list replication controllers: %v", err)
  465. }
  466. if len(rcs.Items) != rcNum {
  467. ret = false
  468. t.Logf("expect %d RCs, got %d RCs", rcNum, len(rcs.Items))
  469. }
  470. return ret, nil
  471. }
  472. // The stress test is not very stressful, because we need to control the running
  473. // time of our pre-submit tests to increase submit-queue throughput. We'll add
  474. // e2e tests that put more stress.
  475. func TestStressingCascadingDeletion(t *testing.T) {
  476. ctx := setup(t, 5)
  477. defer ctx.tearDown()
  478. gc, clientSet := ctx.gc, ctx.clientSet
  479. ns := createNamespaceOrDie("gc-stressing-cascading-deletion", clientSet, t)
  480. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  481. const collections = 10
  482. var wg sync.WaitGroup
  483. wg.Add(collections * 5)
  484. rcUIDs := make(chan types.UID, collections*5)
  485. for i := 0; i < collections; i++ {
  486. // rc is created with empty finalizers, deleted with nil delete options, pods will remain.
  487. go setupRCsPods(t, gc, clientSet, "collection1-"+strconv.Itoa(i), ns.Name, []string{}, nil, &wg, rcUIDs)
  488. // rc is created with the orphan finalizer, deleted with nil options, pods will remain.
  489. go setupRCsPods(t, gc, clientSet, "collection2-"+strconv.Itoa(i), ns.Name, []string{metav1.FinalizerOrphanDependents}, nil, &wg, rcUIDs)
  490. // rc is created with the orphan finalizer, deleted with DeleteOptions.OrphanDependents=false, pods will be deleted.
  491. go setupRCsPods(t, gc, clientSet, "collection3-"+strconv.Itoa(i), ns.Name, []string{metav1.FinalizerOrphanDependents}, getNonOrphanOptions(), &wg, rcUIDs)
  492. // rc is created with empty finalizers, deleted with DeleteOptions.OrphanDependents=true, pods will remain.
  493. go setupRCsPods(t, gc, clientSet, "collection4-"+strconv.Itoa(i), ns.Name, []string{}, getOrphanOptions(), &wg, rcUIDs)
  494. // rc is created with empty finalizers, deleted with DeleteOptions.PropagationPolicy=Orphan, pods will remain.
  495. go setupRCsPods(t, gc, clientSet, "collection5-"+strconv.Itoa(i), ns.Name, []string{}, getPropagateOrphanOptions(), &wg, rcUIDs)
  496. }
  497. wg.Wait()
  498. t.Logf("all pods are created, all replications controllers are created then deleted")
  499. // wait for the RCs and Pods to reach the expected numbers.
  500. if err := wait.Poll(1*time.Second, 300*time.Second, func() (bool, error) {
  501. podsInEachCollection := 3
  502. // see the comments on the calls to setupRCsPods for details
  503. remainingGroups := 4
  504. return verifyRemainingObjects(t, clientSet, ns.Name, 0, collections*podsInEachCollection*remainingGroups)
  505. }); err != nil {
  506. t.Fatal(err)
  507. }
  508. t.Logf("number of remaining replication controllers and pods are as expected")
  509. // verify the remaining pods all have "orphan" in their names.
  510. podClient := clientSet.CoreV1().Pods(ns.Name)
  511. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  512. if err != nil {
  513. t.Fatal(err)
  514. }
  515. for _, pod := range pods.Items {
  516. if !strings.Contains(pod.ObjectMeta.Name, "collection1-") && !strings.Contains(pod.ObjectMeta.Name, "collection2-") && !strings.Contains(pod.ObjectMeta.Name, "collection4-") && !strings.Contains(pod.ObjectMeta.Name, "collection5-") {
  517. t.Errorf("got unexpected remaining pod: %#v", pod)
  518. }
  519. }
  520. // verify there is no node representing replication controllers in the gc's graph
  521. for i := 0; i < collections; i++ {
  522. uid := <-rcUIDs
  523. if gc.GraphHasUID(uid) {
  524. t.Errorf("Expect all nodes representing replication controllers are removed from the Propagator's graph")
  525. }
  526. }
  527. }
  528. func TestOrphaning(t *testing.T) {
  529. ctx := setup(t, 5)
  530. defer ctx.tearDown()
  531. gc, clientSet := ctx.gc, ctx.clientSet
  532. ns := createNamespaceOrDie("gc-orphaning", clientSet, t)
  533. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  534. podClient := clientSet.CoreV1().Pods(ns.Name)
  535. rcClient := clientSet.CoreV1().ReplicationControllers(ns.Name)
  536. // create the RC with the orphan finalizer set
  537. toBeDeletedRC := newOwnerRC(toBeDeletedRCName, ns.Name)
  538. toBeDeletedRC, err := rcClient.Create(context.TODO(), toBeDeletedRC, metav1.CreateOptions{})
  539. if err != nil {
  540. t.Fatalf("Failed to create replication controller: %v", err)
  541. }
  542. // these pods should be orphaned.
  543. var podUIDs []types.UID
  544. podsNum := 3
  545. for i := 0; i < podsNum; i++ {
  546. podName := garbageCollectedPodName + strconv.Itoa(i)
  547. pod := newPod(podName, ns.Name, []metav1.OwnerReference{{UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRCName}})
  548. createdPod, err := podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  549. if err != nil {
  550. t.Fatalf("Failed to create Pod: %v", err)
  551. }
  552. podUIDs = append(podUIDs, createdPod.ObjectMeta.UID)
  553. }
  554. // we need wait for the gc to observe the creation of the pods, otherwise if
  555. // the deletion of RC is observed before the creation of the pods, the pods
  556. // will not be orphaned.
  557. err = wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  558. for _, u := range podUIDs {
  559. if !gc.GraphHasUID(u) {
  560. return false, nil
  561. }
  562. }
  563. return true, nil
  564. })
  565. if err != nil {
  566. t.Fatalf("Failed to observe pods in GC graph for %s: %v", toBeDeletedRC.Name, err)
  567. }
  568. err = rcClient.Delete(context.TODO(), toBeDeletedRCName, getOrphanOptions())
  569. if err != nil {
  570. t.Fatalf("Failed to gracefully delete the rc: %v", err)
  571. }
  572. // verify the toBeDeleteRC is deleted
  573. if err := wait.PollImmediate(1*time.Second, 30*time.Second, func() (bool, error) {
  574. rcs, err := rcClient.List(context.TODO(), metav1.ListOptions{})
  575. if err != nil {
  576. return false, err
  577. }
  578. if len(rcs.Items) == 0 {
  579. t.Logf("Still has %d RCs", len(rcs.Items))
  580. return true, nil
  581. }
  582. return false, nil
  583. }); err != nil {
  584. t.Errorf("unexpected error: %v", err)
  585. }
  586. // verify pods don't have the ownerPod as an owner anymore
  587. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  588. if err != nil {
  589. t.Fatalf("Failed to list pods: %v", err)
  590. }
  591. if len(pods.Items) != podsNum {
  592. t.Errorf("Expect %d pod(s), but got %#v", podsNum, pods)
  593. }
  594. for _, pod := range pods.Items {
  595. if len(pod.ObjectMeta.OwnerReferences) != 0 {
  596. t.Errorf("pod %s still has non-empty OwnerReferences: %v", pod.ObjectMeta.Name, pod.ObjectMeta.OwnerReferences)
  597. }
  598. }
  599. }
  600. func TestSolidOwnerDoesNotBlockWaitingOwner(t *testing.T) {
  601. ctx := setup(t, 5)
  602. defer ctx.tearDown()
  603. clientSet := ctx.clientSet
  604. ns := createNamespaceOrDie("gc-foreground1", clientSet, t)
  605. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  606. podClient := clientSet.CoreV1().Pods(ns.Name)
  607. rcClient := clientSet.CoreV1().ReplicationControllers(ns.Name)
  608. // create the RC with the orphan finalizer set
  609. toBeDeletedRC, err := rcClient.Create(context.TODO(), newOwnerRC(toBeDeletedRCName, ns.Name), metav1.CreateOptions{})
  610. if err != nil {
  611. t.Fatalf("Failed to create replication controller: %v", err)
  612. }
  613. remainingRC, err := rcClient.Create(context.TODO(), newOwnerRC(remainingRCName, ns.Name), metav1.CreateOptions{})
  614. if err != nil {
  615. t.Fatalf("Failed to create replication controller: %v", err)
  616. }
  617. trueVar := true
  618. pod := newPod("pod", ns.Name, []metav1.OwnerReference{
  619. {UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRC.Name, BlockOwnerDeletion: &trueVar},
  620. {UID: remainingRC.ObjectMeta.UID, Name: remainingRC.Name},
  621. })
  622. _, err = podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  623. if err != nil {
  624. t.Fatalf("Failed to create Pod: %v", err)
  625. }
  626. err = rcClient.Delete(context.TODO(), toBeDeletedRCName, getForegroundOptions())
  627. if err != nil {
  628. t.Fatalf("Failed to delete the rc: %v", err)
  629. }
  630. // verify the toBeDeleteRC is deleted
  631. if err := wait.PollImmediate(1*time.Second, 30*time.Second, func() (bool, error) {
  632. _, err := rcClient.Get(context.TODO(), toBeDeletedRC.Name, metav1.GetOptions{})
  633. if err != nil {
  634. if apierrors.IsNotFound(err) {
  635. return true, nil
  636. }
  637. return false, err
  638. }
  639. return false, nil
  640. }); err != nil {
  641. t.Errorf("unexpected error: %v", err)
  642. }
  643. // verify pods don't have the toBeDeleteRC as an owner anymore
  644. pod, err = podClient.Get(context.TODO(), "pod", metav1.GetOptions{})
  645. if err != nil {
  646. t.Fatalf("Failed to list pods: %v", err)
  647. }
  648. if len(pod.ObjectMeta.OwnerReferences) != 1 {
  649. t.Errorf("expect pod to have only one ownerReference: got %#v", pod.ObjectMeta.OwnerReferences)
  650. } else if pod.ObjectMeta.OwnerReferences[0].Name != remainingRC.Name {
  651. t.Errorf("expect pod to have an ownerReference pointing to %s, got %#v", remainingRC.Name, pod.ObjectMeta.OwnerReferences)
  652. }
  653. }
  654. func TestNonBlockingOwnerRefDoesNotBlock(t *testing.T) {
  655. ctx := setup(t, 5)
  656. defer ctx.tearDown()
  657. clientSet := ctx.clientSet
  658. ns := createNamespaceOrDie("gc-foreground2", clientSet, t)
  659. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  660. podClient := clientSet.CoreV1().Pods(ns.Name)
  661. rcClient := clientSet.CoreV1().ReplicationControllers(ns.Name)
  662. // create the RC with the orphan finalizer set
  663. toBeDeletedRC, err := rcClient.Create(context.TODO(), newOwnerRC(toBeDeletedRCName, ns.Name), metav1.CreateOptions{})
  664. if err != nil {
  665. t.Fatalf("Failed to create replication controller: %v", err)
  666. }
  667. // BlockingOwnerDeletion is not set
  668. pod1 := newPod("pod1", ns.Name, []metav1.OwnerReference{
  669. {UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRC.Name},
  670. })
  671. // adding finalizer that no controller handles, so that the pod won't be deleted
  672. pod1.ObjectMeta.Finalizers = []string{"x/y"}
  673. // BlockingOwnerDeletion is false
  674. falseVar := false
  675. pod2 := newPod("pod2", ns.Name, []metav1.OwnerReference{
  676. {UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRC.Name, BlockOwnerDeletion: &falseVar},
  677. })
  678. // adding finalizer that no controller handles, so that the pod won't be deleted
  679. pod2.ObjectMeta.Finalizers = []string{"x/y"}
  680. _, err = podClient.Create(context.TODO(), pod1, metav1.CreateOptions{})
  681. if err != nil {
  682. t.Fatalf("Failed to create Pod: %v", err)
  683. }
  684. _, err = podClient.Create(context.TODO(), pod2, metav1.CreateOptions{})
  685. if err != nil {
  686. t.Fatalf("Failed to create Pod: %v", err)
  687. }
  688. err = rcClient.Delete(context.TODO(), toBeDeletedRCName, getForegroundOptions())
  689. if err != nil {
  690. t.Fatalf("Failed to delete the rc: %v", err)
  691. }
  692. // verify the toBeDeleteRC is deleted
  693. if err := wait.PollImmediate(1*time.Second, 30*time.Second, func() (bool, error) {
  694. _, err := rcClient.Get(context.TODO(), toBeDeletedRC.Name, metav1.GetOptions{})
  695. if err != nil {
  696. if apierrors.IsNotFound(err) {
  697. return true, nil
  698. }
  699. return false, err
  700. }
  701. return false, nil
  702. }); err != nil {
  703. t.Errorf("unexpected error: %v", err)
  704. }
  705. // verify pods are still there
  706. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  707. if err != nil {
  708. t.Fatalf("Failed to list pods: %v", err)
  709. }
  710. if len(pods.Items) != 2 {
  711. t.Errorf("expect there to be 2 pods, got %#v", pods.Items)
  712. }
  713. }
  714. func TestDoubleDeletionWithFinalizer(t *testing.T) {
  715. // test setup
  716. ctx := setup(t, 5)
  717. defer ctx.tearDown()
  718. clientSet := ctx.clientSet
  719. ns := createNamespaceOrDie("gc-double-foreground", clientSet, t)
  720. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  721. // step 1: creates a pod with a custom finalizer and deletes it, then waits until gc removes its finalizer
  722. podClient := clientSet.CoreV1().Pods(ns.Name)
  723. pod := newPod("lucy", ns.Name, nil)
  724. pod.ObjectMeta.Finalizers = []string{"x/y"}
  725. if _, err := podClient.Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
  726. t.Fatalf("Failed to create pod: %v", err)
  727. }
  728. if err := podClient.Delete(context.TODO(), pod.Name, getForegroundOptions()); err != nil {
  729. t.Fatalf("Failed to delete pod: %v", err)
  730. }
  731. if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
  732. returnedPod, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{})
  733. if err != nil {
  734. return false, err
  735. }
  736. if len(returnedPod.Finalizers) != 1 || returnedPod.Finalizers[0] != "x/y" {
  737. t.Logf("waiting for pod %q to have only one finalizer %q at step 1, got %v", returnedPod.Name, "x/y", returnedPod.Finalizers)
  738. return false, nil
  739. }
  740. return true, nil
  741. }); err != nil {
  742. t.Fatalf("Failed waiting for pod to have only one filanizer at step 1, error: %v", err)
  743. }
  744. // step 2: deletes the pod one more time and checks if there's only the custom finalizer left
  745. if err := podClient.Delete(context.TODO(), pod.Name, getForegroundOptions()); err != nil {
  746. t.Fatalf("Failed to delete pod: %v", err)
  747. }
  748. if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
  749. returnedPod, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{})
  750. if err != nil {
  751. return false, err
  752. }
  753. if len(returnedPod.Finalizers) != 1 || returnedPod.Finalizers[0] != "x/y" {
  754. t.Logf("waiting for pod %q to have only one finalizer %q at step 2, got %v", returnedPod.Name, "x/y", returnedPod.Finalizers)
  755. return false, nil
  756. }
  757. return true, nil
  758. }); err != nil {
  759. t.Fatalf("Failed waiting for pod to have only one finalizer at step 2, gc hasn't removed its finalzier?, error: %v", err)
  760. }
  761. // step 3: removes the custom finalizer and checks if the pod was removed
  762. patch := []byte(`[{"op":"remove","path":"/metadata/finalizers"}]`)
  763. if _, err := podClient.Patch(context.TODO(), pod.Name, types.JSONPatchType, patch, metav1.PatchOptions{}); err != nil {
  764. t.Fatalf("Failed to update pod: %v", err)
  765. }
  766. if err := wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
  767. _, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{})
  768. return apierrors.IsNotFound(err), nil
  769. }); err != nil {
  770. t.Fatalf("Failed waiting for pod %q to be deleted", pod.Name)
  771. }
  772. }
  773. func TestBlockingOwnerRefDoesBlock(t *testing.T) {
  774. ctx := setup(t, 0)
  775. defer ctx.tearDown()
  776. gc, clientSet := ctx.gc, ctx.clientSet
  777. ns := createNamespaceOrDie("foo", clientSet, t)
  778. defer deleteNamespaceOrDie(ns.Name, clientSet, t)
  779. podClient := clientSet.CoreV1().Pods(ns.Name)
  780. rcClient := clientSet.CoreV1().ReplicationControllers(ns.Name)
  781. // create the RC with the orphan finalizer set
  782. toBeDeletedRC, err := rcClient.Create(context.TODO(), newOwnerRC(toBeDeletedRCName, ns.Name), metav1.CreateOptions{})
  783. if err != nil {
  784. t.Fatalf("Failed to create replication controller: %v", err)
  785. }
  786. trueVar := true
  787. pod := newPod("pod", ns.Name, []metav1.OwnerReference{
  788. {UID: toBeDeletedRC.ObjectMeta.UID, Name: toBeDeletedRC.Name, BlockOwnerDeletion: &trueVar},
  789. })
  790. // adding finalizer that no controller handles, so that the pod won't be deleted
  791. pod.ObjectMeta.Finalizers = []string{"x/y"}
  792. _, err = podClient.Create(context.TODO(), pod, metav1.CreateOptions{})
  793. if err != nil {
  794. t.Fatalf("Failed to create Pod: %v", err)
  795. }
  796. // this makes sure the garbage collector will have added the pod to its
  797. // dependency graph before handling the foreground deletion of the rc.
  798. ctx.startGC(5)
  799. timeout := make(chan struct{})
  800. go func() {
  801. select {
  802. case <-time.After(5 * time.Second):
  803. close(timeout)
  804. }
  805. }()
  806. if !cache.WaitForCacheSync(timeout, gc.IsSynced) {
  807. t.Fatalf("failed to wait for garbage collector to be synced")
  808. }
  809. err = rcClient.Delete(context.TODO(), toBeDeletedRCName, getForegroundOptions())
  810. if err != nil {
  811. t.Fatalf("Failed to delete the rc: %v", err)
  812. }
  813. time.Sleep(15 * time.Second)
  814. // verify the toBeDeleteRC is NOT deleted
  815. _, err = rcClient.Get(context.TODO(), toBeDeletedRC.Name, metav1.GetOptions{})
  816. if err != nil {
  817. t.Errorf("unexpected error: %v", err)
  818. }
  819. // verify pods are still there
  820. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  821. if err != nil {
  822. t.Fatalf("Failed to list pods: %v", err)
  823. }
  824. if len(pods.Items) != 1 {
  825. t.Errorf("expect there to be 1 pods, got %#v", pods.Items)
  826. }
  827. }
  828. // TestCustomResourceCascadingDeletion ensures the basic cascading delete
  829. // behavior supports custom resources.
  830. func TestCustomResourceCascadingDeletion(t *testing.T) {
  831. ctx := setup(t, 5)
  832. defer ctx.tearDown()
  833. clientSet, apiExtensionClient, dynamicClient := ctx.clientSet, ctx.apiExtensionClient, ctx.dynamicClient
  834. ns := createNamespaceOrDie("crd-cascading", clientSet, t)
  835. definition, resourceClient := createRandomCustomResourceDefinition(t, apiExtensionClient, dynamicClient, ns.Name)
  836. // Create a custom owner resource.
  837. owner := newCRDInstance(definition, ns.Name, names.SimpleNameGenerator.GenerateName("owner"))
  838. owner, err := resourceClient.Create(owner, metav1.CreateOptions{})
  839. if err != nil {
  840. t.Fatalf("failed to create owner resource %q: %v", owner.GetName(), err)
  841. }
  842. t.Logf("created owner resource %q", owner.GetName())
  843. // Create a custom dependent resource.
  844. dependent := newCRDInstance(definition, ns.Name, names.SimpleNameGenerator.GenerateName("dependent"))
  845. link(t, owner, dependent)
  846. dependent, err = resourceClient.Create(dependent, metav1.CreateOptions{})
  847. if err != nil {
  848. t.Fatalf("failed to create dependent resource %q: %v", dependent.GetName(), err)
  849. }
  850. t.Logf("created dependent resource %q", dependent.GetName())
  851. // Delete the owner.
  852. foreground := metav1.DeletePropagationForeground
  853. err = resourceClient.Delete(owner.GetName(), &metav1.DeleteOptions{PropagationPolicy: &foreground})
  854. if err != nil {
  855. t.Fatalf("failed to delete owner resource %q: %v", owner.GetName(), err)
  856. }
  857. // Ensure the owner is deleted.
  858. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  859. _, err := resourceClient.Get(owner.GetName(), metav1.GetOptions{})
  860. return apierrors.IsNotFound(err), nil
  861. }); err != nil {
  862. t.Fatalf("failed waiting for owner resource %q to be deleted", owner.GetName())
  863. }
  864. // Ensure the dependent is deleted.
  865. _, err = resourceClient.Get(dependent.GetName(), metav1.GetOptions{})
  866. if err == nil {
  867. t.Fatalf("expected dependent %q to be deleted", dependent.GetName())
  868. } else {
  869. if !apierrors.IsNotFound(err) {
  870. t.Fatalf("unexpected error getting dependent %q: %v", dependent.GetName(), err)
  871. }
  872. }
  873. }
  874. // TestMixedRelationships ensures that owner/dependent relationships work
  875. // between core and custom resources.
  876. //
  877. // TODO: Consider how this could be represented with table-style tests (e.g. a
  878. // before/after expected object graph given a delete operation targeting a
  879. // specific node in the before graph with certain delete options).
  880. func TestMixedRelationships(t *testing.T) {
  881. ctx := setup(t, 5)
  882. defer ctx.tearDown()
  883. clientSet, apiExtensionClient, dynamicClient := ctx.clientSet, ctx.apiExtensionClient, ctx.dynamicClient
  884. ns := createNamespaceOrDie("crd-mixed", clientSet, t)
  885. configMapClient := clientSet.CoreV1().ConfigMaps(ns.Name)
  886. definition, resourceClient := createRandomCustomResourceDefinition(t, apiExtensionClient, dynamicClient, ns.Name)
  887. // Create a custom owner resource.
  888. customOwner, err := resourceClient.Create(newCRDInstance(definition, ns.Name, names.SimpleNameGenerator.GenerateName("owner")), metav1.CreateOptions{})
  889. if err != nil {
  890. t.Fatalf("failed to create owner: %v", err)
  891. }
  892. t.Logf("created custom owner %q", customOwner.GetName())
  893. // Create a core dependent resource.
  894. coreDependent := newConfigMap(ns.Name, names.SimpleNameGenerator.GenerateName("dependent"))
  895. link(t, customOwner, coreDependent)
  896. coreDependent, err = configMapClient.Create(context.TODO(), coreDependent, metav1.CreateOptions{})
  897. if err != nil {
  898. t.Fatalf("failed to create dependent: %v", err)
  899. }
  900. t.Logf("created core dependent %q", coreDependent.GetName())
  901. // Create a core owner resource.
  902. coreOwner, err := configMapClient.Create(context.TODO(), newConfigMap(ns.Name, names.SimpleNameGenerator.GenerateName("owner")), metav1.CreateOptions{})
  903. if err != nil {
  904. t.Fatalf("failed to create owner: %v", err)
  905. }
  906. t.Logf("created core owner %q: %#v", coreOwner.GetName(), coreOwner)
  907. // Create a custom dependent resource.
  908. customDependent := newCRDInstance(definition, ns.Name, names.SimpleNameGenerator.GenerateName("dependent"))
  909. coreOwner.TypeMeta.Kind = "ConfigMap"
  910. coreOwner.TypeMeta.APIVersion = "v1"
  911. link(t, coreOwner, customDependent)
  912. customDependent, err = resourceClient.Create(customDependent, metav1.CreateOptions{})
  913. if err != nil {
  914. t.Fatalf("failed to create dependent: %v", err)
  915. }
  916. t.Logf("created custom dependent %q", customDependent.GetName())
  917. // Delete the custom owner.
  918. foreground := metav1.DeletePropagationForeground
  919. err = resourceClient.Delete(customOwner.GetName(), &metav1.DeleteOptions{PropagationPolicy: &foreground})
  920. if err != nil {
  921. t.Fatalf("failed to delete owner resource %q: %v", customOwner.GetName(), err)
  922. }
  923. // Ensure the owner is deleted.
  924. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  925. _, err := resourceClient.Get(customOwner.GetName(), metav1.GetOptions{})
  926. return apierrors.IsNotFound(err), nil
  927. }); err != nil {
  928. t.Fatalf("failed waiting for owner resource %q to be deleted", customOwner.GetName())
  929. }
  930. // Ensure the dependent is deleted.
  931. _, err = resourceClient.Get(coreDependent.GetName(), metav1.GetOptions{})
  932. if err == nil {
  933. t.Fatalf("expected dependent %q to be deleted", coreDependent.GetName())
  934. } else {
  935. if !apierrors.IsNotFound(err) {
  936. t.Fatalf("unexpected error getting dependent %q: %v", coreDependent.GetName(), err)
  937. }
  938. }
  939. // Delete the core owner.
  940. err = configMapClient.Delete(context.TODO(), coreOwner.GetName(), &metav1.DeleteOptions{PropagationPolicy: &foreground})
  941. if err != nil {
  942. t.Fatalf("failed to delete owner resource %q: %v", coreOwner.GetName(), err)
  943. }
  944. // Ensure the owner is deleted.
  945. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  946. _, err := configMapClient.Get(context.TODO(), coreOwner.GetName(), metav1.GetOptions{})
  947. return apierrors.IsNotFound(err), nil
  948. }); err != nil {
  949. t.Fatalf("failed waiting for owner resource %q to be deleted", coreOwner.GetName())
  950. }
  951. // Ensure the dependent is deleted.
  952. _, err = resourceClient.Get(customDependent.GetName(), metav1.GetOptions{})
  953. if err == nil {
  954. t.Fatalf("expected dependent %q to be deleted", customDependent.GetName())
  955. } else {
  956. if !apierrors.IsNotFound(err) {
  957. t.Fatalf("unexpected error getting dependent %q: %v", customDependent.GetName(), err)
  958. }
  959. }
  960. }
  961. // TestCRDDeletionCascading ensures propagating deletion of a custom resource
  962. // definition with an instance that owns a core resource.
  963. func TestCRDDeletionCascading(t *testing.T) {
  964. ctx := setup(t, 5)
  965. defer ctx.tearDown()
  966. clientSet, apiExtensionClient, dynamicClient := ctx.clientSet, ctx.apiExtensionClient, ctx.dynamicClient
  967. ns := createNamespaceOrDie("crd-mixed", clientSet, t)
  968. t.Logf("First pass CRD cascading deletion")
  969. definition, resourceClient := createRandomCustomResourceDefinition(t, apiExtensionClient, dynamicClient, ns.Name)
  970. testCRDDeletion(t, ctx, ns, definition, resourceClient)
  971. t.Logf("Second pass CRD cascading deletion")
  972. accessor := meta.NewAccessor()
  973. accessor.SetResourceVersion(definition, "")
  974. _, err := apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
  975. if err != nil {
  976. t.Fatalf("failed to create CustomResourceDefinition: %v", err)
  977. }
  978. testCRDDeletion(t, ctx, ns, definition, resourceClient)
  979. }
  980. func testCRDDeletion(t *testing.T, ctx *testContext, ns *v1.Namespace, definition *apiextensionsv1beta1.CustomResourceDefinition, resourceClient dynamic.ResourceInterface) {
  981. clientSet, apiExtensionClient := ctx.clientSet, ctx.apiExtensionClient
  982. configMapClient := clientSet.CoreV1().ConfigMaps(ns.Name)
  983. // Create a custom owner resource.
  984. owner, err := resourceClient.Create(newCRDInstance(definition, ns.Name, names.SimpleNameGenerator.GenerateName("owner")), metav1.CreateOptions{})
  985. if err != nil {
  986. t.Fatalf("failed to create owner: %v", err)
  987. }
  988. t.Logf("created owner %q", owner.GetName())
  989. // Create a core dependent resource.
  990. dependent := newConfigMap(ns.Name, names.SimpleNameGenerator.GenerateName("dependent"))
  991. link(t, owner, dependent)
  992. dependent, err = configMapClient.Create(context.TODO(), dependent, metav1.CreateOptions{})
  993. if err != nil {
  994. t.Fatalf("failed to create dependent: %v", err)
  995. }
  996. t.Logf("created dependent %q", dependent.GetName())
  997. time.Sleep(ctx.syncPeriod + 5*time.Second)
  998. // Delete the definition, which should cascade to the owner and ultimately its dependents.
  999. if err := apiextensionstestserver.DeleteCustomResourceDefinition(definition, apiExtensionClient); err != nil {
  1000. t.Fatalf("failed to delete %q: %v", definition.Name, err)
  1001. }
  1002. // Ensure the owner is deleted.
  1003. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  1004. _, err := resourceClient.Get(owner.GetName(), metav1.GetOptions{})
  1005. return apierrors.IsNotFound(err), nil
  1006. }); err != nil {
  1007. t.Fatalf("failed waiting for owner %q to be deleted", owner.GetName())
  1008. }
  1009. // Ensure the dependent is deleted.
  1010. if err := wait.Poll(1*time.Second, 60*time.Second, func() (bool, error) {
  1011. _, err := configMapClient.Get(context.TODO(), dependent.GetName(), metav1.GetOptions{})
  1012. return apierrors.IsNotFound(err), nil
  1013. }); err != nil {
  1014. t.Fatalf("failed waiting for dependent %q (owned by %q) to be deleted", dependent.GetName(), owner.GetName())
  1015. }
  1016. }