Skip to content

Commit 3f68000

Browse files
mborszwojtek-t
authored andcommitted
Wait for all informers to sync in /readyz.
1 parent dcdeed9 commit 3f68000

File tree

5 files changed

+63
-16
lines changed

5 files changed

+63
-16
lines changed

staging/src/k8s.io/apiserver/pkg/server/config.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -605,13 +605,20 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
605605
}
606606

607607
genericApiServerHookName := "generic-apiserver-start-informers"
608-
if c.SharedInformerFactory != nil && !s.isPostStartHookRegistered(genericApiServerHookName) {
609-
err := s.AddPostStartHook(genericApiServerHookName, func(context PostStartHookContext) error {
610-
c.SharedInformerFactory.Start(context.StopCh)
611-
return nil
612-
})
613-
if err != nil {
614-
return nil, err
608+
if c.SharedInformerFactory != nil {
609+
if !s.isPostStartHookRegistered(genericApiServerHookName) {
610+
err := s.AddPostStartHook(genericApiServerHookName, func(context PostStartHookContext) error {
611+
c.SharedInformerFactory.Start(context.StopCh)
612+
return nil
613+
})
614+
if err != nil {
615+
return nil, err
616+
}
617+
// TODO: Once we get rid of /healthz consider changing this to post-start-hook.
618+
err = s.addReadyzChecks(healthz.NewInformerSyncHealthz(c.SharedInformerFactory))
619+
if err != nil {
620+
return nil, err
621+
}
615622
}
616623
}
617624

staging/src/k8s.io/apiserver/pkg/server/config_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func TestNewWithDelegate(t *testing.T) {
167167
"/metrics",
168168
"/readyz",
169169
"/readyz/delegate-health",
170+
"/readyz/informer-sync",
170171
"/readyz/log",
171172
"/readyz/ping",
172173
"/readyz/poststarthook/delegate-post-start-hook",
@@ -242,10 +243,10 @@ func checkExpectedPathsAtRoot(url string, expectedPaths []string, t *testing.T)
242243
pathset.Insert(p.(string))
243244
}
244245
expectedset := sets.NewString(expectedPaths...)
245-
for _, p := range pathset.Difference(expectedset) {
246+
for p := range pathset.Difference(expectedset) {
246247
t.Errorf("Got %v path, which we did not expect", p)
247248
}
248-
for _, p := range expectedset.Difference(pathset) {
249+
for p := range expectedset.Difference(pathset) {
249250
t.Errorf(" Expected %v path which we did not get", p)
250251
}
251252
})

staging/src/k8s.io/apiserver/pkg/server/healthz/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ go_library(
3131
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
3232
"//staging/src/k8s.io/apiserver/pkg/endpoints/metrics:go_default_library",
3333
"//staging/src/k8s.io/apiserver/pkg/server/httplog:go_default_library",
34+
"//staging/src/k8s.io/client-go/informers:go_default_library",
3435
"//vendor/k8s.io/klog/v2:go_default_library",
3536
],
3637
)

staging/src/k8s.io/apiserver/pkg/server/healthz/healthz.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/apimachinery/pkg/util/wait"
3030
"k8s.io/apiserver/pkg/endpoints/metrics"
3131
"k8s.io/apiserver/pkg/server/httplog"
32+
"k8s.io/client-go/informers"
3233
"k8s.io/klog/v2"
3334
)
3435

@@ -81,6 +82,39 @@ func (l *log) Check(_ *http.Request) error {
8182
return fmt.Errorf("logging blocked")
8283
}
8384

85+
type informerSync struct {
86+
sharedInformerFactory informers.SharedInformerFactory
87+
}
88+
89+
var _ HealthChecker = &informerSync{}
90+
91+
// NewInformerSyncHealthz returns a new HealthChecker that will pass only if all informers in the given sharedInformerFactory sync.
92+
func NewInformerSyncHealthz(sharedInformerFactory informers.SharedInformerFactory) HealthChecker {
93+
return &informerSync{
94+
sharedInformerFactory: sharedInformerFactory,
95+
}
96+
}
97+
98+
func (i *informerSync) Name() string {
99+
return "informer-sync"
100+
}
101+
102+
func (i *informerSync) Check(_ *http.Request) error {
103+
stopCh := make(chan struct{})
104+
// Close stopCh to force checking if informers are synced now.
105+
close(stopCh)
106+
107+
var informersByStarted map[bool][]string
108+
for informerType, started := range i.sharedInformerFactory.WaitForCacheSync(stopCh) {
109+
informersByStarted[started] = append(informersByStarted[started], informerType.String())
110+
}
111+
112+
if notStarted := informersByStarted[false]; len(notStarted) > 0 {
113+
return fmt.Errorf("%d informers not started yet: %v", len(notStarted), notStarted)
114+
}
115+
return nil
116+
}
117+
84118
// NamedCheck returns a healthz checker for the given name and function.
85119
func NamedCheck(name string, check func(r *http.Request) error) HealthChecker {
86120
return &healthzCheck{name, check}

test/integration/master/kube_apiserver_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,15 @@ func TestRun(t *testing.T) {
9898
}
9999
}
100100

101-
func endpointReturnsStatusOK(client *kubernetes.Clientset, path string) bool {
102-
res := client.CoreV1().RESTClient().Get().AbsPath(path).Do(context.TODO())
101+
func endpointReturnsStatusOK(client *kubernetes.Clientset, path string) (bool, error) {
102+
res := client.CoreV1().RESTClient().Get().RequestURI(path).Do(context.TODO())
103103
var status int
104104
res.StatusCode(&status)
105-
return status == http.StatusOK
105+
_, err := res.Raw()
106+
if err != nil {
107+
return false, err
108+
}
109+
return status == http.StatusOK, nil
106110
}
107111

108112
func TestLivezAndReadyz(t *testing.T) {
@@ -113,11 +117,11 @@ func TestLivezAndReadyz(t *testing.T) {
113117
if err != nil {
114118
t.Fatalf("unexpected error: %v", err)
115119
}
116-
if !endpointReturnsStatusOK(client, "/livez") {
117-
t.Fatalf("livez should be healthy")
120+
if statusOK, err := endpointReturnsStatusOK(client, "/livez"); err != nil || !statusOK {
121+
t.Fatalf("livez should be healthy, got %v and error %v", statusOK, err)
118122
}
119-
if !endpointReturnsStatusOK(client, "/readyz") {
120-
t.Fatalf("readyz should be healthy")
123+
if statusOK, err := endpointReturnsStatusOK(client, "/readyz"); err != nil || !statusOK {
124+
t.Fatalf("readyz should be healthy, got %v and error %v", statusOK, err)
121125
}
122126
}
123127

0 commit comments

Comments
 (0)