Skip to content

Commit 438bc5d

Browse files
authored
Merge pull request kubernetes#128818 from yongruilin/flagz-kube-scheduler
feat: Add flagz endpoint for kube-scheduler
2 parents 9dd53b5 + db6bf02 commit 438bc5d

File tree

5 files changed

+95
-41
lines changed

5 files changed

+95
-41
lines changed

cmd/kube-scheduler/app/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@ import (
2626
restclient "k8s.io/client-go/rest"
2727
"k8s.io/client-go/tools/events"
2828
"k8s.io/client-go/tools/leaderelection"
29+
"k8s.io/component-base/zpages/flagz"
2930
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
3031
)
3132

3233
// Config has all the context to run a Scheduler
3334
type Config struct {
35+
// Flagz is the Reader interface to get flags for flagz page.
36+
Flagz flagz.Reader
37+
3438
// ComponentConfig is the scheduler server's configuration object.
3539
ComponentConfig kubeschedulerconfig.KubeSchedulerConfiguration
3640

cmd/kube-scheduler/app/options/options.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ import (
4646
logsapi "k8s.io/component-base/logs/api/v1"
4747
"k8s.io/component-base/metrics"
4848
utilversion "k8s.io/component-base/version"
49+
zpagesfeatures "k8s.io/component-base/zpages/features"
50+
"k8s.io/component-base/zpages/flagz"
4951
"k8s.io/klog/v2"
5052
schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
5153
"k8s.io/kubernetes/pkg/scheduler"
@@ -260,6 +262,11 @@ func (o *Options) ApplyTo(logger klog.Logger, c *schedulerappconfig.Config) erro
260262
if o.Deprecated != nil {
261263
c.PodMaxInUnschedulablePodsDuration = o.Deprecated.PodMaxInUnschedulablePodsDuration
262264
}
265+
if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentFlagz) {
266+
if o.Flags != nil {
267+
c.Flagz = flagz.NamedFlagSetsReader{FlagSets: *o.Flags}
268+
}
269+
}
263270

264271
return nil
265272
}

