@@ -18,6 +18,7 @@ package autoscaling
1818
1919import (
2020 "fmt"
21+ "time"
2122
2223 autoscaling "k8s.io/api/autoscaling/v1"
2324 apiv1 "k8s.io/api/core/v1"
@@ -91,37 +92,80 @@ var _ = FullVpaE2eDescribe("Pods under VPA", func() {
9192 ginkgo .It ("have cpu requests growing with usage" , func () {
9293 // initial CPU usage is low so a minimal recommendation is expected
9394 err := waitForResourceRequestInRangeInPods (
94- f , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceCPU ,
95+ f , pollTimeout , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceCPU ,
9596 ParseQuantityOrDie (minimalCPULowerBound ), ParseQuantityOrDie (minimalCPUUpperBound ))
9697 gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
9798
9899 // consume more CPU to get a higher recommendation
99100 rc .ConsumeCPU (600 * replicas )
100101 err = waitForResourceRequestInRangeInPods (
101- f , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceCPU ,
102+ f , pollTimeout , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceCPU ,
102103 ParseQuantityOrDie ("500m" ), ParseQuantityOrDie ("900m" ))
103104 gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
104105 })
105106
106107 ginkgo .It ("have memory requests growing with usage" , func () {
107108 // initial memory usage is low so a minimal recommendation is expected
108109 err := waitForResourceRequestInRangeInPods (
109- f , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceMemory ,
110+ f , pollTimeout , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceMemory ,
110111 ParseQuantityOrDie (minimalMemoryLowerBound ), ParseQuantityOrDie (minimalMemoryUpperBound ))
111112 gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
112113
113114 // consume more memory to get a higher recommendation
114115 // NOTE: large range given due to unpredictability of actual memory usage
115116 rc .ConsumeMem (1024 * replicas )
116117 err = waitForResourceRequestInRangeInPods (
117- f , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceMemory ,
118+ f , pollTimeout , metav1.ListOptions {LabelSelector : "name=hamster" }, apiv1 .ResourceMemory ,
118119 ParseQuantityOrDie ("900Mi" ), ParseQuantityOrDie ("4000Mi" ))
119120 gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
120121 })
121122})
122123
123- func waitForPodsMatch (f * framework.Framework , listOptions metav1.ListOptions , matcher func (pod apiv1.Pod ) bool ) error {
124- return wait .PollImmediate (pollInterval , pollTimeout , func () (bool , error ) {
124+ var _ = FullVpaE2eDescribe ("OOMing pods under VPA" , func () {
125+ var (
126+ vpaClientSet * vpa_clientset.Clientset
127+ vpaCRD * vpa_types.VerticalPodAutoscaler
128+ )
129+ const replicas = 3
130+
131+ f := framework .NewDefaultFramework ("vertical-pod-autoscaling" )
132+
133+ ginkgo .BeforeEach (func () {
134+ ns := f .Namespace .Name
135+ ginkgo .By ("Setting up a hamster deployment" )
136+
137+ runOomingReplicationController (
138+ f .ClientSet ,
139+ ns ,
140+ "hamster" ,
141+ replicas )
142+ ginkgo .By ("Setting up a VPA CRD" )
143+ config , err := framework .LoadConfig ()
144+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
145+
146+ vpaCRD = NewVPA (f , "hamster-vpa" , & autoscaling.CrossVersionObjectReference {
147+ APIVersion : "apps/v1" ,
148+ Kind : "Deployment" ,
149+ Name : "hamster" ,
150+ })
151+
152+ vpaClientSet = vpa_clientset .NewForConfigOrDie (config )
153+ vpaClient := vpaClientSet .AutoscalingV1beta2 ()
154+ _ , err = vpaClient .VerticalPodAutoscalers (ns ).Create (vpaCRD )
155+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
156+ })
157+
158+ ginkgo .It ("have memory requests growing with OOMs" , func () {
159+ listOptions := metav1.ListOptions {LabelSelector : "name=hamster" , FieldSelector : getPodSelectorExcludingDonePodsOrDie ()}
160+ err := waitForResourceRequestInRangeInPods (
161+ f , 7 * time .Minute , listOptions , apiv1 .ResourceMemory ,
162+ ParseQuantityOrDie ("1400Mi" ), ParseQuantityOrDie ("10000Mi" ))
163+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
164+ })
165+ })
166+
167+ func waitForPodsMatch (f * framework.Framework , timeout time.Duration , listOptions metav1.ListOptions , matcher func (pod apiv1.Pod ) bool ) error {
168+ return wait .PollImmediate (pollInterval , timeout , func () (bool , error ) {
125169
126170 ns := f .Namespace .Name
127171 c := f .ClientSet
@@ -135,18 +179,23 @@ func waitForPodsMatch(f *framework.Framework, listOptions metav1.ListOptions, ma
135179 return false , nil
136180 }
137181
182+ // Run matcher on all pods, even if we find pod that doesn't match early.
183+ // This allows the matcher to write logs for all pods. This in turns makes
184+ // it easier to spot some problems (for example unexpected pods in the list
185+ // results).
186+ result := true
138187 for _ , pod := range podList .Items {
139188 if ! matcher (pod ) {
140- return false , nil
189+ result = false
141190 }
142191 }
143- return true , nil
192+ return result , nil
144193
145194 })
146195}
147196
148- func waitForResourceRequestInRangeInPods (f * framework.Framework , listOptions metav1.ListOptions , resourceName apiv1.ResourceName , lowerBound , upperBound resource.Quantity ) error {
149- err := waitForPodsMatch (f , listOptions ,
197+ func waitForResourceRequestInRangeInPods (f * framework.Framework , timeout time. Duration , listOptions metav1.ListOptions , resourceName apiv1.ResourceName , lowerBound , upperBound resource.Quantity ) error {
198+ err := waitForPodsMatch (f , timeout , listOptions ,
150199 func (pod apiv1.Pod ) bool {
151200 resourceRequest , found := pod .Spec .Containers [0 ].Resources .Requests [resourceName ]
152201 framework .Logf ("Comparing %v request %v against range of (%v, %v)" , resourceName , resourceRequest , lowerBound , upperBound )
0 commit comments