resource_quota.go 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628
  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 apimachinery
  14. import (
  15. "fmt"
  16. "strconv"
  17. "time"
  18. appsv1 "k8s.io/api/apps/v1"
  19. "k8s.io/api/core/v1"
  20. schedulingv1 "k8s.io/api/scheduling/v1"
  21. "k8s.io/apimachinery/pkg/api/errors"
  22. "k8s.io/apimachinery/pkg/api/resource"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  25. "k8s.io/apimachinery/pkg/util/intstr"
  26. "k8s.io/apimachinery/pkg/util/wait"
  27. clientset "k8s.io/client-go/kubernetes"
  28. "k8s.io/kubernetes/pkg/quota/v1/evaluator/core"
  29. "k8s.io/kubernetes/test/e2e/framework"
  30. e2elog "k8s.io/kubernetes/test/e2e/framework/log"
  31. "k8s.io/kubernetes/test/utils/crd"
  32. imageutils "k8s.io/kubernetes/test/utils/image"
  33. "github.com/onsi/ginkgo"
  34. "github.com/onsi/gomega"
  35. )
  36. const (
  37. // how long to wait for a resource quota update to occur
  38. resourceQuotaTimeout = 30 * time.Second
  39. podName = "pfpod"
  40. )
  41. var classGold = "gold"
  42. var extendedResourceName = "example.com/dongle"
  43. var _ = SIGDescribe("ResourceQuota", func() {
  44. f := framework.NewDefaultFramework("resourcequota")
  45. ginkgo.It("should create a ResourceQuota and ensure its status is promptly calculated.", func() {
  46. ginkgo.By("Counting existing ResourceQuota")
  47. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  48. framework.ExpectNoError(err)
  49. ginkgo.By("Creating a ResourceQuota")
  50. quotaName := "test-quota"
  51. resourceQuota := newTestResourceQuota(quotaName)
  52. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  53. framework.ExpectNoError(err)
  54. ginkgo.By("Ensuring resource quota status is calculated")
  55. usedResources := v1.ResourceList{}
  56. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  57. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  58. framework.ExpectNoError(err)
  59. })
  60. ginkgo.It("should create a ResourceQuota and capture the life of a service.", func() {
  61. ginkgo.By("Counting existing ResourceQuota")
  62. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  63. framework.ExpectNoError(err)
  64. ginkgo.By("Creating a ResourceQuota")
  65. quotaName := "test-quota"
  66. resourceQuota := newTestResourceQuota(quotaName)
  67. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  68. framework.ExpectNoError(err)
  69. ginkgo.By("Ensuring resource quota status is calculated")
  70. usedResources := v1.ResourceList{}
  71. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  72. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  73. framework.ExpectNoError(err)
  74. ginkgo.By("Creating a Service")
  75. service := newTestServiceForQuota("test-service", v1.ServiceTypeClusterIP)
  76. service, err = f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(service)
  77. framework.ExpectNoError(err)
  78. ginkgo.By("Ensuring resource quota status captures service creation")
  79. usedResources = v1.ResourceList{}
  80. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  81. usedResources[v1.ResourceServices] = resource.MustParse("1")
  82. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  83. framework.ExpectNoError(err)
  84. ginkgo.By("Deleting a Service")
  85. err = f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(service.Name, nil)
  86. framework.ExpectNoError(err)
  87. ginkgo.By("Ensuring resource quota status released usage")
  88. usedResources[v1.ResourceServices] = resource.MustParse("0")
  89. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  90. framework.ExpectNoError(err)
  91. })
  92. ginkgo.It("should create a ResourceQuota and capture the life of a secret.", func() {
  93. ginkgo.By("Discovering how many secrets are in namespace by default")
  94. found, unchanged := 0, 0
  95. wait.Poll(1*time.Second, 30*time.Second, func() (bool, error) {
  96. secrets, err := f.ClientSet.CoreV1().Secrets(f.Namespace.Name).List(metav1.ListOptions{})
  97. framework.ExpectNoError(err)
  98. if len(secrets.Items) == found {
  99. // loop until the number of secrets has stabilized for 5 seconds
  100. unchanged++
  101. return unchanged > 4, nil
  102. }
  103. unchanged = 0
  104. found = len(secrets.Items)
  105. return false, nil
  106. })
  107. defaultSecrets := fmt.Sprintf("%d", found)
  108. hardSecrets := fmt.Sprintf("%d", found+1)
  109. ginkgo.By("Counting existing ResourceQuota")
  110. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  111. framework.ExpectNoError(err)
  112. ginkgo.By("Creating a ResourceQuota")
  113. quotaName := "test-quota"
  114. resourceQuota := newTestResourceQuota(quotaName)
  115. resourceQuota.Spec.Hard[v1.ResourceSecrets] = resource.MustParse(hardSecrets)
  116. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  117. framework.ExpectNoError(err)
  118. ginkgo.By("Ensuring resource quota status is calculated")
  119. usedResources := v1.ResourceList{}
  120. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  121. usedResources[v1.ResourceSecrets] = resource.MustParse(defaultSecrets)
  122. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  123. framework.ExpectNoError(err)
  124. ginkgo.By("Creating a Secret")
  125. secret := newTestSecretForQuota("test-secret")
  126. secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret)
  127. framework.ExpectNoError(err)
  128. ginkgo.By("Ensuring resource quota status captures secret creation")
  129. usedResources = v1.ResourceList{}
  130. usedResources[v1.ResourceSecrets] = resource.MustParse(hardSecrets)
  131. // we expect there to be two secrets because each namespace will receive
  132. // a service account token secret by default
  133. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  134. framework.ExpectNoError(err)
  135. ginkgo.By("Deleting a secret")
  136. err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(secret.Name, nil)
  137. framework.ExpectNoError(err)
  138. ginkgo.By("Ensuring resource quota status released usage")
  139. usedResources[v1.ResourceSecrets] = resource.MustParse(defaultSecrets)
  140. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  141. framework.ExpectNoError(err)
  142. })
  143. ginkgo.It("should create a ResourceQuota and capture the life of a pod.", func() {
  144. ginkgo.By("Counting existing ResourceQuota")
  145. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  146. framework.ExpectNoError(err)
  147. ginkgo.By("Creating a ResourceQuota")
  148. quotaName := "test-quota"
  149. resourceQuota := newTestResourceQuota(quotaName)
  150. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  151. framework.ExpectNoError(err)
  152. ginkgo.By("Ensuring resource quota status is calculated")
  153. usedResources := v1.ResourceList{}
  154. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  155. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  156. framework.ExpectNoError(err)
  157. ginkgo.By("Creating a Pod that fits quota")
  158. podName := "test-pod"
  159. requests := v1.ResourceList{}
  160. limits := v1.ResourceList{}
  161. requests[v1.ResourceCPU] = resource.MustParse("500m")
  162. requests[v1.ResourceMemory] = resource.MustParse("252Mi")
  163. requests[v1.ResourceEphemeralStorage] = resource.MustParse("30Gi")
  164. requests[v1.ResourceName(extendedResourceName)] = resource.MustParse("2")
  165. limits[v1.ResourceName(extendedResourceName)] = resource.MustParse("2")
  166. pod := newTestPodForQuota(f, podName, requests, limits)
  167. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  168. framework.ExpectNoError(err)
  169. podToUpdate := pod
  170. ginkgo.By("Ensuring ResourceQuota status captures the pod usage")
  171. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  172. usedResources[v1.ResourcePods] = resource.MustParse("1")
  173. usedResources[v1.ResourceCPU] = requests[v1.ResourceCPU]
  174. usedResources[v1.ResourceMemory] = requests[v1.ResourceMemory]
  175. usedResources[v1.ResourceEphemeralStorage] = requests[v1.ResourceEphemeralStorage]
  176. usedResources[v1.ResourceName(v1.DefaultResourceRequestsPrefix+extendedResourceName)] = requests[v1.ResourceName(extendedResourceName)]
  177. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  178. framework.ExpectNoError(err)
  179. ginkgo.By("Not allowing a pod to be created that exceeds remaining quota")
  180. requests = v1.ResourceList{}
  181. requests[v1.ResourceCPU] = resource.MustParse("600m")
  182. requests[v1.ResourceMemory] = resource.MustParse("100Mi")
  183. pod = newTestPodForQuota(f, "fail-pod", requests, v1.ResourceList{})
  184. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  185. framework.ExpectError(err)
  186. ginkgo.By("Not allowing a pod to be created that exceeds remaining quota(validation on extended resources)")
  187. requests = v1.ResourceList{}
  188. limits = v1.ResourceList{}
  189. requests[v1.ResourceCPU] = resource.MustParse("500m")
  190. requests[v1.ResourceMemory] = resource.MustParse("100Mi")
  191. requests[v1.ResourceEphemeralStorage] = resource.MustParse("30Gi")
  192. requests[v1.ResourceName(extendedResourceName)] = resource.MustParse("2")
  193. limits[v1.ResourceName(extendedResourceName)] = resource.MustParse("2")
  194. pod = newTestPodForQuota(f, "fail-pod-for-extended-resource", requests, limits)
  195. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  196. framework.ExpectError(err)
  197. ginkgo.By("Ensuring a pod cannot update its resource requirements")
  198. // a pod cannot dynamically update its resource requirements.
  199. requests = v1.ResourceList{}
  200. requests[v1.ResourceCPU] = resource.MustParse("100m")
  201. requests[v1.ResourceMemory] = resource.MustParse("100Mi")
  202. requests[v1.ResourceEphemeralStorage] = resource.MustParse("10Gi")
  203. podToUpdate.Spec.Containers[0].Resources.Requests = requests
  204. _, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Update(podToUpdate)
  205. framework.ExpectError(err)
  206. ginkgo.By("Ensuring attempts to update pod resource requirements did not change quota usage")
  207. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  208. framework.ExpectNoError(err)
  209. ginkgo.By("Deleting the pod")
  210. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(podName, metav1.NewDeleteOptions(0))
  211. framework.ExpectNoError(err)
  212. ginkgo.By("Ensuring resource quota status released the pod usage")
  213. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  214. usedResources[v1.ResourcePods] = resource.MustParse("0")
  215. usedResources[v1.ResourceCPU] = resource.MustParse("0")
  216. usedResources[v1.ResourceMemory] = resource.MustParse("0")
  217. usedResources[v1.ResourceEphemeralStorage] = resource.MustParse("0")
  218. usedResources[v1.ResourceName(v1.DefaultResourceRequestsPrefix+extendedResourceName)] = resource.MustParse("0")
  219. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  220. framework.ExpectNoError(err)
  221. })
  222. ginkgo.It("should create a ResourceQuota and capture the life of a configMap.", func() {
  223. found, unchanged := 0, 0
  224. wait.Poll(1*time.Second, 30*time.Second, func() (bool, error) {
  225. configmaps, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).List(metav1.ListOptions{})
  226. framework.ExpectNoError(err)
  227. if len(configmaps.Items) == found {
  228. // loop until the number of configmaps has stabilized for 5 seconds
  229. unchanged++
  230. return unchanged > 4, nil
  231. }
  232. unchanged = 0
  233. found = len(configmaps.Items)
  234. return false, nil
  235. })
  236. defaultConfigMaps := fmt.Sprintf("%d", found)
  237. hardConfigMaps := fmt.Sprintf("%d", found+1)
  238. ginkgo.By("Counting existing ResourceQuota")
  239. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  240. framework.ExpectNoError(err)
  241. ginkgo.By("Creating a ResourceQuota")
  242. quotaName := "test-quota"
  243. resourceQuota := newTestResourceQuota(quotaName)
  244. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  245. framework.ExpectNoError(err)
  246. ginkgo.By("Ensuring resource quota status is calculated")
  247. usedResources := v1.ResourceList{}
  248. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  249. usedResources[v1.ResourceConfigMaps] = resource.MustParse(defaultConfigMaps)
  250. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  251. framework.ExpectNoError(err)
  252. ginkgo.By("Creating a ConfigMap")
  253. configMap := newTestConfigMapForQuota("test-configmap")
  254. configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap)
  255. framework.ExpectNoError(err)
  256. ginkgo.By("Ensuring resource quota status captures configMap creation")
  257. usedResources = v1.ResourceList{}
  258. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  259. // we expect there to be two configmaps because each namespace will receive
  260. // a ca.crt configmap by default.
  261. // ref:https://github.com/kubernetes/kubernetes/pull/68812
  262. usedResources[v1.ResourceConfigMaps] = resource.MustParse(hardConfigMaps)
  263. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  264. framework.ExpectNoError(err)
  265. ginkgo.By("Deleting a ConfigMap")
  266. err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(configMap.Name, nil)
  267. framework.ExpectNoError(err)
  268. ginkgo.By("Ensuring resource quota status released usage")
  269. usedResources[v1.ResourceConfigMaps] = resource.MustParse(defaultConfigMaps)
  270. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  271. framework.ExpectNoError(err)
  272. })
  273. ginkgo.It("should create a ResourceQuota and capture the life of a replication controller.", func() {
  274. ginkgo.By("Counting existing ResourceQuota")
  275. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  276. framework.ExpectNoError(err)
  277. ginkgo.By("Creating a ResourceQuota")
  278. quotaName := "test-quota"
  279. resourceQuota := newTestResourceQuota(quotaName)
  280. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  281. framework.ExpectNoError(err)
  282. ginkgo.By("Ensuring resource quota status is calculated")
  283. usedResources := v1.ResourceList{}
  284. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  285. usedResources[v1.ResourceReplicationControllers] = resource.MustParse("0")
  286. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  287. framework.ExpectNoError(err)
  288. ginkgo.By("Creating a ReplicationController")
  289. replicationController := newTestReplicationControllerForQuota("test-rc", "nginx", 0)
  290. replicationController, err = f.ClientSet.CoreV1().ReplicationControllers(f.Namespace.Name).Create(replicationController)
  291. framework.ExpectNoError(err)
  292. ginkgo.By("Ensuring resource quota status captures replication controller creation")
  293. usedResources = v1.ResourceList{}
  294. usedResources[v1.ResourceReplicationControllers] = resource.MustParse("1")
  295. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  296. framework.ExpectNoError(err)
  297. ginkgo.By("Deleting a ReplicationController")
  298. err = f.ClientSet.CoreV1().ReplicationControllers(f.Namespace.Name).Delete(replicationController.Name, nil)
  299. framework.ExpectNoError(err)
  300. ginkgo.By("Ensuring resource quota status released usage")
  301. usedResources[v1.ResourceReplicationControllers] = resource.MustParse("0")
  302. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  303. framework.ExpectNoError(err)
  304. })
  305. ginkgo.It("should create a ResourceQuota and capture the life of a replica set.", func() {
  306. ginkgo.By("Counting existing ResourceQuota")
  307. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  308. framework.ExpectNoError(err)
  309. ginkgo.By("Creating a ResourceQuota")
  310. quotaName := "test-quota"
  311. resourceQuota := newTestResourceQuota(quotaName)
  312. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  313. framework.ExpectNoError(err)
  314. ginkgo.By("Ensuring resource quota status is calculated")
  315. usedResources := v1.ResourceList{}
  316. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  317. usedResources[v1.ResourceName("count/replicasets.apps")] = resource.MustParse("0")
  318. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  319. framework.ExpectNoError(err)
  320. ginkgo.By("Creating a ReplicaSet")
  321. replicaSet := newTestReplicaSetForQuota("test-rs", "nginx", 0)
  322. replicaSet, err = f.ClientSet.AppsV1().ReplicaSets(f.Namespace.Name).Create(replicaSet)
  323. framework.ExpectNoError(err)
  324. ginkgo.By("Ensuring resource quota status captures replicaset creation")
  325. usedResources = v1.ResourceList{}
  326. usedResources[v1.ResourceName("count/replicasets.apps")] = resource.MustParse("1")
  327. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  328. framework.ExpectNoError(err)
  329. ginkgo.By("Deleting a ReplicaSet")
  330. err = f.ClientSet.AppsV1().ReplicaSets(f.Namespace.Name).Delete(replicaSet.Name, nil)
  331. framework.ExpectNoError(err)
  332. ginkgo.By("Ensuring resource quota status released usage")
  333. usedResources[v1.ResourceName("count/replicasets.apps")] = resource.MustParse("0")
  334. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  335. framework.ExpectNoError(err)
  336. })
  337. ginkgo.It("should create a ResourceQuota and capture the life of a persistent volume claim. [sig-storage]", func() {
  338. ginkgo.By("Counting existing ResourceQuota")
  339. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  340. framework.ExpectNoError(err)
  341. ginkgo.By("Creating a ResourceQuota")
  342. quotaName := "test-quota"
  343. resourceQuota := newTestResourceQuota(quotaName)
  344. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  345. framework.ExpectNoError(err)
  346. ginkgo.By("Ensuring resource quota status is calculated")
  347. usedResources := v1.ResourceList{}
  348. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  349. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("0")
  350. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("0")
  351. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  352. framework.ExpectNoError(err)
  353. ginkgo.By("Creating a PersistentVolumeClaim")
  354. pvc := newTestPersistentVolumeClaimForQuota("test-claim")
  355. pvc, err = f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Create(pvc)
  356. framework.ExpectNoError(err)
  357. ginkgo.By("Ensuring resource quota status captures persistent volume claim creation")
  358. usedResources = v1.ResourceList{}
  359. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("1")
  360. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("1Gi")
  361. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  362. framework.ExpectNoError(err)
  363. ginkgo.By("Deleting a PersistentVolumeClaim")
  364. err = f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Delete(pvc.Name, nil)
  365. framework.ExpectNoError(err)
  366. ginkgo.By("Ensuring resource quota status released usage")
  367. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("0")
  368. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("0")
  369. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  370. framework.ExpectNoError(err)
  371. })
  372. ginkgo.It("should create a ResourceQuota and capture the life of a persistent volume claim with a storage class. [sig-storage]", func() {
  373. ginkgo.By("Counting existing ResourceQuota")
  374. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  375. framework.ExpectNoError(err)
  376. ginkgo.By("Creating a ResourceQuota")
  377. quotaName := "test-quota"
  378. resourceQuota := newTestResourceQuota(quotaName)
  379. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  380. framework.ExpectNoError(err)
  381. ginkgo.By("Ensuring resource quota status is calculated")
  382. usedResources := v1.ResourceList{}
  383. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  384. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("0")
  385. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("0")
  386. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourcePersistentVolumeClaims)] = resource.MustParse("0")
  387. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourceRequestsStorage)] = resource.MustParse("0")
  388. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  389. framework.ExpectNoError(err)
  390. ginkgo.By("Creating a PersistentVolumeClaim with storage class")
  391. pvc := newTestPersistentVolumeClaimForQuota("test-claim")
  392. pvc.Spec.StorageClassName = &classGold
  393. pvc, err = f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Create(pvc)
  394. framework.ExpectNoError(err)
  395. ginkgo.By("Ensuring resource quota status captures persistent volume claim creation")
  396. usedResources = v1.ResourceList{}
  397. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("1")
  398. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("1Gi")
  399. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourcePersistentVolumeClaims)] = resource.MustParse("1")
  400. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourceRequestsStorage)] = resource.MustParse("1Gi")
  401. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  402. framework.ExpectNoError(err)
  403. ginkgo.By("Deleting a PersistentVolumeClaim")
  404. err = f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Delete(pvc.Name, nil)
  405. framework.ExpectNoError(err)
  406. ginkgo.By("Ensuring resource quota status released usage")
  407. usedResources[v1.ResourcePersistentVolumeClaims] = resource.MustParse("0")
  408. usedResources[v1.ResourceRequestsStorage] = resource.MustParse("0")
  409. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourcePersistentVolumeClaims)] = resource.MustParse("0")
  410. usedResources[core.V1ResourceByStorageClass(classGold, v1.ResourceRequestsStorage)] = resource.MustParse("0")
  411. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  412. framework.ExpectNoError(err)
  413. })
  414. ginkgo.It("should create a ResourceQuota and capture the life of a custom resource.", func() {
  415. ginkgo.By("Creating a Custom Resource Definition")
  416. testcrd, err := crd.CreateTestCRD(f)
  417. framework.ExpectNoError(err)
  418. defer testcrd.CleanUp()
  419. countResourceName := "count/" + testcrd.Crd.Spec.Names.Plural + "." + testcrd.Crd.Spec.Group
  420. // resourcequota controller needs to take 30 seconds at most to detect the new custom resource.
  421. // in order to make sure the resourcequota controller knows this resource, we create one test
  422. // resourcequota object, and triggering updates on it until the status is updated.
  423. quotaName := "quota-for-" + testcrd.Crd.Spec.Names.Plural
  424. resourceQuota, err := createResourceQuota(f.ClientSet, f.Namespace.Name, &v1.ResourceQuota{
  425. ObjectMeta: metav1.ObjectMeta{Name: quotaName},
  426. Spec: v1.ResourceQuotaSpec{
  427. Hard: v1.ResourceList{
  428. v1.ResourceName(countResourceName): resource.MustParse("0"),
  429. },
  430. },
  431. })
  432. err = updateResourceQuotaUntilUsageAppears(f.ClientSet, f.Namespace.Name, quotaName, v1.ResourceName(countResourceName))
  433. framework.ExpectNoError(err)
  434. err = f.ClientSet.CoreV1().ResourceQuotas(f.Namespace.Name).Delete(quotaName, nil)
  435. framework.ExpectNoError(err)
  436. ginkgo.By("Counting existing ResourceQuota")
  437. c, err := countResourceQuota(f.ClientSet, f.Namespace.Name)
  438. framework.ExpectNoError(err)
  439. ginkgo.By("Creating a ResourceQuota")
  440. quotaName = "test-quota"
  441. resourceQuota = newTestResourceQuota(quotaName)
  442. resourceQuota.Spec.Hard[v1.ResourceName(countResourceName)] = resource.MustParse("1")
  443. resourceQuota, err = createResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuota)
  444. framework.ExpectNoError(err)
  445. ginkgo.By("Ensuring resource quota status is calculated")
  446. usedResources := v1.ResourceList{}
  447. usedResources[v1.ResourceQuotas] = resource.MustParse(strconv.Itoa(c + 1))
  448. usedResources[v1.ResourceName(countResourceName)] = resource.MustParse("0")
  449. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  450. framework.ExpectNoError(err)
  451. ginkgo.By("Creating a custom resource")
  452. resourceClient := testcrd.DynamicClients["v1"]
  453. testcr, err := instantiateCustomResource(&unstructured.Unstructured{
  454. Object: map[string]interface{}{
  455. "apiVersion": testcrd.Crd.Spec.Group + "/" + testcrd.Crd.Spec.Versions[0].Name,
  456. "kind": testcrd.Crd.Spec.Names.Kind,
  457. "metadata": map[string]interface{}{
  458. "name": "test-cr-1",
  459. },
  460. },
  461. }, resourceClient, testcrd.Crd)
  462. framework.ExpectNoError(err)
  463. ginkgo.By("Ensuring resource quota status captures custom resource creation")
  464. usedResources = v1.ResourceList{}
  465. usedResources[v1.ResourceName(countResourceName)] = resource.MustParse("1")
  466. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  467. framework.ExpectNoError(err)
  468. ginkgo.By("Creating a second custom resource")
  469. _, err = instantiateCustomResource(&unstructured.Unstructured{
  470. Object: map[string]interface{}{
  471. "apiVersion": testcrd.Crd.Spec.Group + "/" + testcrd.Crd.Spec.Versions[0].Name,
  472. "kind": testcrd.Crd.Spec.Names.Kind,
  473. "metadata": map[string]interface{}{
  474. "name": "test-cr-2",
  475. },
  476. },
  477. }, resourceClient, testcrd.Crd)
  478. // since we only give one quota, this creation should fail.
  479. framework.ExpectError(err)
  480. ginkgo.By("Deleting a custom resource")
  481. err = deleteCustomResource(resourceClient, testcr.GetName())
  482. framework.ExpectNoError(err)
  483. ginkgo.By("Ensuring resource quota status released usage")
  484. usedResources[v1.ResourceName(countResourceName)] = resource.MustParse("0")
  485. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, quotaName, usedResources)
  486. framework.ExpectNoError(err)
  487. })
  488. ginkgo.It("should verify ResourceQuota with terminating scopes.", func() {
  489. ginkgo.By("Creating a ResourceQuota with terminating scope")
  490. quotaTerminatingName := "quota-terminating"
  491. resourceQuotaTerminating, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScope(quotaTerminatingName, v1.ResourceQuotaScopeTerminating))
  492. framework.ExpectNoError(err)
  493. ginkgo.By("Ensuring ResourceQuota status is calculated")
  494. usedResources := v1.ResourceList{}
  495. usedResources[v1.ResourcePods] = resource.MustParse("0")
  496. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  497. framework.ExpectNoError(err)
  498. ginkgo.By("Creating a ResourceQuota with not terminating scope")
  499. quotaNotTerminatingName := "quota-not-terminating"
  500. resourceQuotaNotTerminating, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScope(quotaNotTerminatingName, v1.ResourceQuotaScopeNotTerminating))
  501. framework.ExpectNoError(err)
  502. ginkgo.By("Ensuring ResourceQuota status is calculated")
  503. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  504. framework.ExpectNoError(err)
  505. ginkgo.By("Creating a long running pod")
  506. podName := "test-pod"
  507. requests := v1.ResourceList{}
  508. requests[v1.ResourceCPU] = resource.MustParse("500m")
  509. requests[v1.ResourceMemory] = resource.MustParse("200Mi")
  510. limits := v1.ResourceList{}
  511. limits[v1.ResourceCPU] = resource.MustParse("1")
  512. limits[v1.ResourceMemory] = resource.MustParse("400Mi")
  513. pod := newTestPodForQuota(f, podName, requests, limits)
  514. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  515. framework.ExpectNoError(err)
  516. ginkgo.By("Ensuring resource quota with not terminating scope captures the pod usage")
  517. usedResources[v1.ResourcePods] = resource.MustParse("1")
  518. usedResources[v1.ResourceRequestsCPU] = requests[v1.ResourceCPU]
  519. usedResources[v1.ResourceRequestsMemory] = requests[v1.ResourceMemory]
  520. usedResources[v1.ResourceLimitsCPU] = limits[v1.ResourceCPU]
  521. usedResources[v1.ResourceLimitsMemory] = limits[v1.ResourceMemory]
  522. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  523. framework.ExpectNoError(err)
  524. ginkgo.By("Ensuring resource quota with terminating scope ignored the pod usage")
  525. usedResources[v1.ResourcePods] = resource.MustParse("0")
  526. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  527. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  528. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  529. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  530. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  531. framework.ExpectNoError(err)
  532. ginkgo.By("Deleting the pod")
  533. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(podName, metav1.NewDeleteOptions(0))
  534. framework.ExpectNoError(err)
  535. ginkgo.By("Ensuring resource quota status released the pod usage")
  536. usedResources[v1.ResourcePods] = resource.MustParse("0")
  537. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  538. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  539. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  540. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  541. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  542. framework.ExpectNoError(err)
  543. ginkgo.By("Creating a terminating pod")
  544. podName = "terminating-pod"
  545. pod = newTestPodForQuota(f, podName, requests, limits)
  546. activeDeadlineSeconds := int64(3600)
  547. pod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
  548. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  549. framework.ExpectNoError(err)
  550. ginkgo.By("Ensuring resource quota with terminating scope captures the pod usage")
  551. usedResources[v1.ResourcePods] = resource.MustParse("1")
  552. usedResources[v1.ResourceRequestsCPU] = requests[v1.ResourceCPU]
  553. usedResources[v1.ResourceRequestsMemory] = requests[v1.ResourceMemory]
  554. usedResources[v1.ResourceLimitsCPU] = limits[v1.ResourceCPU]
  555. usedResources[v1.ResourceLimitsMemory] = limits[v1.ResourceMemory]
  556. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  557. framework.ExpectNoError(err)
  558. ginkgo.By("Ensuring resource quota with not terminating scope ignored the pod usage")
  559. usedResources[v1.ResourcePods] = resource.MustParse("0")
  560. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  561. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  562. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  563. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  564. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  565. framework.ExpectNoError(err)
  566. ginkgo.By("Deleting the pod")
  567. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(podName, metav1.NewDeleteOptions(0))
  568. framework.ExpectNoError(err)
  569. ginkgo.By("Ensuring resource quota status released the pod usage")
  570. usedResources[v1.ResourcePods] = resource.MustParse("0")
  571. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  572. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  573. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  574. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  575. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  576. framework.ExpectNoError(err)
  577. })
  578. ginkgo.It("should verify ResourceQuota with best effort scope.", func() {
  579. ginkgo.By("Creating a ResourceQuota with best effort scope")
  580. resourceQuotaBestEffort, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScope("quota-besteffort", v1.ResourceQuotaScopeBestEffort))
  581. framework.ExpectNoError(err)
  582. ginkgo.By("Ensuring ResourceQuota status is calculated")
  583. usedResources := v1.ResourceList{}
  584. usedResources[v1.ResourcePods] = resource.MustParse("0")
  585. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  586. framework.ExpectNoError(err)
  587. ginkgo.By("Creating a ResourceQuota with not best effort scope")
  588. resourceQuotaNotBestEffort, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScope("quota-not-besteffort", v1.ResourceQuotaScopeNotBestEffort))
  589. framework.ExpectNoError(err)
  590. ginkgo.By("Ensuring ResourceQuota status is calculated")
  591. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  592. framework.ExpectNoError(err)
  593. ginkgo.By("Creating a best-effort pod")
  594. pod := newTestPodForQuota(f, podName, v1.ResourceList{}, v1.ResourceList{})
  595. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  596. framework.ExpectNoError(err)
  597. ginkgo.By("Ensuring resource quota with best effort scope captures the pod usage")
  598. usedResources[v1.ResourcePods] = resource.MustParse("1")
  599. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  600. framework.ExpectNoError(err)
  601. ginkgo.By("Ensuring resource quota with not best effort ignored the pod usage")
  602. usedResources[v1.ResourcePods] = resource.MustParse("0")
  603. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  604. framework.ExpectNoError(err)
  605. ginkgo.By("Deleting the pod")
  606. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  607. framework.ExpectNoError(err)
  608. ginkgo.By("Ensuring resource quota status released the pod usage")
  609. usedResources[v1.ResourcePods] = resource.MustParse("0")
  610. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  611. framework.ExpectNoError(err)
  612. ginkgo.By("Creating a not best-effort pod")
  613. requests := v1.ResourceList{}
  614. requests[v1.ResourceCPU] = resource.MustParse("500m")
  615. requests[v1.ResourceMemory] = resource.MustParse("200Mi")
  616. limits := v1.ResourceList{}
  617. limits[v1.ResourceCPU] = resource.MustParse("1")
  618. limits[v1.ResourceMemory] = resource.MustParse("400Mi")
  619. pod = newTestPodForQuota(f, "burstable-pod", requests, limits)
  620. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  621. framework.ExpectNoError(err)
  622. ginkgo.By("Ensuring resource quota with not best effort scope captures the pod usage")
  623. usedResources[v1.ResourcePods] = resource.MustParse("1")
  624. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  625. framework.ExpectNoError(err)
  626. ginkgo.By("Ensuring resource quota with best effort scope ignored the pod usage")
  627. usedResources[v1.ResourcePods] = resource.MustParse("0")
  628. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  629. framework.ExpectNoError(err)
  630. ginkgo.By("Deleting the pod")
  631. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  632. framework.ExpectNoError(err)
  633. ginkgo.By("Ensuring resource quota status released the pod usage")
  634. usedResources[v1.ResourcePods] = resource.MustParse("0")
  635. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  636. framework.ExpectNoError(err)
  637. })
  638. ginkgo.It("Should be able to update and delete ResourceQuota.", func() {
  639. client := f.ClientSet
  640. ns := f.Namespace.Name
  641. ginkgo.By("Creating a ResourceQuota")
  642. quotaName := "test-quota"
  643. resourceQuota := &v1.ResourceQuota{
  644. Spec: v1.ResourceQuotaSpec{
  645. Hard: v1.ResourceList{},
  646. },
  647. }
  648. resourceQuota.ObjectMeta.Name = quotaName
  649. resourceQuota.Spec.Hard[v1.ResourceCPU] = resource.MustParse("1")
  650. resourceQuota.Spec.Hard[v1.ResourceMemory] = resource.MustParse("500Mi")
  651. _, err := createResourceQuota(client, ns, resourceQuota)
  652. framework.ExpectNoError(err)
  653. ginkgo.By("Getting a ResourceQuota")
  654. resourceQuotaResult, err := client.CoreV1().ResourceQuotas(ns).Get(quotaName, metav1.GetOptions{})
  655. framework.ExpectNoError(err)
  656. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceCPU]).To(gomega.Equal(resource.MustParse("1")))
  657. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceMemory]).To(gomega.Equal(resource.MustParse("500Mi")))
  658. ginkgo.By("Updating a ResourceQuota")
  659. resourceQuota.Spec.Hard[v1.ResourceCPU] = resource.MustParse("2")
  660. resourceQuota.Spec.Hard[v1.ResourceMemory] = resource.MustParse("1Gi")
  661. resourceQuotaResult, err = client.CoreV1().ResourceQuotas(ns).Update(resourceQuota)
  662. framework.ExpectNoError(err)
  663. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceCPU]).To(gomega.Equal(resource.MustParse("2")))
  664. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceMemory]).To(gomega.Equal(resource.MustParse("1Gi")))
  665. ginkgo.By("Verifying a ResourceQuota was modified")
  666. resourceQuotaResult, err = client.CoreV1().ResourceQuotas(ns).Get(quotaName, metav1.GetOptions{})
  667. framework.ExpectNoError(err)
  668. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceCPU]).To(gomega.Equal(resource.MustParse("2")))
  669. gomega.Expect(resourceQuotaResult.Spec.Hard[v1.ResourceMemory]).To(gomega.Equal(resource.MustParse("1Gi")))
  670. ginkgo.By("Deleting a ResourceQuota")
  671. err = deleteResourceQuota(client, ns, quotaName)
  672. framework.ExpectNoError(err)
  673. ginkgo.By("Verifying the deleted ResourceQuota")
  674. _, err = client.CoreV1().ResourceQuotas(ns).Get(quotaName, metav1.GetOptions{})
  675. gomega.Expect(errors.IsNotFound(err)).To(gomega.Equal(true))
  676. })
  677. })
  678. var _ = SIGDescribe("ResourceQuota [Feature:ScopeSelectors]", func() {
  679. f := framework.NewDefaultFramework("scope-selectors")
  680. ginkgo.It("should verify ResourceQuota with best effort scope using scope-selectors.", func() {
  681. ginkgo.By("Creating a ResourceQuota with best effort scope")
  682. resourceQuotaBestEffort, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeSelector("quota-besteffort", v1.ResourceQuotaScopeBestEffort))
  683. framework.ExpectNoError(err)
  684. ginkgo.By("Ensuring ResourceQuota status is calculated")
  685. usedResources := v1.ResourceList{}
  686. usedResources[v1.ResourcePods] = resource.MustParse("0")
  687. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  688. framework.ExpectNoError(err)
  689. ginkgo.By("Creating a ResourceQuota with not best effort scope")
  690. resourceQuotaNotBestEffort, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeSelector("quota-not-besteffort", v1.ResourceQuotaScopeNotBestEffort))
  691. framework.ExpectNoError(err)
  692. ginkgo.By("Ensuring ResourceQuota status is calculated")
  693. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  694. framework.ExpectNoError(err)
  695. ginkgo.By("Creating a best-effort pod")
  696. pod := newTestPodForQuota(f, podName, v1.ResourceList{}, v1.ResourceList{})
  697. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  698. framework.ExpectNoError(err)
  699. ginkgo.By("Ensuring resource quota with best effort scope captures the pod usage")
  700. usedResources[v1.ResourcePods] = resource.MustParse("1")
  701. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  702. framework.ExpectNoError(err)
  703. ginkgo.By("Ensuring resource quota with not best effort ignored the pod usage")
  704. usedResources[v1.ResourcePods] = resource.MustParse("0")
  705. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  706. framework.ExpectNoError(err)
  707. ginkgo.By("Deleting the pod")
  708. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  709. framework.ExpectNoError(err)
  710. ginkgo.By("Ensuring resource quota status released the pod usage")
  711. usedResources[v1.ResourcePods] = resource.MustParse("0")
  712. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  713. framework.ExpectNoError(err)
  714. ginkgo.By("Creating a not best-effort pod")
  715. requests := v1.ResourceList{}
  716. requests[v1.ResourceCPU] = resource.MustParse("500m")
  717. requests[v1.ResourceMemory] = resource.MustParse("200Mi")
  718. limits := v1.ResourceList{}
  719. limits[v1.ResourceCPU] = resource.MustParse("1")
  720. limits[v1.ResourceMemory] = resource.MustParse("400Mi")
  721. pod = newTestPodForQuota(f, "burstable-pod", requests, limits)
  722. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  723. framework.ExpectNoError(err)
  724. ginkgo.By("Ensuring resource quota with not best effort scope captures the pod usage")
  725. usedResources[v1.ResourcePods] = resource.MustParse("1")
  726. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  727. framework.ExpectNoError(err)
  728. ginkgo.By("Ensuring resource quota with best effort scope ignored the pod usage")
  729. usedResources[v1.ResourcePods] = resource.MustParse("0")
  730. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaBestEffort.Name, usedResources)
  731. framework.ExpectNoError(err)
  732. ginkgo.By("Deleting the pod")
  733. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  734. framework.ExpectNoError(err)
  735. ginkgo.By("Ensuring resource quota status released the pod usage")
  736. usedResources[v1.ResourcePods] = resource.MustParse("0")
  737. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotBestEffort.Name, usedResources)
  738. framework.ExpectNoError(err)
  739. })
  740. ginkgo.It("should verify ResourceQuota with terminating scopes through scope selectors.", func() {
  741. ginkgo.By("Creating a ResourceQuota with terminating scope")
  742. quotaTerminatingName := "quota-terminating"
  743. resourceQuotaTerminating, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeSelector(quotaTerminatingName, v1.ResourceQuotaScopeTerminating))
  744. framework.ExpectNoError(err)
  745. ginkgo.By("Ensuring ResourceQuota status is calculated")
  746. usedResources := v1.ResourceList{}
  747. usedResources[v1.ResourcePods] = resource.MustParse("0")
  748. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  749. framework.ExpectNoError(err)
  750. ginkgo.By("Creating a ResourceQuota with not terminating scope")
  751. quotaNotTerminatingName := "quota-not-terminating"
  752. resourceQuotaNotTerminating, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeSelector(quotaNotTerminatingName, v1.ResourceQuotaScopeNotTerminating))
  753. framework.ExpectNoError(err)
  754. ginkgo.By("Ensuring ResourceQuota status is calculated")
  755. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  756. framework.ExpectNoError(err)
  757. ginkgo.By("Creating a long running pod")
  758. podName := "test-pod"
  759. requests := v1.ResourceList{}
  760. requests[v1.ResourceCPU] = resource.MustParse("500m")
  761. requests[v1.ResourceMemory] = resource.MustParse("200Mi")
  762. limits := v1.ResourceList{}
  763. limits[v1.ResourceCPU] = resource.MustParse("1")
  764. limits[v1.ResourceMemory] = resource.MustParse("400Mi")
  765. pod := newTestPodForQuota(f, podName, requests, limits)
  766. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  767. framework.ExpectNoError(err)
  768. ginkgo.By("Ensuring resource quota with not terminating scope captures the pod usage")
  769. usedResources[v1.ResourcePods] = resource.MustParse("1")
  770. usedResources[v1.ResourceRequestsCPU] = requests[v1.ResourceCPU]
  771. usedResources[v1.ResourceRequestsMemory] = requests[v1.ResourceMemory]
  772. usedResources[v1.ResourceLimitsCPU] = limits[v1.ResourceCPU]
  773. usedResources[v1.ResourceLimitsMemory] = limits[v1.ResourceMemory]
  774. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  775. framework.ExpectNoError(err)
  776. ginkgo.By("Ensuring resource quota with terminating scope ignored the pod usage")
  777. usedResources[v1.ResourcePods] = resource.MustParse("0")
  778. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  779. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  780. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  781. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  782. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  783. framework.ExpectNoError(err)
  784. ginkgo.By("Deleting the pod")
  785. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(podName, metav1.NewDeleteOptions(0))
  786. framework.ExpectNoError(err)
  787. ginkgo.By("Ensuring resource quota status released the pod usage")
  788. usedResources[v1.ResourcePods] = resource.MustParse("0")
  789. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  790. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  791. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  792. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  793. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  794. framework.ExpectNoError(err)
  795. ginkgo.By("Creating a terminating pod")
  796. podName = "terminating-pod"
  797. pod = newTestPodForQuota(f, podName, requests, limits)
  798. activeDeadlineSeconds := int64(3600)
  799. pod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
  800. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  801. framework.ExpectNoError(err)
  802. ginkgo.By("Ensuring resource quota with terminating scope captures the pod usage")
  803. usedResources[v1.ResourcePods] = resource.MustParse("1")
  804. usedResources[v1.ResourceRequestsCPU] = requests[v1.ResourceCPU]
  805. usedResources[v1.ResourceRequestsMemory] = requests[v1.ResourceMemory]
  806. usedResources[v1.ResourceLimitsCPU] = limits[v1.ResourceCPU]
  807. usedResources[v1.ResourceLimitsMemory] = limits[v1.ResourceMemory]
  808. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  809. framework.ExpectNoError(err)
  810. ginkgo.By("Ensuring resource quota with not terminating scope ignored the pod usage")
  811. usedResources[v1.ResourcePods] = resource.MustParse("0")
  812. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  813. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  814. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  815. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  816. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaNotTerminating.Name, usedResources)
  817. framework.ExpectNoError(err)
  818. ginkgo.By("Deleting the pod")
  819. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(podName, metav1.NewDeleteOptions(0))
  820. framework.ExpectNoError(err)
  821. ginkgo.By("Ensuring resource quota status released the pod usage")
  822. usedResources[v1.ResourcePods] = resource.MustParse("0")
  823. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  824. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0")
  825. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  826. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0")
  827. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaTerminating.Name, usedResources)
  828. framework.ExpectNoError(err)
  829. })
  830. })
  831. var _ = SIGDescribe("ResourceQuota [Feature:PodPriority]", func() {
  832. f := framework.NewDefaultFramework("resourcequota-priorityclass")
  833. ginkgo.It("should verify ResourceQuota's priority class scope (quota set to pod count: 1) against a pod with same priority class.", func() {
  834. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass1"}, Value: int32(1000)})
  835. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  836. hard := v1.ResourceList{}
  837. hard[v1.ResourcePods] = resource.MustParse("1")
  838. ginkgo.By("Creating a ResourceQuota with priority class scope")
  839. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpIn, []string{"pclass1"}))
  840. framework.ExpectNoError(err)
  841. ginkgo.By("Ensuring ResourceQuota status is calculated")
  842. usedResources := v1.ResourceList{}
  843. usedResources[v1.ResourcePods] = resource.MustParse("0")
  844. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  845. framework.ExpectNoError(err)
  846. ginkgo.By("Creating a pod with priority class")
  847. podName := "testpod-pclass1"
  848. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass1")
  849. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  850. framework.ExpectNoError(err)
  851. ginkgo.By("Ensuring resource quota with priority class scope captures the pod usage")
  852. usedResources[v1.ResourcePods] = resource.MustParse("1")
  853. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  854. framework.ExpectNoError(err)
  855. ginkgo.By("Deleting the pod")
  856. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  857. framework.ExpectNoError(err)
  858. ginkgo.By("Ensuring resource quota status released the pod usage")
  859. usedResources[v1.ResourcePods] = resource.MustParse("0")
  860. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  861. framework.ExpectNoError(err)
  862. })
  863. ginkgo.It("should verify ResourceQuota's priority class scope (quota set to pod count: 1) against 2 pods with same priority class.", func() {
  864. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass2"}, Value: int32(1000)})
  865. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  866. hard := v1.ResourceList{}
  867. hard[v1.ResourcePods] = resource.MustParse("1")
  868. ginkgo.By("Creating a ResourceQuota with priority class scope")
  869. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpIn, []string{"pclass2"}))
  870. framework.ExpectNoError(err)
  871. ginkgo.By("Ensuring ResourceQuota status is calculated")
  872. usedResources := v1.ResourceList{}
  873. usedResources[v1.ResourcePods] = resource.MustParse("0")
  874. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  875. framework.ExpectNoError(err)
  876. ginkgo.By("Creating first pod with priority class should pass")
  877. podName := "testpod-pclass2-1"
  878. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass2")
  879. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  880. framework.ExpectNoError(err)
  881. ginkgo.By("Ensuring resource quota with priority class scope captures the pod usage")
  882. usedResources[v1.ResourcePods] = resource.MustParse("1")
  883. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  884. framework.ExpectNoError(err)
  885. ginkgo.By("Creating 2nd pod with priority class should fail")
  886. podName2 := "testpod-pclass2-2"
  887. pod2 := newTestPodForQuotaWithPriority(f, podName2, v1.ResourceList{}, v1.ResourceList{}, "pclass2")
  888. pod2, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod2)
  889. framework.ExpectError(err)
  890. ginkgo.By("Deleting first pod")
  891. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  892. framework.ExpectNoError(err)
  893. ginkgo.By("Ensuring resource quota status released the pod usage")
  894. usedResources[v1.ResourcePods] = resource.MustParse("0")
  895. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  896. framework.ExpectNoError(err)
  897. })
  898. ginkgo.It("should verify ResourceQuota's priority class scope (quota set to pod count: 1) against 2 pods with different priority class.", func() {
  899. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass3"}, Value: int32(1000)})
  900. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  901. hard := v1.ResourceList{}
  902. hard[v1.ResourcePods] = resource.MustParse("1")
  903. ginkgo.By("Creating a ResourceQuota with priority class scope")
  904. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpIn, []string{"pclass4"}))
  905. framework.ExpectNoError(err)
  906. ginkgo.By("Ensuring ResourceQuota status is calculated")
  907. usedResources := v1.ResourceList{}
  908. usedResources[v1.ResourcePods] = resource.MustParse("0")
  909. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  910. framework.ExpectNoError(err)
  911. ginkgo.By("Creating a pod with priority class with pclass3")
  912. podName := "testpod-pclass3-1"
  913. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass3")
  914. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  915. framework.ExpectNoError(err)
  916. ginkgo.By("Ensuring resource quota with priority class scope remains same")
  917. usedResources[v1.ResourcePods] = resource.MustParse("0")
  918. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  919. framework.ExpectNoError(err)
  920. ginkgo.By("Creating a 2nd pod with priority class pclass3")
  921. podName2 := "testpod-pclass2-2"
  922. pod2 := newTestPodForQuotaWithPriority(f, podName2, v1.ResourceList{}, v1.ResourceList{}, "pclass3")
  923. pod2, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod2)
  924. framework.ExpectNoError(err)
  925. ginkgo.By("Ensuring resource quota with priority class scope remains same")
  926. usedResources[v1.ResourcePods] = resource.MustParse("0")
  927. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  928. framework.ExpectNoError(err)
  929. ginkgo.By("Deleting both pods")
  930. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  931. framework.ExpectNoError(err)
  932. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod2.Name, metav1.NewDeleteOptions(0))
  933. framework.ExpectNoError(err)
  934. })
  935. ginkgo.It("should verify ResourceQuota's multiple priority class scope (quota set to pod count: 2) against 2 pods with same priority classes.", func() {
  936. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass5"}, Value: int32(1000)})
  937. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  938. _, err = f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass6"}, Value: int32(1000)})
  939. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  940. hard := v1.ResourceList{}
  941. hard[v1.ResourcePods] = resource.MustParse("2")
  942. ginkgo.By("Creating a ResourceQuota with priority class scope")
  943. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpIn, []string{"pclass5", "pclass6"}))
  944. framework.ExpectNoError(err)
  945. ginkgo.By("Ensuring ResourceQuota status is calculated")
  946. usedResources := v1.ResourceList{}
  947. usedResources[v1.ResourcePods] = resource.MustParse("0")
  948. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  949. framework.ExpectNoError(err)
  950. ginkgo.By("Creating a pod with priority class pclass5")
  951. podName := "testpod-pclass5"
  952. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass5")
  953. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  954. framework.ExpectNoError(err)
  955. ginkgo.By("Ensuring resource quota with priority class is updated with the pod usage")
  956. usedResources[v1.ResourcePods] = resource.MustParse("1")
  957. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  958. framework.ExpectNoError(err)
  959. ginkgo.By("Creating 2nd pod with priority class pclass6")
  960. podName2 := "testpod-pclass6"
  961. pod2 := newTestPodForQuotaWithPriority(f, podName2, v1.ResourceList{}, v1.ResourceList{}, "pclass6")
  962. pod2, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod2)
  963. framework.ExpectNoError(err)
  964. ginkgo.By("Ensuring resource quota with priority class scope is updated with the pod usage")
  965. usedResources[v1.ResourcePods] = resource.MustParse("2")
  966. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  967. framework.ExpectNoError(err)
  968. ginkgo.By("Deleting both pods")
  969. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  970. framework.ExpectNoError(err)
  971. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod2.Name, metav1.NewDeleteOptions(0))
  972. framework.ExpectNoError(err)
  973. ginkgo.By("Ensuring resource quota status released the pod usage")
  974. usedResources[v1.ResourcePods] = resource.MustParse("0")
  975. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  976. framework.ExpectNoError(err)
  977. })
  978. ginkgo.It("should verify ResourceQuota's priority class scope (quota set to pod count: 1) against a pod with different priority class (ScopeSelectorOpNotIn).", func() {
  979. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass7"}, Value: int32(1000)})
  980. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  981. hard := v1.ResourceList{}
  982. hard[v1.ResourcePods] = resource.MustParse("1")
  983. ginkgo.By("Creating a ResourceQuota with priority class scope")
  984. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpNotIn, []string{"pclass7"}))
  985. framework.ExpectNoError(err)
  986. ginkgo.By("Ensuring ResourceQuota status is calculated")
  987. usedResources := v1.ResourceList{}
  988. usedResources[v1.ResourcePods] = resource.MustParse("0")
  989. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  990. framework.ExpectNoError(err)
  991. ginkgo.By("Creating a pod with priority class pclass7")
  992. podName := "testpod-pclass7"
  993. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass7")
  994. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  995. framework.ExpectNoError(err)
  996. ginkgo.By("Ensuring resource quota with priority class is not used")
  997. usedResources[v1.ResourcePods] = resource.MustParse("0")
  998. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  999. framework.ExpectNoError(err)
  1000. ginkgo.By("Deleting the pod")
  1001. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  1002. framework.ExpectNoError(err)
  1003. })
  1004. ginkgo.It("should verify ResourceQuota's priority class scope (quota set to pod count: 1) against a pod with different priority class (ScopeSelectorOpExists).", func() {
  1005. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass8"}, Value: int32(1000)})
  1006. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  1007. hard := v1.ResourceList{}
  1008. hard[v1.ResourcePods] = resource.MustParse("1")
  1009. ginkgo.By("Creating a ResourceQuota with priority class scope")
  1010. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpExists, []string{}))
  1011. framework.ExpectNoError(err)
  1012. ginkgo.By("Ensuring ResourceQuota status is calculated")
  1013. usedResources := v1.ResourceList{}
  1014. usedResources[v1.ResourcePods] = resource.MustParse("0")
  1015. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1016. framework.ExpectNoError(err)
  1017. ginkgo.By("Creating a pod with priority class pclass8")
  1018. podName := "testpod-pclass8"
  1019. pod := newTestPodForQuotaWithPriority(f, podName, v1.ResourceList{}, v1.ResourceList{}, "pclass8")
  1020. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  1021. framework.ExpectNoError(err)
  1022. ginkgo.By("Ensuring resource quota with priority class is updated with the pod usage")
  1023. usedResources[v1.ResourcePods] = resource.MustParse("1")
  1024. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1025. framework.ExpectNoError(err)
  1026. ginkgo.By("Deleting the pod")
  1027. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  1028. framework.ExpectNoError(err)
  1029. ginkgo.By("Ensuring resource quota status released the pod usage")
  1030. usedResources[v1.ResourcePods] = resource.MustParse("0")
  1031. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1032. framework.ExpectNoError(err)
  1033. })
  1034. ginkgo.It("should verify ResourceQuota's priority class scope (cpu, memory quota set) against a pod with same priority class.", func() {
  1035. _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(&schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: "pclass9"}, Value: int32(1000)})
  1036. gomega.Expect(err == nil || errors.IsAlreadyExists(err)).To(gomega.Equal(true))
  1037. hard := v1.ResourceList{}
  1038. hard[v1.ResourcePods] = resource.MustParse("1")
  1039. hard[v1.ResourceRequestsCPU] = resource.MustParse("1")
  1040. hard[v1.ResourceRequestsMemory] = resource.MustParse("1Gi")
  1041. hard[v1.ResourceLimitsCPU] = resource.MustParse("3")
  1042. hard[v1.ResourceLimitsMemory] = resource.MustParse("3Gi")
  1043. ginkgo.By("Creating a ResourceQuota with priority class scope")
  1044. resourceQuotaPriorityClass, err := createResourceQuota(f.ClientSet, f.Namespace.Name, newTestResourceQuotaWithScopeForPriorityClass("quota-priorityclass", hard, v1.ScopeSelectorOpIn, []string{"pclass9"}))
  1045. framework.ExpectNoError(err)
  1046. ginkgo.By("Ensuring ResourceQuota status is calculated")
  1047. usedResources := v1.ResourceList{}
  1048. usedResources[v1.ResourcePods] = resource.MustParse("0")
  1049. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  1050. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0Gi")
  1051. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  1052. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0Gi")
  1053. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1054. framework.ExpectNoError(err)
  1055. ginkgo.By("Creating a pod with priority class")
  1056. podName := "testpod-pclass9"
  1057. request := v1.ResourceList{}
  1058. request[v1.ResourceCPU] = resource.MustParse("1")
  1059. request[v1.ResourceMemory] = resource.MustParse("1Gi")
  1060. limit := v1.ResourceList{}
  1061. limit[v1.ResourceCPU] = resource.MustParse("2")
  1062. limit[v1.ResourceMemory] = resource.MustParse("2Gi")
  1063. pod := newTestPodForQuotaWithPriority(f, podName, request, limit, "pclass9")
  1064. pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod)
  1065. framework.ExpectNoError(err)
  1066. ginkgo.By("Ensuring resource quota with priority class scope captures the pod usage")
  1067. usedResources[v1.ResourcePods] = resource.MustParse("1")
  1068. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("1")
  1069. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("1Gi")
  1070. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("2")
  1071. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("2Gi")
  1072. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1073. framework.ExpectNoError(err)
  1074. ginkgo.By("Deleting the pod")
  1075. err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, metav1.NewDeleteOptions(0))
  1076. framework.ExpectNoError(err)
  1077. ginkgo.By("Ensuring resource quota status released the pod usage")
  1078. usedResources[v1.ResourcePods] = resource.MustParse("0")
  1079. usedResources[v1.ResourceRequestsCPU] = resource.MustParse("0")
  1080. usedResources[v1.ResourceRequestsMemory] = resource.MustParse("0Gi")
  1081. usedResources[v1.ResourceLimitsCPU] = resource.MustParse("0")
  1082. usedResources[v1.ResourceLimitsMemory] = resource.MustParse("0Gi")
  1083. err = waitForResourceQuota(f.ClientSet, f.Namespace.Name, resourceQuotaPriorityClass.Name, usedResources)
  1084. framework.ExpectNoError(err)
  1085. })
  1086. })
  1087. // newTestResourceQuotaWithScopeSelector returns a quota that enforces default constraints for testing with scopeSelectors
  1088. func newTestResourceQuotaWithScopeSelector(name string, scope v1.ResourceQuotaScope) *v1.ResourceQuota {
  1089. hard := v1.ResourceList{}
  1090. hard[v1.ResourcePods] = resource.MustParse("5")
  1091. switch scope {
  1092. case v1.ResourceQuotaScopeTerminating, v1.ResourceQuotaScopeNotTerminating:
  1093. hard[v1.ResourceRequestsCPU] = resource.MustParse("1")
  1094. hard[v1.ResourceRequestsMemory] = resource.MustParse("500Mi")
  1095. hard[v1.ResourceLimitsCPU] = resource.MustParse("2")
  1096. hard[v1.ResourceLimitsMemory] = resource.MustParse("1Gi")
  1097. }
  1098. return &v1.ResourceQuota{
  1099. ObjectMeta: metav1.ObjectMeta{Name: name},
  1100. Spec: v1.ResourceQuotaSpec{Hard: hard,
  1101. ScopeSelector: &v1.ScopeSelector{
  1102. MatchExpressions: []v1.ScopedResourceSelectorRequirement{
  1103. {
  1104. ScopeName: scope,
  1105. Operator: v1.ScopeSelectorOpExists},
  1106. },
  1107. },
  1108. },
  1109. }
  1110. }
  1111. // newTestResourceQuotaWithScope returns a quota that enforces default constraints for testing with scopes
  1112. func newTestResourceQuotaWithScope(name string, scope v1.ResourceQuotaScope) *v1.ResourceQuota {
  1113. hard := v1.ResourceList{}
  1114. hard[v1.ResourcePods] = resource.MustParse("5")
  1115. switch scope {
  1116. case v1.ResourceQuotaScopeTerminating, v1.ResourceQuotaScopeNotTerminating:
  1117. hard[v1.ResourceRequestsCPU] = resource.MustParse("1")
  1118. hard[v1.ResourceRequestsMemory] = resource.MustParse("500Mi")
  1119. hard[v1.ResourceLimitsCPU] = resource.MustParse("2")
  1120. hard[v1.ResourceLimitsMemory] = resource.MustParse("1Gi")
  1121. }
  1122. return &v1.ResourceQuota{
  1123. ObjectMeta: metav1.ObjectMeta{Name: name},
  1124. Spec: v1.ResourceQuotaSpec{Hard: hard, Scopes: []v1.ResourceQuotaScope{scope}},
  1125. }
  1126. }
  1127. // newTestResourceQuotaWithScopeForPriorityClass returns a quota
  1128. // that enforces default constraints for testing with ResourceQuotaScopePriorityClass scope
  1129. func newTestResourceQuotaWithScopeForPriorityClass(name string, hard v1.ResourceList, op v1.ScopeSelectorOperator, values []string) *v1.ResourceQuota {
  1130. return &v1.ResourceQuota{
  1131. ObjectMeta: metav1.ObjectMeta{Name: name},
  1132. Spec: v1.ResourceQuotaSpec{Hard: hard,
  1133. ScopeSelector: &v1.ScopeSelector{
  1134. MatchExpressions: []v1.ScopedResourceSelectorRequirement{
  1135. {
  1136. ScopeName: v1.ResourceQuotaScopePriorityClass,
  1137. Operator: op,
  1138. Values: values,
  1139. },
  1140. },
  1141. },
  1142. },
  1143. }
  1144. }
  1145. // newTestResourceQuota returns a quota that enforces default constraints for testing
  1146. func newTestResourceQuota(name string) *v1.ResourceQuota {
  1147. hard := v1.ResourceList{}
  1148. hard[v1.ResourcePods] = resource.MustParse("5")
  1149. hard[v1.ResourceServices] = resource.MustParse("10")
  1150. hard[v1.ResourceServicesNodePorts] = resource.MustParse("1")
  1151. hard[v1.ResourceServicesLoadBalancers] = resource.MustParse("1")
  1152. hard[v1.ResourceReplicationControllers] = resource.MustParse("10")
  1153. hard[v1.ResourceQuotas] = resource.MustParse("1")
  1154. hard[v1.ResourceCPU] = resource.MustParse("1")
  1155. hard[v1.ResourceMemory] = resource.MustParse("500Mi")
  1156. hard[v1.ResourceConfigMaps] = resource.MustParse("2")
  1157. hard[v1.ResourceSecrets] = resource.MustParse("10")
  1158. hard[v1.ResourcePersistentVolumeClaims] = resource.MustParse("10")
  1159. hard[v1.ResourceRequestsStorage] = resource.MustParse("10Gi")
  1160. hard[v1.ResourceEphemeralStorage] = resource.MustParse("50Gi")
  1161. hard[core.V1ResourceByStorageClass(classGold, v1.ResourcePersistentVolumeClaims)] = resource.MustParse("10")
  1162. hard[core.V1ResourceByStorageClass(classGold, v1.ResourceRequestsStorage)] = resource.MustParse("10Gi")
  1163. // test quota on discovered resource type
  1164. hard[v1.ResourceName("count/replicasets.apps")] = resource.MustParse("5")
  1165. // test quota on extended resource
  1166. hard[v1.ResourceName(v1.DefaultResourceRequestsPrefix+extendedResourceName)] = resource.MustParse("3")
  1167. return &v1.ResourceQuota{
  1168. ObjectMeta: metav1.ObjectMeta{Name: name},
  1169. Spec: v1.ResourceQuotaSpec{Hard: hard},
  1170. }
  1171. }
  1172. // newTestPodForQuota returns a pod that has the specified requests and limits
  1173. func newTestPodForQuota(f *framework.Framework, name string, requests v1.ResourceList, limits v1.ResourceList) *v1.Pod {
  1174. return &v1.Pod{
  1175. ObjectMeta: metav1.ObjectMeta{
  1176. Name: name,
  1177. },
  1178. Spec: v1.PodSpec{
  1179. Containers: []v1.Container{
  1180. {
  1181. Name: "pause",
  1182. Image: imageutils.GetPauseImageName(),
  1183. Resources: v1.ResourceRequirements{
  1184. Requests: requests,
  1185. Limits: limits,
  1186. },
  1187. },
  1188. },
  1189. },
  1190. }
  1191. }
  1192. // newTestPodForQuotaWithPriority returns a pod that has the specified requests, limits and priority class
  1193. func newTestPodForQuotaWithPriority(f *framework.Framework, name string, requests v1.ResourceList, limits v1.ResourceList, pclass string) *v1.Pod {
  1194. return &v1.Pod{
  1195. ObjectMeta: metav1.ObjectMeta{
  1196. Name: name,
  1197. },
  1198. Spec: v1.PodSpec{
  1199. Containers: []v1.Container{
  1200. {
  1201. Name: "pause",
  1202. Image: imageutils.GetPauseImageName(),
  1203. Resources: v1.ResourceRequirements{
  1204. Requests: requests,
  1205. Limits: limits,
  1206. },
  1207. },
  1208. },
  1209. PriorityClassName: pclass,
  1210. },
  1211. }
  1212. }
  1213. // newTestPersistentVolumeClaimForQuota returns a simple persistent volume claim
  1214. func newTestPersistentVolumeClaimForQuota(name string) *v1.PersistentVolumeClaim {
  1215. return &v1.PersistentVolumeClaim{
  1216. ObjectMeta: metav1.ObjectMeta{
  1217. Name: name,
  1218. },
  1219. Spec: v1.PersistentVolumeClaimSpec{
  1220. AccessModes: []v1.PersistentVolumeAccessMode{
  1221. v1.ReadWriteOnce,
  1222. v1.ReadOnlyMany,
  1223. v1.ReadWriteMany,
  1224. },
  1225. Resources: v1.ResourceRequirements{
  1226. Requests: v1.ResourceList{
  1227. v1.ResourceName(v1.ResourceStorage): resource.MustParse("1Gi"),
  1228. },
  1229. },
  1230. },
  1231. }
  1232. }
  1233. // newTestReplicationControllerForQuota returns a simple replication controller
  1234. func newTestReplicationControllerForQuota(name, image string, replicas int32) *v1.ReplicationController {
  1235. return &v1.ReplicationController{
  1236. ObjectMeta: metav1.ObjectMeta{
  1237. Name: name,
  1238. },
  1239. Spec: v1.ReplicationControllerSpec{
  1240. Replicas: func(i int32) *int32 { return &i }(replicas),
  1241. Selector: map[string]string{
  1242. "name": name,
  1243. },
  1244. Template: &v1.PodTemplateSpec{
  1245. ObjectMeta: metav1.ObjectMeta{
  1246. Labels: map[string]string{"name": name},
  1247. },
  1248. Spec: v1.PodSpec{
  1249. Containers: []v1.Container{
  1250. {
  1251. Name: name,
  1252. Image: image,
  1253. },
  1254. },
  1255. },
  1256. },
  1257. },
  1258. }
  1259. }
  1260. // newTestReplicaSetForQuota returns a simple replica set
  1261. func newTestReplicaSetForQuota(name, image string, replicas int32) *appsv1.ReplicaSet {
  1262. zero := int64(0)
  1263. return &appsv1.ReplicaSet{
  1264. ObjectMeta: metav1.ObjectMeta{
  1265. Name: name,
  1266. },
  1267. Spec: appsv1.ReplicaSetSpec{
  1268. Replicas: &replicas,
  1269. Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"name": name}},
  1270. Template: v1.PodTemplateSpec{
  1271. ObjectMeta: metav1.ObjectMeta{
  1272. Labels: map[string]string{"name": name},
  1273. },
  1274. Spec: v1.PodSpec{
  1275. TerminationGracePeriodSeconds: &zero,
  1276. Containers: []v1.Container{
  1277. {
  1278. Name: name,
  1279. Image: image,
  1280. },
  1281. },
  1282. },
  1283. },
  1284. },
  1285. }
  1286. }
  1287. // newTestServiceForQuota returns a simple service
  1288. func newTestServiceForQuota(name string, serviceType v1.ServiceType) *v1.Service {
  1289. return &v1.Service{
  1290. ObjectMeta: metav1.ObjectMeta{
  1291. Name: name,
  1292. },
  1293. Spec: v1.ServiceSpec{
  1294. Type: serviceType,
  1295. Ports: []v1.ServicePort{{
  1296. Port: 80,
  1297. TargetPort: intstr.FromInt(80),
  1298. }},
  1299. },
  1300. }
  1301. }
  1302. func newTestConfigMapForQuota(name string) *v1.ConfigMap {
  1303. return &v1.ConfigMap{
  1304. ObjectMeta: metav1.ObjectMeta{
  1305. Name: name,
  1306. },
  1307. Data: map[string]string{
  1308. "a": "b",
  1309. },
  1310. }
  1311. }
  1312. func newTestSecretForQuota(name string) *v1.Secret {
  1313. return &v1.Secret{
  1314. ObjectMeta: metav1.ObjectMeta{
  1315. Name: name,
  1316. },
  1317. Data: map[string][]byte{
  1318. "data-1": []byte("value-1\n"),
  1319. "data-2": []byte("value-2\n"),
  1320. "data-3": []byte("value-3\n"),
  1321. },
  1322. }
  1323. }
  1324. // createResourceQuota in the specified namespace
  1325. func createResourceQuota(c clientset.Interface, namespace string, resourceQuota *v1.ResourceQuota) (*v1.ResourceQuota, error) {
  1326. return c.CoreV1().ResourceQuotas(namespace).Create(resourceQuota)
  1327. }
  1328. // deleteResourceQuota with the specified name
  1329. func deleteResourceQuota(c clientset.Interface, namespace, name string) error {
  1330. return c.CoreV1().ResourceQuotas(namespace).Delete(name, nil)
  1331. }
  1332. // countResourceQuota counts the number of ResourceQuota in the specified namespace
  1333. func countResourceQuota(c clientset.Interface, namespace string) (int, error) {
  1334. found, unchanged := 0, 0
  1335. return found, wait.Poll(1*time.Second, 30*time.Second, func() (bool, error) {
  1336. resourceQuotas, err := c.CoreV1().ResourceQuotas(namespace).List(metav1.ListOptions{})
  1337. framework.ExpectNoError(err)
  1338. if len(resourceQuotas.Items) == found {
  1339. // loop until the number of resource quotas has stabilized for 5 seconds
  1340. unchanged++
  1341. return unchanged > 4, nil
  1342. }
  1343. unchanged = 0
  1344. found = len(resourceQuotas.Items)
  1345. return false, nil
  1346. })
  1347. }
  1348. // wait for resource quota status to show the expected used resources value
  1349. func waitForResourceQuota(c clientset.Interface, ns, quotaName string, used v1.ResourceList) error {
  1350. return wait.Poll(framework.Poll, resourceQuotaTimeout, func() (bool, error) {
  1351. resourceQuota, err := c.CoreV1().ResourceQuotas(ns).Get(quotaName, metav1.GetOptions{})
  1352. if err != nil {
  1353. return false, err
  1354. }
  1355. // used may not yet be calculated
  1356. if resourceQuota.Status.Used == nil {
  1357. return false, nil
  1358. }
  1359. // verify that the quota shows the expected used resource values
  1360. for k, v := range used {
  1361. if actualValue, found := resourceQuota.Status.Used[k]; !found || (actualValue.Cmp(v) != 0) {
  1362. e2elog.Logf("resource %s, expected %s, actual %s", k, v.String(), actualValue.String())
  1363. return false, nil
  1364. }
  1365. }
  1366. return true, nil
  1367. })
  1368. }
  1369. // updateResourceQuotaUntilUsageAppears updates the resource quota object until the usage is populated
  1370. // for the specific resource name.
  1371. func updateResourceQuotaUntilUsageAppears(c clientset.Interface, ns, quotaName string, resourceName v1.ResourceName) error {
  1372. return wait.Poll(framework.Poll, 1*time.Minute, func() (bool, error) {
  1373. resourceQuota, err := c.CoreV1().ResourceQuotas(ns).Get(quotaName, metav1.GetOptions{})
  1374. if err != nil {
  1375. return false, err
  1376. }
  1377. // verify that the quota shows the expected used resource values
  1378. _, ok := resourceQuota.Status.Used[resourceName]
  1379. if ok {
  1380. return true, nil
  1381. }
  1382. current := resourceQuota.Spec.Hard[resourceName]
  1383. current.Add(resource.MustParse("1"))
  1384. resourceQuota.Spec.Hard[resourceName] = current
  1385. _, err = c.CoreV1().ResourceQuotas(ns).Update(resourceQuota)
  1386. // ignoring conflicts since someone else may already updated it.
  1387. if errors.IsConflict(err) {
  1388. return false, nil
  1389. }
  1390. return false, err
  1391. })
  1392. }