cmd/kube-scheduler/app/server.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ import (
5656
"k8s.io/component-base/term"
5757
utilversion "k8s.io/component-base/version"
5858
"k8s.io/component-base/version/verflag"
59+
zpagesfeatures "k8s.io/component-base/zpages/features"
60+
"k8s.io/component-base/zpages/flagz"
5961
"k8s.io/klog/v2"
6062
schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
6163
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
@@ -68,6 +70,10 @@ import (
6870
"k8s.io/kubernetes/pkg/scheduler/profile"
6971
)
7072

73+
const (
74+
kubeScheduler = "kube-scheduler"
75+
)
76+
7177
func init() {
7278
utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
7379
utilruntime.Must(features.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
@@ -224,7 +230,7 @@ func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *
224230
cc.Client,
225231
metav1.NamespaceSystem,
226232
cc.LeaderElection.Lock.Identity(),
227-
"kube-scheduler",
233+
kubeScheduler,
228234
binaryVersion.FinalizeVersion(),
229235
emulationVersion.FinalizeVersion(),
230236
coordinationv1.OldestEmulationVersion,
@@ -236,9 +242,9 @@ func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *
236242
go leaseCandidate.Run(ctx)
237243
}
238244

239-
// Start up the healthz server.
245+
// Start up the server for endpoints.
240246
if cc.SecureServing != nil {
241-
handler := buildHandlerChain(newHealthEndpointsAndMetricsHandler(&cc.ComponentConfig, cc.InformerFactory, isLeader, checks, readyzChecks), cc.Authentication.Authenticator, cc.Authorization.Authorizer)
247+
handler := buildHandlerChain(newEndpointsHandler(&cc.ComponentConfig, cc.InformerFactory, isLeader, checks, readyzChecks, cc.Flagz), cc.Authentication.Authenticator, cc.Authorization.Authorizer)
242248
// TODO: handle stoppedCh and listenerStoppedCh returned by c.SecureServing.Serve
243249
if _, _, err := cc.SecureServing.Serve(handler, 0, ctx.Done()); err != nil {
244250
// fail early for secure handlers, removing the old error loop from above
@@ -344,11 +350,11 @@ func installMetricHandler(pathRecorderMux *mux.PathRecorderMux, informers inform
344350
})
345351
}
346352

347-
// newHealthEndpointsAndMetricsHandler creates an API health server from the config, and will also
348-
// embed the metrics handler.
353+
// newEndpointsHandler creates an API health server from the config, and will also
354+
// embed the metrics handler and z-pages handler.
349355
// TODO: healthz check is deprecated, please use livez and readyz instead. Will be removed in the future.
350-
func newHealthEndpointsAndMetricsHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, informers informers.SharedInformerFactory, isLeader func() bool, healthzChecks, readyzChecks []healthz.HealthChecker) http.Handler {
351-
pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler")
356+
func newEndpointsHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, informers informers.SharedInformerFactory, isLeader func() bool, healthzChecks, readyzChecks []healthz.HealthChecker, flagReader flagz.Reader) http.Handler {
357+
pathRecorderMux := mux.NewPathRecorderMux(kubeScheduler)
352358
healthz.InstallHandler(pathRecorderMux, healthzChecks...)
353359
healthz.InstallLivezHandler(pathRecorderMux)
354360
healthz.InstallReadyzHandler(pathRecorderMux, readyzChecks...)
@@ -362,6 +368,12 @@ func newHealthEndpointsAndMetricsHandler(config *kubeschedulerconfig.KubeSchedul
362368
}
363369
routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
364370
}
371+
372+
if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentFlagz) {
373+
if flagReader != nil {
374+
flagz.Install(pathRecorderMux, kubeScheduler, flagReader)
375+
}
376+
}
365377
return pathRecorderMux
366378
}
367379

staging/src/k8s.io/component-base/zpages/flagz/flagreader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type Reader interface {
2525
GetFlagz() map[string]string
2626
}
2727

28-
// NamedFlagSetsGetter implements Reader for cliflag.NamedFlagSets
28+
// NamedFlagSetsReader implements Reader for cliflag.NamedFlagSets
2929
type NamedFlagSetsReader struct {
3030
FlagSets cliflag.NamedFlagSets
3131
}

test/integration/scheduler/serving/healthcheck_test.go renamed to test/integration/scheduler/serving/endpoints_test.go

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,21 @@ import (
2424
"net/http"
2525
"os"
2626
"path"
27+
"regexp"
2728
"strings"
2829
"testing"
2930

31+
utilfeature "k8s.io/apiserver/pkg/util/feature"
32+
featuregatetesting "k8s.io/component-base/featuregate/testing"
33+
"k8s.io/component-base/zpages/features"
3034
"k8s.io/klog/v2/ktesting"
3135
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
3236
kubeschedulertesting "k8s.io/kubernetes/cmd/kube-scheduler/app/testing"
3337
"k8s.io/kubernetes/test/integration/framework"
3438
)
3539

