Skip to content

Commit 41a7cea

Browse files
committed
UPSTREAM: 96984: APF e2e: wait for steady state before proceeding
1 parent 3308cc0 commit 41a7cea

File tree

2 files changed

+66
-15
lines changed

2 files changed

+66
-15
lines changed

test/e2e/apimachinery/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ go_library(
7676
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
7777
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
7878
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
79+
"//staging/src/k8s.io/apiserver/pkg/util/apihelpers:go_default_library",
7980
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
8081
"//staging/src/k8s.io/cli-runtime/pkg/printers:go_default_library",
8182
"//staging/src/k8s.io/client-go/discovery:go_default_library",

test/e2e/apimachinery/flowcontrol.go

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package apimachinery
1919
import (
2020
"bytes"
2121
"context"
22+
"errors"
2223
"fmt"
2324
"io"
2425
"net/http"
@@ -32,14 +33,21 @@ import (
3233

3334
flowcontrol "k8s.io/api/flowcontrol/v1beta1"
3435
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36+
"k8s.io/apimachinery/pkg/util/wait"
37+
"k8s.io/apiserver/pkg/util/apihelpers"
38+
clientset "k8s.io/client-go/kubernetes"
3539
"k8s.io/client-go/rest"
3640
clientsideflowcontrol "k8s.io/client-go/util/flowcontrol"
3741
"k8s.io/kubernetes/test/e2e/framework"
3842
)
3943

4044
const (
41-
requestConcurrencyLimitMetricName = "apiserver_flowcontrol_request_concurrency_limit"
42-
requestConcurrencyLimitMetricLabelName = "priority_level"
45+
requestConcurrencyLimitMetricName = "apiserver_flowcontrol_request_concurrency_limit"
46+
priorityLevelLabelName = "priority_level"
47+
)
48+
49+
var (
50+
errPriorityLevelNotFound = errors.New("cannot find a metric sample with a matching priority level name label")
4351
)
4452

4553
var _ = SIGDescribe("API priority and fairness", func() {
@@ -59,6 +67,9 @@ var _ = SIGDescribe("API priority and fairness", func() {
5967
createdFlowSchema, cleanup := createFlowSchema(f, testingFlowSchemaName, 1000, testingPriorityLevelName, []string{matchingUsername})
6068
defer cleanup()
6169

70+
ginkgo.By("waiting for testing FlowSchema and PriorityLevelConfiguration to reach steady state")
71+
waitForSteadyState(f, testingFlowSchemaName, testingPriorityLevelName)
72+
6273
var response *http.Response
6374
ginkgo.By("response headers should contain the UID of the appropriate FlowSchema and PriorityLevelConfiguration for a matching user")
6475
response = makeRequest(f, matchingUsername)
@@ -126,11 +137,15 @@ var _ = SIGDescribe("API priority and fairness", func() {
126137
framework.Logf("creating FlowSchema %q", clients[i].flowSchemaName)
127138
_, cleanup = createFlowSchema(f, clients[i].flowSchemaName, clients[i].matchingPrecedence, clients[i].priorityLevelName, []string{clients[i].username})
128139
defer cleanup()
140+
141+
ginkgo.By("waiting for testing FlowSchema and PriorityLevelConfiguration to reach steady state")
142+
waitForSteadyState(f, clients[i].flowSchemaName, clients[i].priorityLevelName)
129143
}
130144

131145
ginkgo.By("getting request concurrency from metrics")
132146
for i := range clients {
133-
realConcurrency := getPriorityLevelConcurrency(f, clients[i].priorityLevelName)
147+
realConcurrency, err := getPriorityLevelConcurrency(f.ClientSet, clients[i].priorityLevelName)
148+
framework.ExpectNoError(err)
134149
clients[i].concurrency = int32(float64(realConcurrency) * clients[i].concurrencyMultiplier)
135150
if clients[i].concurrency < 1 {
136151
clients[i].concurrency = 1
@@ -185,6 +200,9 @@ var _ = SIGDescribe("API priority and fairness", func() {
185200
_, cleanup = createFlowSchema(f, flowSchemaName, 1000, priorityLevelName, []string{highQPSClientName, lowQPSClientName})
186201
defer cleanup()
187202

203+
ginkgo.By("waiting for testing flow schema and priority level to reach steady state")
204+
waitForSteadyState(f, flowSchemaName, priorityLevelName)
205+
188206
type client struct {
189207
username string
190208
qps float64
@@ -199,7 +217,8 @@ var _ = SIGDescribe("API priority and fairness", func() {
199217
}
200218

201219
framework.Logf("getting real concurrency")
202-
realConcurrency := getPriorityLevelConcurrency(f, priorityLevelName)
220+
realConcurrency, err := getPriorityLevelConcurrency(f.ClientSet, priorityLevelName)
221+
framework.ExpectNoError(err)
203222
for i := range clients {
204223
clients[i].concurrency = int32(float64(realConcurrency) * clients[i].concurrencyMultiplier)
205224
if clients[i].concurrency < 1 {
@@ -259,33 +278,35 @@ func createPriorityLevel(f *framework.Framework, priorityLevelName string, assur
259278
}
260279
}
261280

262-
//lint:ignore U1000 function is actually referenced
263-
func getPriorityLevelConcurrency(f *framework.Framework, priorityLevelName string) int32 {
264-
resp, err := f.ClientSet.CoreV1().RESTClient().Get().RequestURI("/metrics").DoRaw(context.TODO())
265-
framework.ExpectNoError(err)
281+
func getPriorityLevelConcurrency(c clientset.Interface, priorityLevelName string) (int32, error) {
282+
resp, err := c.CoreV1().RESTClient().Get().RequestURI("/metrics").DoRaw(context.TODO())
283+
if err != nil {
284+
return 0, err
285+
}
266286
sampleDecoder := expfmt.SampleDecoder{
267287
Dec: expfmt.NewDecoder(bytes.NewBuffer(resp), expfmt.FmtText),
268288
Opts: &expfmt.DecodeOptions{},
269289
}
270290
for {
271291
var v model.Vector
272292
err := sampleDecoder.Decode(&v)
273-
if err == io.EOF {
274-
break
293+
if err != nil {
294+
if err == io.EOF {
295+
break
296+
}
297+
return 0, err
275298
}
276-
framework.ExpectNoError(err)
277299
for _, metric := range v {
278300
if string(metric.Metric[model.MetricNameLabel]) != requestConcurrencyLimitMetricName {
279301
continue
280302
}
281-
if string(metric.Metric[requestConcurrencyLimitMetricLabelName]) != priorityLevelName {
303+
if string(metric.Metric[priorityLevelLabelName]) != priorityLevelName {
282304
continue
283305
}
284-
return int32(metric.Value)
306+
return int32(metric.Value), nil
285307
}
286308
}
287-
framework.ExpectNoError(fmt.Errorf("cannot find metric %q with matching priority level name label %q", requestConcurrencyLimitMetricName, priorityLevelName))
288-
return 0
309+
return 0, errPriorityLevelNotFound
289310
}
290311

291312
// createFlowSchema creates a flow schema referring to a particular priority
@@ -335,6 +356,35 @@ func createFlowSchema(f *framework.Framework, flowSchemaName string, matchingPre
335356
}
336357
}
337358

359+
// waitForSteadyState repeatedly polls the API server to check if the newly
360+
// created flow schema and priority level have been seen by the APF controller
361+
// by checking: (1) the dangling priority level reference condition in the flow
362+
// schema status, and (2) metrics. The function times out after 30 seconds.
363+
func waitForSteadyState(f *framework.Framework, flowSchemaName string, priorityLevelName string) {
364+
framework.ExpectNoError(wait.Poll(time.Second, 30*time.Second, func() (bool, error) {
365+
fs, err := f.ClientSet.FlowcontrolV1beta1().FlowSchemas().Get(context.TODO(), flowSchemaName, metav1.GetOptions{})
366+
if err != nil {
367+
return false, err
368+
}
369+
condition := apihelpers.GetFlowSchemaConditionByType(fs, flowcontrol.FlowSchemaConditionDangling)
370+
if condition == nil || condition.Status != flowcontrol.ConditionFalse {
371+
// The absence of the dangling status object implies that the APF
372+
// controller isn't done with syncing the flow schema object. And, of
373+
// course, the condition being anything but false means that steady state
374+
// hasn't been achieved.
375+
return false, nil
376+
}
377+
_, err = getPriorityLevelConcurrency(f.ClientSet, priorityLevelName)
378+
if err != nil {
379+
if err == errPriorityLevelNotFound {
380+
return false, nil
381+
}
382+
return false, err
383+
}
384+
return true, nil
385+
}))
386+
}
387+
338388
// makeRequests creates a request to the API server and returns the response.
339389
func makeRequest(f *framework.Framework, username string) *http.Response {
340390
config := f.ClientConfig()

0 commit comments

Comments
 (0)