garbage_collector.go 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  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 apimachinery
  14. import (
  15. "context"
  16. "encoding/json"
  17. "fmt"
  18. "sync/atomic"
  19. "time"
  20. appsv1 "k8s.io/api/apps/v1"
  21. batchv1 "k8s.io/api/batch/v1"
  22. batchv1beta1 "k8s.io/api/batch/v1beta1"
  23. v1 "k8s.io/api/core/v1"
  24. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  25. apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
  26. apiextensionstestserver "k8s.io/apiextensions-apiserver/test/integration/fixtures"
  27. apierrors "k8s.io/apimachinery/pkg/api/errors"
  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. utilerrors "k8s.io/apimachinery/pkg/util/errors"
  33. "k8s.io/apimachinery/pkg/util/wait"
  34. "k8s.io/apiserver/pkg/storage/names"
  35. clientset "k8s.io/client-go/kubernetes"
  36. "k8s.io/kubernetes/test/e2e/framework"
  37. e2emetrics "k8s.io/kubernetes/test/e2e/framework/metrics"
  38. e2enode "k8s.io/kubernetes/test/e2e/framework/node"
  39. e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
  40. "github.com/onsi/ginkgo"
  41. imageutils "k8s.io/kubernetes/test/utils/image"
  42. )
  43. // estimateMaximumPods estimates how many pods the cluster can handle
  44. // with some wiggle room, to prevent pods being unable to schedule due
  45. // to max pod constraints.
  46. func estimateMaximumPods(c clientset.Interface, min, max int32) int32 {
  47. nodes, err := e2enode.GetReadySchedulableNodes(c)
  48. framework.ExpectNoError(err)
  49. availablePods := int32(0)
  50. for _, node := range nodes.Items {
  51. if q, ok := node.Status.Allocatable["pods"]; ok {
  52. if num, ok := q.AsInt64(); ok {
  53. availablePods += int32(num)
  54. continue
  55. }
  56. }
  57. // best guess per node, since default maxPerCore is 10 and most nodes have at least
  58. // one core.
  59. availablePods += 10
  60. }
  61. //avoid creating exactly max pods
  62. availablePods *= 8 / 10
  63. // bound the top and bottom
  64. if availablePods > max {
  65. availablePods = max
  66. }
  67. if availablePods < min {
  68. availablePods = min
  69. }
  70. return availablePods
  71. }
  72. func getForegroundOptions() *metav1.DeleteOptions {
  73. policy := metav1.DeletePropagationForeground
  74. return &metav1.DeleteOptions{PropagationPolicy: &policy}
  75. }
  76. func getBackgroundOptions() *metav1.DeleteOptions {
  77. policy := metav1.DeletePropagationBackground
  78. return &metav1.DeleteOptions{PropagationPolicy: &policy}
  79. }
  80. func getOrphanOptions() *metav1.DeleteOptions {
  81. policy := metav1.DeletePropagationOrphan
  82. return &metav1.DeleteOptions{PropagationPolicy: &policy}
  83. }
  84. var (
  85. zero = int64(0)
  86. lablecount = int64(0)
  87. // The GC controller periodically rediscovers available APIs and syncs running informers for those resources.
  88. // If previously available APIs are removed during that resync process, the sync process can fail and need to be retried.
  89. //
  90. // During e2e runs, parallel tests add/remove API resources (by creating/deleting CRDs and aggregated APIs),
  91. // which makes it likely GC will need to retry informer resync at some point during an e2e run.
  92. //
  93. // This timeout covers two resync/retry periods, and should be added to wait timeouts to account for delays
  94. // to the GC controller caused by API changes in other tests.
  95. gcInformerResyncRetryTimeout = time.Minute
  96. // CronJobGroupVersionResource unambiguously identifies a CronJob resource.
  97. CronJobGroupVersionResource = schema.GroupVersionResource{Group: batchv1beta1.GroupName, Version: "v1beta1", Resource: "cronjobs"}
  98. )
  99. func getPodTemplateSpec(labels map[string]string) v1.PodTemplateSpec {
  100. return v1.PodTemplateSpec{
  101. ObjectMeta: metav1.ObjectMeta{
  102. Labels: labels,
  103. },
  104. Spec: v1.PodSpec{
  105. TerminationGracePeriodSeconds: &zero,
  106. Containers: []v1.Container{
  107. {
  108. Name: "nginx",
  109. Image: imageutils.GetE2EImage(imageutils.Nginx),
  110. },
  111. },
  112. },
  113. }
  114. }
  115. func newOwnerDeployment(f *framework.Framework, deploymentName string, labels map[string]string) *appsv1.Deployment {
  116. replicas := int32(2)
  117. return &appsv1.Deployment{
  118. ObjectMeta: metav1.ObjectMeta{
  119. Name: deploymentName,
  120. },
  121. Spec: appsv1.DeploymentSpec{
  122. Replicas: &replicas,
  123. Selector: &metav1.LabelSelector{MatchLabels: labels},
  124. Strategy: appsv1.DeploymentStrategy{
  125. Type: appsv1.RollingUpdateDeploymentStrategyType,
  126. },
  127. Template: getPodTemplateSpec(labels),
  128. },
  129. }
  130. }
  131. func newOwnerRC(f *framework.Framework, name string, replicas int32, labels map[string]string) *v1.ReplicationController {
  132. template := getPodTemplateSpec(labels)
  133. return &v1.ReplicationController{
  134. TypeMeta: metav1.TypeMeta{
  135. Kind: "ReplicationController",
  136. APIVersion: "v1",
  137. },
  138. ObjectMeta: metav1.ObjectMeta{
  139. Namespace: f.Namespace.Name,
  140. Name: name,
  141. },
  142. Spec: v1.ReplicationControllerSpec{
  143. Replicas: &replicas,
  144. Selector: labels,
  145. Template: &template,
  146. },
  147. }
  148. }
  149. func newGCPod(name string) *v1.Pod {
  150. return &v1.Pod{
  151. TypeMeta: metav1.TypeMeta{
  152. Kind: "Pod",
  153. APIVersion: "v1",
  154. },
  155. ObjectMeta: metav1.ObjectMeta{
  156. Name: name,
  157. },
  158. Spec: v1.PodSpec{
  159. TerminationGracePeriodSeconds: new(int64),
  160. Containers: []v1.Container{
  161. {
  162. Name: "nginx",
  163. Image: imageutils.GetE2EImage(imageutils.Nginx),
  164. },
  165. },
  166. },
  167. }
  168. }
  169. // verifyRemainingObjects verifies if the number of remaining objects.
  170. // It returns error if the communication with the API server fails.
  171. func verifyRemainingObjects(f *framework.Framework, objects map[string]int) (bool, error) {
  172. var ret = true
  173. for object, num := range objects {
  174. switch object {
  175. case "Pods":
  176. pods, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  177. if err != nil {
  178. return false, fmt.Errorf("failed to list pods: %v", err)
  179. }
  180. if len(pods.Items) != num {
  181. ret = false
  182. ginkgo.By(fmt.Sprintf("expected %d pods, got %d pods", num, len(pods.Items)))
  183. }
  184. case "Deployments":
  185. deployments, err := f.ClientSet.AppsV1().Deployments(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  186. if err != nil {
  187. return false, fmt.Errorf("failed to list deployments: %v", err)
  188. }
  189. if len(deployments.Items) != num {
  190. ret = false
  191. ginkgo.By(fmt.Sprintf("expected %d Deployments, got %d Deployments", num, len(deployments.Items)))
  192. }
  193. case "ReplicaSets":
  194. rs, err := f.ClientSet.AppsV1().ReplicaSets(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  195. if err != nil {
  196. return false, fmt.Errorf("failed to list rs: %v", err)
  197. }
  198. if len(rs.Items) != num {
  199. ret = false
  200. ginkgo.By(fmt.Sprintf("expected %d rs, got %d rs", num, len(rs.Items)))
  201. }
  202. case "ReplicationControllers":
  203. rcs, err := f.ClientSet.CoreV1().ReplicationControllers(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  204. if err != nil {
  205. return false, fmt.Errorf("failed to list replication controllers: %v", err)
  206. }
  207. if len(rcs.Items) != num {
  208. ret = false
  209. ginkgo.By(fmt.Sprintf("expected %d RCs, got %d RCs", num, len(rcs.Items)))
  210. }
  211. case "CronJobs":
  212. cronJobs, err := f.ClientSet.BatchV1beta1().CronJobs(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  213. if err != nil {
  214. return false, fmt.Errorf("failed to list cronjobs: %v", err)
  215. }
  216. if len(cronJobs.Items) != num {
  217. ret = false
  218. ginkgo.By(fmt.Sprintf("expected %d cronjobs, got %d cronjobs", num, len(cronJobs.Items)))
  219. }
  220. case "Jobs":
  221. jobs, err := f.ClientSet.BatchV1().Jobs(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  222. if err != nil {
  223. return false, fmt.Errorf("failed to list jobs: %v", err)
  224. }
  225. if len(jobs.Items) != num {
  226. ret = false
  227. ginkgo.By(fmt.Sprintf("expected %d jobs, got %d jobs", num, len(jobs.Items)))
  228. }
  229. default:
  230. return false, fmt.Errorf("object %s is not supported", object)
  231. }
  232. }
  233. return ret, nil
  234. }
  235. func gatherMetrics(f *framework.Framework) {
  236. ginkgo.By("Gathering metrics")
  237. var summary framework.TestDataSummary
  238. grabber, err := e2emetrics.NewMetricsGrabber(f.ClientSet, f.KubemarkExternalClusterClientSet, false, false, true, false, false)
  239. if err != nil {
  240. framework.Logf("Failed to create MetricsGrabber. Skipping metrics gathering.")
  241. } else {
  242. received, err := grabber.Grab()
  243. if err != nil {
  244. framework.Logf("MetricsGrabber failed grab metrics. Skipping metrics gathering.")
  245. } else {
  246. summary = (*e2emetrics.ComponentCollection)(&received)
  247. framework.Logf(summary.PrintHumanReadable())
  248. }
  249. }
  250. }
  251. func newCronJob(name, schedule string) *batchv1beta1.CronJob {
  252. parallelism := int32(1)
  253. completions := int32(1)
  254. return &batchv1beta1.CronJob{
  255. ObjectMeta: metav1.ObjectMeta{
  256. Name: name,
  257. },
  258. TypeMeta: metav1.TypeMeta{
  259. Kind: "CronJob",
  260. },
  261. Spec: batchv1beta1.CronJobSpec{
  262. Schedule: schedule,
  263. JobTemplate: batchv1beta1.JobTemplateSpec{
  264. Spec: batchv1.JobSpec{
  265. Parallelism: &parallelism,
  266. Completions: &completions,
  267. Template: v1.PodTemplateSpec{
  268. Spec: v1.PodSpec{
  269. RestartPolicy: v1.RestartPolicyOnFailure,
  270. TerminationGracePeriodSeconds: &zero,
  271. Containers: []v1.Container{
  272. {
  273. Name: "c",
  274. Image: imageutils.GetE2EImage(imageutils.BusyBox),
  275. Command: []string{"sleep", "300"},
  276. },
  277. },
  278. },
  279. },
  280. },
  281. },
  282. },
  283. }
  284. }
  285. // getUniqLabel returns a UniqLabel based on labeLkey and labelvalue.
  286. func getUniqLabel(labelkey, labelvalue string) map[string]string {
  287. count := atomic.AddInt64(&lablecount, 1)
  288. uniqlabelkey := fmt.Sprintf("%s-%05d", labelkey, count)
  289. uniqlabelvalue := fmt.Sprintf("%s-%05d", labelvalue, count)
  290. return map[string]string{uniqlabelkey: uniqlabelvalue}
  291. }
  292. var _ = SIGDescribe("Garbage collector", func() {
  293. f := framework.NewDefaultFramework("gc")
  294. /*
  295. Release : v1.9
  296. Testname: Garbage Collector, delete replication controller, propagation policy background
  297. Description: Create a replication controller with 2 Pods. Once RC is created and the first Pod is created, delete RC with deleteOptions.PropagationPolicy set to Background. Deleting the Replication Controller MUST cause pods created by that RC to be deleted.
  298. */
  299. framework.ConformanceIt("should delete pods created by rc when not orphaning", func() {
  300. clientSet := f.ClientSet
  301. rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
  302. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  303. rcName := "simpletest.rc"
  304. uniqLabels := getUniqLabel("gctest", "delete_pods")
  305. rc := newOwnerRC(f, rcName, 2, uniqLabels)
  306. ginkgo.By("create the rc")
  307. rc, err := rcClient.Create(context.TODO(), rc, metav1.CreateOptions{})
  308. if err != nil {
  309. framework.Failf("Failed to create replication controller: %v", err)
  310. }
  311. // wait for rc to create some pods
  312. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  313. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  314. if err != nil {
  315. return false, fmt.Errorf("failed to list pods: %v", err)
  316. }
  317. // We intentionally don't wait the number of pods to reach
  318. // rc.Spec.Replicas. We want to see if the garbage collector and the
  319. // rc manager work properly if the rc is deleted before it reaches
  320. // stasis.
  321. if len(pods.Items) > 0 {
  322. return true, nil
  323. }
  324. return false, nil
  325. }); err != nil {
  326. framework.Failf("failed to wait for the rc to create some pods: %v", err)
  327. }
  328. ginkgo.By("delete the rc")
  329. deleteOptions := getBackgroundOptions()
  330. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(rc.UID))
  331. if err := rcClient.Delete(context.TODO(), rc.ObjectMeta.Name, deleteOptions); err != nil {
  332. framework.Failf("failed to delete the rc: %v", err)
  333. }
  334. ginkgo.By("wait for all pods to be garbage collected")
  335. // wait for the RCs and Pods to reach the expected numbers.
  336. if err := wait.Poll(5*time.Second, (60*time.Second)+gcInformerResyncRetryTimeout, func() (bool, error) {
  337. objects := map[string]int{"ReplicationControllers": 0, "Pods": 0}
  338. return verifyRemainingObjects(f, objects)
  339. }); err != nil {
  340. framework.Failf("failed to wait for all pods to be deleted: %v", err)
  341. remainingPods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  342. if err != nil {
  343. framework.Failf("failed to list pods post mortem: %v", err)
  344. } else {
  345. framework.Failf("remaining pods are: %#v", remainingPods)
  346. }
  347. }
  348. gatherMetrics(f)
  349. })
  350. /*
  351. Release : v1.9
  352. Testname: Garbage Collector, delete replication controller, propagation policy orphan
  353. Description: Create a replication controller with maximum allocatable Pods between 10 and 100 replicas. Once RC is created and the all Pods are created, delete RC with deleteOptions.PropagationPolicy set to Orphan. Deleting the Replication Controller MUST cause pods created by that RC to be orphaned.
  354. */
  355. framework.ConformanceIt("should orphan pods created by rc if delete options say so", func() {
  356. clientSet := f.ClientSet
  357. rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
  358. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  359. rcName := "simpletest.rc"
  360. uniqLabels := getUniqLabel("gctest", "orphan_pods")
  361. rc := newOwnerRC(f, rcName, estimateMaximumPods(clientSet, 10, 100), uniqLabels)
  362. ginkgo.By("create the rc")
  363. rc, err := rcClient.Create(context.TODO(), rc, metav1.CreateOptions{})
  364. if err != nil {
  365. framework.Failf("Failed to create replication controller: %v", err)
  366. }
  367. // wait for rc to create pods
  368. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  369. rc, err := rcClient.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  370. if err != nil {
  371. return false, fmt.Errorf("failed to get rc: %v", err)
  372. }
  373. if rc.Status.Replicas == *rc.Spec.Replicas {
  374. return true, nil
  375. }
  376. return false, nil
  377. }); err != nil {
  378. framework.Failf("failed to wait for the rc.Status.Replicas to reach rc.Spec.Replicas: %v", err)
  379. }
  380. ginkgo.By("delete the rc")
  381. deleteOptions := getOrphanOptions()
  382. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(rc.UID))
  383. if err := rcClient.Delete(context.TODO(), rc.ObjectMeta.Name, deleteOptions); err != nil {
  384. framework.Failf("failed to delete the rc: %v", err)
  385. }
  386. ginkgo.By("wait for the rc to be deleted")
  387. // Orphaning the 100 pods takes 100 PATCH operations. The default qps of
  388. // a client is 5. If the qps is saturated, it will take 20s to orphan
  389. // the pods. However, apiserver takes hundreds of ms to finish one
  390. // PATCH, and the gc sends the patching in a single thread, so the
  391. // actual qps is less than 5. Also, the e2e tests are running in
  392. // parallel, the GC controller might get distracted by other tests.
  393. // According to the test logs, 120s is enough time.
  394. if err := wait.Poll(5*time.Second, 120*time.Second+gcInformerResyncRetryTimeout, func() (bool, error) {
  395. rcs, err := rcClient.List(context.TODO(), metav1.ListOptions{})
  396. if err != nil {
  397. return false, fmt.Errorf("failed to list rcs: %v", err)
  398. }
  399. if len(rcs.Items) != 0 {
  400. return false, nil
  401. }
  402. return true, nil
  403. }); err != nil {
  404. framework.Failf("%v", err)
  405. }
  406. ginkgo.By("wait for 30 seconds to see if the garbage collector mistakenly deletes the pods")
  407. time.Sleep(30 * time.Second)
  408. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  409. if err != nil {
  410. framework.Failf("Failed to list pods: %v", err)
  411. }
  412. if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
  413. framework.Failf("expect %d pods, got %d pods", e, a)
  414. }
  415. gatherMetrics(f)
  416. })
  417. // deleteOptions.OrphanDependents is deprecated in 1.7 and preferred to use the PropagationPolicy.
  418. // Discussion is tracked under https://github.com/kubernetes/kubernetes/issues/65427 to promote for conformance in future.
  419. ginkgo.It("should orphan pods created by rc if deleteOptions.OrphanDependents is nil", func() {
  420. clientSet := f.ClientSet
  421. rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
  422. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  423. rcName := "simpletest.rc"
  424. uniqLabels := getUniqLabel("gctest", "orphan_pods_nil_option")
  425. rc := newOwnerRC(f, rcName, 2, uniqLabels)
  426. ginkgo.By("create the rc")
  427. rc, err := rcClient.Create(context.TODO(), rc, metav1.CreateOptions{})
  428. if err != nil {
  429. framework.Failf("Failed to create replication controller: %v", err)
  430. }
  431. // wait for rc to create some pods
  432. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  433. rc, err := rcClient.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  434. if err != nil {
  435. return false, fmt.Errorf("failed to get rc: %v", err)
  436. }
  437. if rc.Status.Replicas == *rc.Spec.Replicas {
  438. return true, nil
  439. }
  440. return false, nil
  441. }); err != nil {
  442. framework.Failf("failed to wait for the rc.Status.Replicas to reach rc.Spec.Replicas: %v", err)
  443. }
  444. ginkgo.By("delete the rc")
  445. deleteOptions := &metav1.DeleteOptions{}
  446. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(rc.UID))
  447. if err := rcClient.Delete(context.TODO(), rc.ObjectMeta.Name, deleteOptions); err != nil {
  448. framework.Failf("failed to delete the rc: %v", err)
  449. }
  450. ginkgo.By("wait for 30 seconds to see if the garbage collector mistakenly deletes the pods")
  451. time.Sleep(30 * time.Second)
  452. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  453. if err != nil {
  454. framework.Failf("Failed to list pods: %v", err)
  455. }
  456. if e, a := int(*(rc.Spec.Replicas)), len(pods.Items); e != a {
  457. framework.Failf("expect %d pods, got %d pods", e, a)
  458. }
  459. gatherMetrics(f)
  460. })
  461. /*
  462. Release : v1.9
  463. Testname: Garbage Collector, delete deployment, propagation policy background
  464. Description: Create a deployment with a replicaset. Once replicaset is created , delete the deployment with deleteOptions.PropagationPolicy set to Background. Deleting the deployment MUST delete the replicaset created by the deployment and also the Pods that belong to the deployments MUST be deleted.
  465. */
  466. framework.ConformanceIt("should delete RS created by deployment when not orphaning", func() {
  467. clientSet := f.ClientSet
  468. deployClient := clientSet.AppsV1().Deployments(f.Namespace.Name)
  469. rsClient := clientSet.AppsV1().ReplicaSets(f.Namespace.Name)
  470. deploymentName := "simpletest.deployment"
  471. uniqLabels := getUniqLabel("gctest", "delete_rs")
  472. deployment := newOwnerDeployment(f, deploymentName, uniqLabels)
  473. ginkgo.By("create the deployment")
  474. createdDeployment, err := deployClient.Create(context.TODO(), deployment, metav1.CreateOptions{})
  475. if err != nil {
  476. framework.Failf("Failed to create deployment: %v", err)
  477. }
  478. // wait for deployment to create some rs
  479. ginkgo.By("Wait for the Deployment to create new ReplicaSet")
  480. err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute, func() (bool, error) {
  481. rsList, err := rsClient.List(context.TODO(), metav1.ListOptions{})
  482. if err != nil {
  483. return false, fmt.Errorf("failed to list rs: %v", err)
  484. }
  485. return len(rsList.Items) > 0, nil
  486. })
  487. if err != nil {
  488. framework.Failf("Failed to wait for the Deployment to create some ReplicaSet: %v", err)
  489. }
  490. ginkgo.By("delete the deployment")
  491. deleteOptions := getBackgroundOptions()
  492. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(createdDeployment.UID))
  493. if err := deployClient.Delete(context.TODO(), deployment.ObjectMeta.Name, deleteOptions); err != nil {
  494. framework.Failf("failed to delete the deployment: %v", err)
  495. }
  496. ginkgo.By("wait for all rs to be garbage collected")
  497. err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute+gcInformerResyncRetryTimeout, func() (bool, error) {
  498. objects := map[string]int{"Deployments": 0, "ReplicaSets": 0, "Pods": 0}
  499. return verifyRemainingObjects(f, objects)
  500. })
  501. if err != nil {
  502. errList := make([]error, 0)
  503. errList = append(errList, err)
  504. remainingRSs, err := rsClient.List(context.TODO(), metav1.ListOptions{})
  505. if err != nil {
  506. errList = append(errList, fmt.Errorf("failed to list RSs post mortem: %v", err))
  507. } else {
  508. errList = append(errList, fmt.Errorf("remaining rs are: %#v", remainingRSs))
  509. }
  510. aggregatedError := utilerrors.NewAggregate(errList)
  511. framework.Failf("Failed to wait for all rs to be garbage collected: %v", aggregatedError)
  512. }
  513. gatherMetrics(f)
  514. })
  515. /*
  516. Release : v1.9
  517. Testname: Garbage Collector, delete deployment, propagation policy orphan
  518. Description: Create a deployment with a replicaset. Once replicaset is created , delete the deployment with deleteOptions.PropagationPolicy set to Orphan. Deleting the deployment MUST cause the replicaset created by the deployment to be orphaned, also the Pods created by the deployments MUST be orphaned.
  519. */
  520. framework.ConformanceIt("should orphan RS created by deployment when deleteOptions.PropagationPolicy is Orphan", func() {
  521. clientSet := f.ClientSet
  522. deployClient := clientSet.AppsV1().Deployments(f.Namespace.Name)
  523. rsClient := clientSet.AppsV1().ReplicaSets(f.Namespace.Name)
  524. deploymentName := "simpletest.deployment"
  525. uniqLabels := getUniqLabel("gctest", "orphan_rs")
  526. deployment := newOwnerDeployment(f, deploymentName, uniqLabels)
  527. ginkgo.By("create the deployment")
  528. createdDeployment, err := deployClient.Create(context.TODO(), deployment, metav1.CreateOptions{})
  529. if err != nil {
  530. framework.Failf("Failed to create deployment: %v", err)
  531. }
  532. // wait for deployment to create some rs
  533. ginkgo.By("Wait for the Deployment to create new ReplicaSet")
  534. err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute, func() (bool, error) {
  535. rsList, err := rsClient.List(context.TODO(), metav1.ListOptions{})
  536. if err != nil {
  537. return false, fmt.Errorf("failed to list rs: %v", err)
  538. }
  539. return len(rsList.Items) > 0, nil
  540. })
  541. if err != nil {
  542. framework.Failf("Failed to wait for the Deployment to create some ReplicaSet: %v", err)
  543. }
  544. ginkgo.By("delete the deployment")
  545. deleteOptions := getOrphanOptions()
  546. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(createdDeployment.UID))
  547. if err := deployClient.Delete(context.TODO(), deployment.ObjectMeta.Name, deleteOptions); err != nil {
  548. framework.Failf("failed to delete the deployment: %v", err)
  549. }
  550. ginkgo.By("wait for deployment deletion to see if the garbage collector mistakenly deletes the rs")
  551. err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute+gcInformerResyncRetryTimeout, func() (bool, error) {
  552. dList, err := deployClient.List(context.TODO(), metav1.ListOptions{})
  553. if err != nil {
  554. return false, fmt.Errorf("failed to list deployments: %v", err)
  555. }
  556. return len(dList.Items) == 0, nil
  557. })
  558. if err != nil {
  559. framework.Failf("Failed to wait for the Deployment to be deleted: %v", err)
  560. }
  561. // Once the deployment object is gone, we'll know the GC has finished performing any relevant actions.
  562. objects := map[string]int{"Deployments": 0, "ReplicaSets": 1, "Pods": 2}
  563. ok, err := verifyRemainingObjects(f, objects)
  564. if err != nil {
  565. framework.Failf("Unexpected error while verifying remaining deployments, rs, and pods: %v", err)
  566. }
  567. if !ok {
  568. errList := make([]error, 0)
  569. remainingRSs, err := rsClient.List(context.TODO(), metav1.ListOptions{})
  570. if err != nil {
  571. errList = append(errList, fmt.Errorf("failed to list RSs post mortem: %v", err))
  572. } else {
  573. errList = append(errList, fmt.Errorf("remaining rs post mortem: %#v", remainingRSs))
  574. }
  575. remainingDSs, err := deployClient.List(context.TODO(), metav1.ListOptions{})
  576. if err != nil {
  577. errList = append(errList, fmt.Errorf("failed to list Deployments post mortem: %v", err))
  578. } else {
  579. errList = append(errList, fmt.Errorf("remaining deployment's post mortem: %#v", remainingDSs))
  580. }
  581. aggregatedError := utilerrors.NewAggregate(errList)
  582. framework.Failf("Failed to verify remaining deployments, rs, and pods: %v", aggregatedError)
  583. }
  584. rs, err := clientSet.AppsV1().ReplicaSets(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  585. if err != nil {
  586. framework.Failf("Failed to list ReplicaSet %v", err)
  587. }
  588. for _, replicaSet := range rs.Items {
  589. if metav1.GetControllerOf(&replicaSet.ObjectMeta) != nil {
  590. framework.Failf("Found ReplicaSet with non nil ownerRef %v", replicaSet)
  591. }
  592. }
  593. gatherMetrics(f)
  594. })
  595. /*
  596. Release : v1.9
  597. Testname: Garbage Collector, delete replication controller, after owned pods
  598. Description: Create a replication controller with maximum allocatable Pods between 10 and 100 replicas. Once RC is created and the all Pods are created, delete RC with deleteOptions.PropagationPolicy set to Foreground. Deleting the Replication Controller MUST cause pods created by that RC to be deleted before the RC is deleted.
  599. */
  600. framework.ConformanceIt("should keep the rc around until all its pods are deleted if the deleteOptions says so", func() {
  601. clientSet := f.ClientSet
  602. rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
  603. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  604. rcName := "simpletest.rc"
  605. uniqLabels := getUniqLabel("gctest", "delete_pods_foreground")
  606. rc := newOwnerRC(f, rcName, estimateMaximumPods(clientSet, 10, 100), uniqLabels)
  607. ginkgo.By("create the rc")
  608. rc, err := rcClient.Create(context.TODO(), rc, metav1.CreateOptions{})
  609. if err != nil {
  610. framework.Failf("Failed to create replication controller: %v", err)
  611. }
  612. // wait for rc to create pods
  613. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  614. rc, err := rcClient.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  615. if err != nil {
  616. return false, fmt.Errorf("failed to get rc: %v", err)
  617. }
  618. if rc.Status.Replicas == *rc.Spec.Replicas {
  619. return true, nil
  620. }
  621. return false, nil
  622. }); err != nil {
  623. framework.Failf("failed to wait for the rc.Status.Replicas to reach rc.Spec.Replicas: %v", err)
  624. }
  625. ginkgo.By("delete the rc")
  626. deleteOptions := getForegroundOptions()
  627. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(rc.UID))
  628. if err := rcClient.Delete(context.TODO(), rc.ObjectMeta.Name, deleteOptions); err != nil {
  629. framework.Failf("failed to delete the rc: %v", err)
  630. }
  631. ginkgo.By("wait for the rc to be deleted")
  632. // default client QPS is 20, deleting each pod requires 2 requests, so 30s should be enough
  633. // TODO: 30s is enough assuming immediate processing of dependents following
  634. // owner deletion, but in practice there can be a long delay between owner
  635. // deletion and dependent deletion processing. For now, increase the timeout
  636. // and investigate the processing delay.
  637. if err := wait.Poll(1*time.Second, 30*time.Second+gcInformerResyncRetryTimeout, func() (bool, error) {
  638. _, err := rcClient.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  639. if err == nil {
  640. pods, _ := podClient.List(context.TODO(), metav1.ListOptions{})
  641. framework.Logf("%d pods remaining", len(pods.Items))
  642. count := 0
  643. for _, pod := range pods.Items {
  644. if pod.ObjectMeta.DeletionTimestamp == nil {
  645. count++
  646. }
  647. }
  648. framework.Logf("%d pods has nil DeletionTimestamp", count)
  649. framework.Logf("")
  650. return false, nil
  651. }
  652. if apierrors.IsNotFound(err) {
  653. return true, nil
  654. }
  655. return false, err
  656. }); err != nil {
  657. pods, err2 := podClient.List(context.TODO(), metav1.ListOptions{})
  658. if err2 != nil {
  659. framework.Failf("%v", err2)
  660. }
  661. framework.Logf("%d remaining pods are:", len(pods.Items))
  662. framework.Logf("The ObjectMeta of the remaining pods are:")
  663. for _, pod := range pods.Items {
  664. framework.Logf("%#v", pod.ObjectMeta)
  665. }
  666. framework.Failf("failed to delete the rc: %v", err)
  667. }
  668. // There shouldn't be any pods
  669. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  670. if err != nil {
  671. framework.Failf("%v", err)
  672. }
  673. if len(pods.Items) != 0 {
  674. framework.Failf("expected no pods, got %#v", pods)
  675. }
  676. gatherMetrics(f)
  677. })
  678. // TODO: this should be an integration test
  679. /*
  680. Release : v1.9
  681. Testname: Garbage Collector, multiple owners
  682. Description: Create a replication controller RC1, with maximum allocatable Pods between 10 and 100 replicas. Create second replication controller RC2 and set RC2 as owner for half of those replicas. Once RC1 is created and the all Pods are created, delete RC1 with deleteOptions.PropagationPolicy set to Foreground. Half of the Pods that has RC2 as owner MUST not be deleted but have a deletion timestamp. Deleting the Replication Controller MUST not delete Pods that are owned by multiple replication controllers.
  683. */
  684. framework.ConformanceIt("should not delete dependents that have both valid owner and owner that's waiting for dependents to be deleted", func() {
  685. clientSet := f.ClientSet
  686. rcClient := clientSet.CoreV1().ReplicationControllers(f.Namespace.Name)
  687. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  688. rc1Name := "simpletest-rc-to-be-deleted"
  689. replicas := int32(estimateMaximumPods(clientSet, 10, 100))
  690. halfReplicas := int(replicas / 2)
  691. uniqLabelsDeleted := getUniqLabel("gctest_d", "valid_and_pending_owners_d")
  692. rc1 := newOwnerRC(f, rc1Name, replicas, uniqLabelsDeleted)
  693. ginkgo.By("create the rc1")
  694. rc1, err := rcClient.Create(context.TODO(), rc1, metav1.CreateOptions{})
  695. if err != nil {
  696. framework.Failf("Failed to create replication controller: %v", err)
  697. }
  698. rc2Name := "simpletest-rc-to-stay"
  699. uniqLabelsStay := getUniqLabel("gctest_s", "valid_and_pending_owners_s")
  700. rc2 := newOwnerRC(f, rc2Name, 0, uniqLabelsStay)
  701. ginkgo.By("create the rc2")
  702. rc2, err = rcClient.Create(context.TODO(), rc2, metav1.CreateOptions{})
  703. if err != nil {
  704. framework.Failf("Failed to create replication controller: %v", err)
  705. }
  706. // wait for rc1 to be stable
  707. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  708. rc1, err := rcClient.Get(context.TODO(), rc1.Name, metav1.GetOptions{})
  709. if err != nil {
  710. return false, fmt.Errorf("failed to get rc: %v", err)
  711. }
  712. if rc1.Status.Replicas == *rc1.Spec.Replicas {
  713. return true, nil
  714. }
  715. return false, nil
  716. }); err != nil {
  717. framework.Failf("failed to wait for the rc.Status.Replicas to reach rc.Spec.Replicas: %v", err)
  718. }
  719. ginkgo.By(fmt.Sprintf("set half of pods created by rc %s to have rc %s as owner as well", rc1Name, rc2Name))
  720. pods, err := podClient.List(context.TODO(), metav1.ListOptions{})
  721. framework.ExpectNoError(err, "failed to list pods in namespace: %s", f.Namespace.Name)
  722. patch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"apiVersion":"v1","kind":"ReplicationController","name":"%s","uid":"%s"}]}}`, rc2.ObjectMeta.Name, rc2.ObjectMeta.UID)
  723. for i := 0; i < halfReplicas; i++ {
  724. pod := pods.Items[i]
  725. _, err := podClient.Patch(context.TODO(), pod.Name, types.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
  726. framework.ExpectNoError(err, "failed to apply to pod %s in namespace %s, a strategic merge patch: %s", pod.Name, f.Namespace.Name, patch)
  727. }
  728. ginkgo.By(fmt.Sprintf("delete the rc %s", rc1Name))
  729. deleteOptions := getForegroundOptions()
  730. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(rc1.UID))
  731. if err := rcClient.Delete(context.TODO(), rc1.ObjectMeta.Name, deleteOptions); err != nil {
  732. framework.Failf("failed to delete the rc: %v", err)
  733. }
  734. ginkgo.By("wait for the rc to be deleted")
  735. // TODO: shorten the timeout when we make GC's periodic API rediscovery more efficient.
  736. // Tracked at https://github.com/kubernetes/kubernetes/issues/50046.
  737. if err := wait.Poll(5*time.Second, 90*time.Second, func() (bool, error) {
  738. _, err := rcClient.Get(context.TODO(), rc1.Name, metav1.GetOptions{})
  739. if err == nil {
  740. pods, _ := podClient.List(context.TODO(), metav1.ListOptions{})
  741. framework.Logf("%d pods remaining", len(pods.Items))
  742. count := 0
  743. for _, pod := range pods.Items {
  744. if pod.ObjectMeta.DeletionTimestamp == nil {
  745. count++
  746. }
  747. }
  748. framework.Logf("%d pods has nil DeletionTimestamp", count)
  749. framework.Logf("")
  750. return false, nil
  751. }
  752. if apierrors.IsNotFound(err) {
  753. return true, nil
  754. }
  755. return false, err
  756. }); err != nil {
  757. pods, err2 := podClient.List(context.TODO(), metav1.ListOptions{})
  758. if err2 != nil {
  759. framework.Failf("%v", err2)
  760. }
  761. framework.Logf("%d remaining pods are:", len(pods.Items))
  762. framework.Logf("ObjectMeta of remaining pods are:")
  763. for _, pod := range pods.Items {
  764. framework.Logf("%#v", pod.ObjectMeta)
  765. }
  766. framework.Failf("failed to delete rc %s, err: %v", rc1Name, err)
  767. }
  768. // half of the pods should still exist,
  769. pods, err = podClient.List(context.TODO(), metav1.ListOptions{})
  770. if err != nil {
  771. framework.Failf("%v", err)
  772. }
  773. if len(pods.Items) != halfReplicas {
  774. framework.Failf("expected %d pods, got %d", halfReplicas, len(pods.Items))
  775. }
  776. for _, pod := range pods.Items {
  777. if pod.ObjectMeta.DeletionTimestamp != nil {
  778. framework.Failf("expected pod DeletionTimestamp to be nil, got %#v", pod.ObjectMeta)
  779. }
  780. // they should only have 1 ownerReference left
  781. if len(pod.ObjectMeta.OwnerReferences) != 1 {
  782. framework.Failf("expected pod to only have 1 owner, got %#v", pod.ObjectMeta.OwnerReferences)
  783. }
  784. }
  785. gatherMetrics(f)
  786. })
  787. // TODO: should be an integration test
  788. /*
  789. Release : v1.9
  790. Testname: Garbage Collector, dependency cycle
  791. Description: Create three pods, patch them with Owner references such that pod1 has pod3, pod2 has pod1 and pod3 has pod2 as owner references respectively. Delete pod1 MUST delete all pods. The dependency cycle MUST not block the garbage collection.
  792. */
  793. framework.ConformanceIt("should not be blocked by dependency circle", func() {
  794. clientSet := f.ClientSet
  795. podClient := clientSet.CoreV1().Pods(f.Namespace.Name)
  796. pod1Name := "pod1"
  797. pod1 := newGCPod(pod1Name)
  798. pod1, err := podClient.Create(context.TODO(), pod1, metav1.CreateOptions{})
  799. framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", pod1Name, f.Namespace.Name)
  800. pod2Name := "pod2"
  801. pod2 := newGCPod(pod2Name)
  802. pod2, err = podClient.Create(context.TODO(), pod2, metav1.CreateOptions{})
  803. framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", pod2Name, f.Namespace.Name)
  804. pod3Name := "pod3"
  805. pod3 := newGCPod(pod3Name)
  806. pod3, err = podClient.Create(context.TODO(), pod3, metav1.CreateOptions{})
  807. framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", pod3Name, f.Namespace.Name)
  808. // create circular dependency
  809. addRefPatch := func(name string, uid types.UID) []byte {
  810. return []byte(fmt.Sprintf(`{"metadata":{"ownerReferences":[{"apiVersion":"v1","kind":"Pod","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}]}}`, name, uid))
  811. }
  812. patch1 := addRefPatch(pod3.Name, pod3.UID)
  813. pod1, err = podClient.Patch(context.TODO(), pod1.Name, types.StrategicMergePatchType, patch1, metav1.PatchOptions{})
  814. framework.ExpectNoError(err, "failed to apply to pod %s in namespace %s, a strategic merge patch: %s", pod1.Name, f.Namespace.Name, patch1)
  815. framework.Logf("pod1.ObjectMeta.OwnerReferences=%#v", pod1.ObjectMeta.OwnerReferences)
  816. patch2 := addRefPatch(pod1.Name, pod1.UID)
  817. pod2, err = podClient.Patch(context.TODO(), pod2.Name, types.StrategicMergePatchType, patch2, metav1.PatchOptions{})
  818. framework.ExpectNoError(err, "failed to apply to pod %s in namespace %s, a strategic merge patch: %s", pod2.Name, f.Namespace.Name, patch2)
  819. framework.Logf("pod2.ObjectMeta.OwnerReferences=%#v", pod2.ObjectMeta.OwnerReferences)
  820. patch3 := addRefPatch(pod2.Name, pod2.UID)
  821. pod3, err = podClient.Patch(context.TODO(), pod3.Name, types.StrategicMergePatchType, patch3, metav1.PatchOptions{})
  822. framework.ExpectNoError(err, "failed to apply to pod %s in namespace %s, a strategic merge patch: %s", pod3.Name, f.Namespace.Name, patch3)
  823. framework.Logf("pod3.ObjectMeta.OwnerReferences=%#v", pod3.ObjectMeta.OwnerReferences)
  824. // delete one pod, should result in the deletion of all pods
  825. deleteOptions := getForegroundOptions()
  826. deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(pod1.UID))
  827. err = podClient.Delete(context.TODO(), pod1.ObjectMeta.Name, deleteOptions)
  828. framework.ExpectNoError(err, "failed to delete pod %s in namespace: %s", pod1.Name, f.Namespace.Name)
  829. var pods *v1.PodList
  830. var err2 error
  831. // TODO: shorten the timeout when we make GC's periodic API rediscovery more efficient.
  832. // Tracked at https://github.com/kubernetes/kubernetes/issues/50046.
  833. if err := wait.Poll(5*time.Second, 90*time.Second+gcInformerResyncRetryTimeout, func() (bool, error) {
  834. pods, err2 = podClient.List(context.TODO(), metav1.ListOptions{})
  835. if err2 != nil {
  836. return false, fmt.Errorf("failed to list pods: %v", err)
  837. }
  838. if len(pods.Items) == 0 {
  839. return true, nil
  840. }
  841. return false, nil
  842. }); err != nil {
  843. data, _ := json.Marshal(pods.Items)
  844. framework.Logf("pods are %s", string(data))
  845. framework.Failf("failed to wait for all pods to be deleted: %v", err)
  846. }
  847. })
  848. ginkgo.It("should support cascading deletion of custom resources", func() {
  849. config, err := framework.LoadConfig()
  850. if err != nil {
  851. framework.Failf("failed to load config: %v", err)
  852. }
  853. apiExtensionClient, err := apiextensionsclientset.NewForConfig(config)
  854. if err != nil {
  855. framework.Failf("failed to initialize apiExtensionClient: %v", err)
  856. }
  857. // Create a random custom resource definition and ensure it's available for
  858. // use.
  859. definition := apiextensionstestserver.NewRandomNameV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
  860. defer func() {
  861. err = apiextensionstestserver.DeleteV1CustomResourceDefinition(definition, apiExtensionClient)
  862. if err != nil && !apierrors.IsNotFound(err) {
  863. framework.Failf("failed to delete CustomResourceDefinition: %v", err)
  864. }
  865. }()
  866. definition, err = apiextensionstestserver.CreateNewV1CustomResourceDefinition(definition, apiExtensionClient, f.DynamicClient)
  867. if err != nil {
  868. framework.Failf("failed to create CustomResourceDefinition: %v", err)
  869. }
  870. framework.ExpectEqual(len(definition.Spec.Versions), 1, "custom resource definition should have one version")
  871. version := definition.Spec.Versions[0]
  872. // Get a client for the custom resource.
  873. gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: version.Name, Resource: definition.Spec.Names.Plural}
  874. resourceClient := f.DynamicClient.Resource(gvr)
  875. apiVersion := definition.Spec.Group + "/" + version.Name
  876. // Create a custom owner resource.
  877. ownerName := names.SimpleNameGenerator.GenerateName("owner")
  878. owner := &unstructured.Unstructured{
  879. Object: map[string]interface{}{
  880. "apiVersion": apiVersion,
  881. "kind": definition.Spec.Names.Kind,
  882. "metadata": map[string]interface{}{
  883. "name": ownerName,
  884. },
  885. },
  886. }
  887. persistedOwner, err := resourceClient.Create(owner, metav1.CreateOptions{})
  888. if err != nil {
  889. framework.Failf("failed to create owner resource %q: %v", ownerName, err)
  890. }
  891. framework.Logf("created owner resource %q", ownerName)
  892. // Create a custom dependent resource.
  893. dependentName := names.SimpleNameGenerator.GenerateName("dependent")
  894. dependent := &unstructured.Unstructured{
  895. Object: map[string]interface{}{
  896. "apiVersion": apiVersion,
  897. "kind": definition.Spec.Names.Kind,
  898. "metadata": map[string]interface{}{
  899. "name": dependentName,
  900. "ownerReferences": []interface{}{
  901. map[string]interface{}{
  902. "uid": string(persistedOwner.GetUID()),
  903. "apiVersion": apiVersion,
  904. "kind": definition.Spec.Names.Kind,
  905. "name": ownerName,
  906. },
  907. },
  908. },
  909. },
  910. }
  911. persistedDependent, err := resourceClient.Create(dependent, metav1.CreateOptions{})
  912. if err != nil {
  913. framework.Failf("failed to create dependent resource %q: %v", dependentName, err)
  914. }
  915. framework.Logf("created dependent resource %q", dependentName)
  916. // Delete the owner.
  917. background := metav1.DeletePropagationBackground
  918. err = resourceClient.Delete(ownerName, &metav1.DeleteOptions{PropagationPolicy: &background})
  919. if err != nil {
  920. framework.Failf("failed to delete owner resource %q: %v", ownerName, err)
  921. }
  922. // Create and delete an unrelated instance of the custom resource in foreground deletion mode,
  923. // so we have a signal when GC is aware of this custom resource type
  924. canaryName := names.SimpleNameGenerator.GenerateName("canary")
  925. canary := &unstructured.Unstructured{
  926. Object: map[string]interface{}{
  927. "apiVersion": apiVersion,
  928. "kind": definition.Spec.Names.Kind,
  929. "metadata": map[string]interface{}{"name": canaryName}},
  930. }
  931. _, err = resourceClient.Create(canary, metav1.CreateOptions{})
  932. if err != nil {
  933. framework.Failf("failed to create canary resource %q: %v", canaryName, err)
  934. }
  935. framework.Logf("created canary resource %q", canaryName)
  936. foreground := metav1.DeletePropagationForeground
  937. err = resourceClient.Delete(canaryName, &metav1.DeleteOptions{PropagationPolicy: &foreground})
  938. if err != nil {
  939. framework.Failf("failed to delete canary resource %q: %v", canaryName, err)
  940. }
  941. // Wait for the canary foreground finalization to complete, which means GC is aware of our new custom resource type
  942. var lastCanary *unstructured.Unstructured
  943. if err := wait.PollImmediate(5*time.Second, 3*time.Minute, func() (bool, error) {
  944. lastCanary, err = resourceClient.Get(dependentName, metav1.GetOptions{})
  945. return apierrors.IsNotFound(err), nil
  946. }); err != nil {
  947. framework.Logf("canary last state: %#v", lastCanary)
  948. framework.Failf("failed waiting for canary resource %q to be deleted", canaryName)
  949. }
  950. // Ensure the dependent is deleted.
  951. var lastDependent *unstructured.Unstructured
  952. var err2 error
  953. if err := wait.Poll(5*time.Second, 60*time.Second, func() (bool, error) {
  954. lastDependent, err2 = resourceClient.Get(dependentName, metav1.GetOptions{})
  955. return apierrors.IsNotFound(err2), nil
  956. }); err != nil {
  957. framework.Logf("owner: %#v", persistedOwner)
  958. framework.Logf("dependent: %#v", persistedDependent)
  959. framework.Logf("dependent last state: %#v", lastDependent)
  960. framework.Failf("failed waiting for dependent resource %q to be deleted", dependentName)
  961. }
  962. // Ensure the owner is deleted.
  963. _, err = resourceClient.Get(ownerName, metav1.GetOptions{})
  964. if err == nil {
  965. framework.Failf("expected owner resource %q to be deleted", ownerName)
  966. } else {
  967. if !apierrors.IsNotFound(err) {
  968. framework.Failf("unexpected error getting owner resource %q: %v", ownerName, err)
  969. }
  970. }
  971. })
  972. ginkgo.It("should support orphan deletion of custom resources", func() {
  973. config, err := framework.LoadConfig()
  974. if err != nil {
  975. framework.Failf("failed to load config: %v", err)
  976. }
  977. apiExtensionClient, err := apiextensionsclientset.NewForConfig(config)
  978. if err != nil {
  979. framework.Failf("failed to initialize apiExtensionClient: %v", err)
  980. }
  981. // Create a random custom resource definition and ensure it's available for
  982. // use.
  983. definition := apiextensionstestserver.NewRandomNameV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
  984. defer func() {
  985. err = apiextensionstestserver.DeleteV1CustomResourceDefinition(definition, apiExtensionClient)
  986. if err != nil && !apierrors.IsNotFound(err) {
  987. framework.Failf("failed to delete CustomResourceDefinition: %v", err)
  988. }
  989. }()
  990. definition, err = apiextensionstestserver.CreateNewV1CustomResourceDefinition(definition, apiExtensionClient, f.DynamicClient)
  991. if err != nil {
  992. framework.Failf("failed to create CustomResourceDefinition: %v", err)
  993. }
  994. framework.ExpectEqual(len(definition.Spec.Versions), 1, "custom resource definition should have one version")
  995. version := definition.Spec.Versions[0]
  996. // Get a client for the custom resource.
  997. gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: version.Name, Resource: definition.Spec.Names.Plural}
  998. resourceClient := f.DynamicClient.Resource(gvr)
  999. apiVersion := definition.Spec.Group + "/" + version.Name
  1000. // Create a custom owner resource.
  1001. ownerName := names.SimpleNameGenerator.GenerateName("owner")
  1002. owner := &unstructured.Unstructured{
  1003. Object: map[string]interface{}{
  1004. "apiVersion": apiVersion,
  1005. "kind": definition.Spec.Names.Kind,
  1006. "metadata": map[string]interface{}{
  1007. "name": ownerName,
  1008. },
  1009. },
  1010. }
  1011. persistedOwner, err := resourceClient.Create(owner, metav1.CreateOptions{})
  1012. if err != nil {
  1013. framework.Failf("failed to create owner resource %q: %v", ownerName, err)
  1014. }
  1015. framework.Logf("created owner resource %q", ownerName)
  1016. // Create a custom dependent resource.
  1017. dependentName := names.SimpleNameGenerator.GenerateName("dependent")
  1018. dependent := &unstructured.Unstructured{
  1019. Object: map[string]interface{}{
  1020. "apiVersion": apiVersion,
  1021. "kind": definition.Spec.Names.Kind,
  1022. "metadata": map[string]interface{}{
  1023. "name": dependentName,
  1024. "ownerReferences": []map[string]string{
  1025. {
  1026. "uid": string(persistedOwner.GetUID()),
  1027. "apiVersion": apiVersion,
  1028. "kind": definition.Spec.Names.Kind,
  1029. "name": ownerName,
  1030. },
  1031. },
  1032. },
  1033. },
  1034. }
  1035. _, err = resourceClient.Create(dependent, metav1.CreateOptions{})
  1036. if err != nil {
  1037. framework.Failf("failed to create dependent resource %q: %v", dependentName, err)
  1038. }
  1039. framework.Logf("created dependent resource %q", dependentName)
  1040. // Delete the owner and orphan the dependent.
  1041. err = resourceClient.Delete(ownerName, getOrphanOptions())
  1042. if err != nil {
  1043. framework.Failf("failed to delete owner resource %q: %v", ownerName, err)
  1044. }
  1045. ginkgo.By("wait for the owner to be deleted")
  1046. if err := wait.Poll(5*time.Second, 120*time.Second, func() (bool, error) {
  1047. _, err = resourceClient.Get(ownerName, metav1.GetOptions{})
  1048. if err == nil {
  1049. return false, nil
  1050. }
  1051. if err != nil && !apierrors.IsNotFound(err) {
  1052. return false, fmt.Errorf("failed to get owner: %v", err)
  1053. }
  1054. return true, nil
  1055. }); err != nil {
  1056. framework.Failf("timeout in waiting for the owner to be deleted: %v", err)
  1057. }
  1058. // Wait 30s and ensure the dependent is not deleted.
  1059. ginkgo.By("wait for 30 seconds to see if the garbage collector mistakenly deletes the dependent crd")
  1060. if err := wait.Poll(5*time.Second, 30*time.Second, func() (bool, error) {
  1061. _, err := resourceClient.Get(dependentName, metav1.GetOptions{})
  1062. return false, err
  1063. }); err != nil && err != wait.ErrWaitTimeout {
  1064. framework.Failf("failed to ensure the dependent is not deleted: %v", err)
  1065. }
  1066. })
  1067. ginkgo.It("should delete jobs and pods created by cronjob", func() {
  1068. e2eskipper.SkipIfMissingResource(f.DynamicClient, CronJobGroupVersionResource, f.Namespace.Name)
  1069. ginkgo.By("Create the cronjob")
  1070. cronJob := newCronJob("simple", "*/1 * * * ?")
  1071. cronJob, err := f.ClientSet.BatchV1beta1().CronJobs(f.Namespace.Name).Create(context.TODO(), cronJob, metav1.CreateOptions{})
  1072. framework.ExpectNoError(err, "failed to create cronjob: %+v, in namespace: %s", cronJob, f.Namespace.Name)
  1073. ginkgo.By("Wait for the CronJob to create new Job")
  1074. err = wait.PollImmediate(500*time.Millisecond, 2*time.Minute, func() (bool, error) {
  1075. jobs, err := f.ClientSet.BatchV1().Jobs(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
  1076. if err != nil {
  1077. return false, fmt.Errorf("failed to list jobs: %v", err)
  1078. }
  1079. return len(jobs.Items) > 0, nil
  1080. })
  1081. if err != nil {
  1082. framework.Failf("Failed to wait for the CronJob to create some Jobs: %v", err)
  1083. }
  1084. ginkgo.By("Delete the cronjob")
  1085. if err := f.ClientSet.BatchV1beta1().CronJobs(f.Namespace.Name).Delete(context.TODO(), cronJob.Name, getBackgroundOptions()); err != nil {
  1086. framework.Failf("Failed to delete the CronJob: %v", err)
  1087. }
  1088. ginkgo.By("Verify if cronjob does not leave jobs nor pods behind")
  1089. err = wait.PollImmediate(500*time.Millisecond, 1*time.Minute, func() (bool, error) {
  1090. objects := map[string]int{"CronJobs": 0, "Jobs": 0, "Pods": 0}
  1091. return verifyRemainingObjects(f, objects)
  1092. })
  1093. if err != nil {
  1094. framework.Failf("Failed to wait for all jobs and pods to be deleted: %v", err)
  1095. }
  1096. gatherMetrics(f)
  1097. })
  1098. })