36-
func TestHealthEndpoints(t *testing.T) {
40+
func TestEndpointHandlers(t *testing.T) {
41+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ComponentFlagz, true)
3742
server, configStr, _, err := startTestAPIServer(t)
3843
if err != nil {
3944
t.Fatalf("Failed to start kube-apiserver server: %v", err)
@@ -64,52 +69,64 @@ func TestHealthEndpoints(t *testing.T) {
6469
}()
6570

6671
tests := []struct {
67-
name string
68-
path string
69-
useBrokenConfig bool
70-
wantResponseCode int
72+
name string
73+
path string
74+
useBrokenConfig bool
75+
requestHeader map[string]string
76+
wantResponseCode int
77+
wantResponseBodyRegx string
7178
}{
7279
{
73-
"/healthz",
74-
"/healthz",
75-
false,
76-
http.StatusOK,
80+
name: "/healthz",
81+
path: "/healthz",
82+
useBrokenConfig: false,
83+
wantResponseCode: http.StatusOK,
7784
},
7885
{
79-
"/livez",
80-
"/livez",
81-
false,
82-
http.StatusOK,
86+
name: "/livez",
87+
path: "/livez",
88+
useBrokenConfig: false,
89+
wantResponseCode: http.StatusOK,
8390
},
8491
{
85-
"/livez with ping check",
86-
"/livez/ping",
87-
false,
88-
http.StatusOK,
92+
name: "/livez with ping check",
93+
path: "/livez/ping",
94+
useBrokenConfig: false,
95+
wantResponseCode: http.StatusOK,
8996
},
9097
{
91-
"/readyz",
92-
"/readyz",
93-
false,
94-
http.StatusOK,
98+
name: "/readyz",
99+
path: "/readyz",
100+
useBrokenConfig: false,
101+
wantResponseCode: http.StatusOK,
95102
},
96103
{
97-
"/readyz with sched-handler-sync",
98-
"/readyz/sched-handler-sync",
99-
false,
100-
http.StatusOK,
104+
name: "/readyz with sched-handler-sync",
105+
path: "/readyz/sched-handler-sync",
106+
useBrokenConfig: false,
107+
wantResponseCode: http.StatusOK,
101108
},
102109
{
103-
"/readyz with shutdown",
104-
"/readyz/shutdown",
105-
false,
106-
http.StatusOK,
110+
name: "/readyz with shutdown",
111+
path: "/readyz/shutdown",
112+
useBrokenConfig: false,
113+
wantResponseCode: http.StatusOK,
107114
},
108115
{
109-
"/readyz with broken apiserver",
110-
"/readyz",
111-
true,
112-
http.StatusInternalServerError,
116+
name: "/readyz with broken apiserver",
117+
path: "/readyz",
118+
useBrokenConfig: true,
119+
wantResponseCode: http.StatusInternalServerError,
120+
},
121+
{
122+
name: "/flagz",
123+
path: "/flagz",
124+
requestHeader: map[string]string{"Accept": "text/plain"},
125+
wantResponseCode: http.StatusOK,
126+
wantResponseBodyRegx: `^\n` +
127+
`kube-scheduler flags\n` +
128+
`Warning: This endpoint is not meant to be machine parseable, ` +
129+
`has no formatting compatibility guarantees and is for debugging purposes only.`,
113130
},
114131
}
115132

@@ -141,6 +158,11 @@ func TestHealthEndpoints(t *testing.T) {
141158
if err != nil {
142159
t.Fatalf("failed to request: %v", err)
143160
}
161+
if tt.requestHeader != nil {
162+
for k, v := range tt.requestHeader {
163+
req.Header.Set(k, v)
164+
}
165+
}
144166
r, err := client.Do(req)
145167
if err != nil {
146168
t.Fatalf("failed to GET %s from component: %v", tt.path, err)
@@ -156,6 +178,15 @@ func TestHealthEndpoints(t *testing.T) {
156178
if got, expected := r.StatusCode, tt.wantResponseCode; got != expected {
157179
t.Fatalf("expected http %d at %s of component, got: %d %q", expected, tt.path, got, string(body))
158180
}
181+
if tt.wantResponseBodyRegx != "" {
182+
matched, err := regexp.MatchString(tt.wantResponseBodyRegx, string(body))
183+
if err != nil {
184+
t.Fatalf("failed to compile regex: %v", err)
185+
}
186+
if !matched {
187+
t.Fatalf("response body does not match regex.\nExpected:\n%s\n\nGot:\n%s", tt.wantResponseBodyRegx, string(body))
188+
}
189+
}
159190
})
160191
}
161192
}

0 commit comments

Comments
 (0)