Skip to content

Commit 7eb8d62

Browse files
committed
agent: smarter readiness check
This commit introduces a smarter way for the readiness check. Currently as soon as the agent is up, it signals itself as ready regardless of whether its actually connected to the server or not. This commit introduces a readiness check in the Agent which reports true if its connected to atleast one proxy server. Signed-off-by: Imran Pochi <[email protected]>
1 parent b006c04 commit 7eb8d62

File tree

4 files changed

+86
-11
lines changed

4 files changed

+86
-11
lines changed

cmd/agent/app/server.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"k8s.io/klog/v2"
3737

3838
"sigs.k8s.io/apiserver-network-proxy/cmd/agent/app/options"
39+
"sigs.k8s.io/apiserver-network-proxy/pkg/agent"
3940
"sigs.k8s.io/apiserver-network-proxy/pkg/util"
4041
)
4142

@@ -63,11 +64,13 @@ func (a *Agent) run(o *options.GrpcProxyAgentOptions) error {
6364
}
6465

6566
stopCh := make(chan struct{})
66-
if err := a.runProxyConnection(o, stopCh); err != nil {
67+
68+
cs, err := a.runProxyConnection(o, stopCh)
69+
if err != nil {
6770
return fmt.Errorf("failed to run proxy connection with %v", err)
6871
}
6972

70-
if err := a.runHealthServer(o); err != nil {
73+
if err := a.runHealthServer(o, cs); err != nil {
7174
return fmt.Errorf("failed to run health server with %v", err)
7275
}
7376

@@ -80,11 +83,11 @@ func (a *Agent) run(o *options.GrpcProxyAgentOptions) error {
8083
return nil
8184
}
8285

83-
func (a *Agent) runProxyConnection(o *options.GrpcProxyAgentOptions, stopCh <-chan struct{}) error {
86+
func (a *Agent) runProxyConnection(o *options.GrpcProxyAgentOptions, stopCh <-chan struct{}) (agent.ReadinessManager, error) {
8487
var tlsConfig *tls.Config
8588
var err error
8689
if tlsConfig, err = util.GetClientTLSConfig(o.CaCert, o.AgentCert, o.AgentKey, o.ProxyServerHost, o.AlpnProtos); err != nil {
87-
return err
90+
return nil, err
8891
}
8992
dialOptions := []grpc.DialOption{
9093
grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
@@ -97,15 +100,21 @@ func (a *Agent) runProxyConnection(o *options.GrpcProxyAgentOptions, stopCh <-ch
97100
cs := cc.NewAgentClientSet(stopCh)
98101
cs.Serve()
99102

100-
return nil
103+
return cs, nil
101104
}
102105

103-
func (a *Agent) runHealthServer(o *options.GrpcProxyAgentOptions) error {
106+
func (a *Agent) runHealthServer(o *options.GrpcProxyAgentOptions, cs agent.ReadinessManager) error {
104107
livenessHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
105108
fmt.Fprintf(w, "ok")
106109
})
107110
readinessHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
108-
fmt.Fprintf(w, "ok")
111+
if cs.Ready() {
112+
w.WriteHeader(http.StatusOK)
113+
fmt.Fprintf(w, "ok")
114+
} else {
115+
w.WriteHeader(http.StatusServiceUnavailable)
116+
fmt.Fprintf(w, "not ready")
117+
}
109118
})
110119

111120
muxHandler := http.NewServeMux()

pkg/agent/readiness.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
copyright 2023 the kubernetes authors.
3+
4+
licensed under the apache license, version 2.0 (the "license");
5+
you may not use this file except in compliance with the license.
6+
you may obtain a copy of the license at
7+
8+
http://www.apache.org/licenses/license-2.0
9+
10+
unless required by applicable law or agreed to in writing, software
11+
distributed under the license is distributed on an "as is" basis,
12+
without warranties or conditions of any kind, either express or implied.
13+
see the license for the specific language governing permissions and
14+
limitations under the license.
15+
*/
16+
17+
package agent
18+
19+
// ReadinessManager supports checking if the agent is ready.
20+
type ReadinessManager interface {
21+
// Ready returns true the proxy server is ready.
22+
Ready() bool
23+
}
24+
25+
var _ ReadinessManager = &ClientSet{}
26+
27+
func (cs *ClientSet) Ready() bool {
28+
// Returns true if the agent is connected to at least one server.
29+
return cs.HealthyClientsCount() > 0
30+
}

tests/proxy_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,7 @@ func runAgentWithID(agentID, addr string, stopCh <-chan struct{}) *agent.ClientS
969969
ProbeInterval: 100 * time.Millisecond,
970970
DialOptions: []grpc.DialOption{grpc.WithInsecure()},
971971
}
972+
972973
client := cc.NewAgentClientSet(stopCh)
973974
client.Serve()
974975
return client

tests/readiness_test.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ limitations under the License.
1616

1717
package tests
1818

19-
import (
20-
"testing"
21-
)
19+
import "testing"
2220

23-
func TestReadiness(t *testing.T) {
21+
func TestGRPCServerAndAgentReadiness(t *testing.T) {
2422
stopCh := make(chan struct{})
2523
defer close(stopCh)
2624

@@ -38,8 +36,45 @@ func TestReadiness(t *testing.T) {
3836
clientset := runAgent(proxy.agent, stopCh)
3937
waitForConnectedServerCount(t, 1, clientset)
4038

39+
// check the agent connected status
40+
isAgentReady := clientset.Ready()
41+
if !isAgentReady {
42+
t.Fatalf("expected connection status 'true', got: %t", isAgentReady)
43+
}
4144
ready, _ = server.Readiness.Ready()
4245
if !ready {
4346
t.Fatalf("expected ready")
4447
}
4548
}
49+
50+
func TestHTTPConnServerAndAgentReadiness(t *testing.T) {
51+
stopCh := make(chan struct{})
52+
defer close(stopCh)
53+
54+
proxy, cleanup, err := runHTTPConnProxyServer()
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
defer cleanup()
59+
60+
clientset := runAgent(proxy.agent, stopCh)
61+
waitForConnectedServerCount(t, 1, clientset)
62+
63+
// check the agent connected status
64+
isAgentReady := clientset.Ready()
65+
if !isAgentReady {
66+
t.Fatalf("expected connection status 'true', got: %t", isAgentReady)
67+
}
68+
}
69+
70+
func TestAgentReadinessWithoutServer(t *testing.T) {
71+
stopCh := make(chan struct{})
72+
defer close(stopCh)
73+
74+
clientset := runAgent("localhost:8080", stopCh)
75+
// check the agent connected status
76+
isAgentReady := clientset.Ready()
77+
if isAgentReady {
78+
t.Fatalf("expected connection status 'false', got: %t", isAgentReady)
79+
}
80+
}

0 commit comments

Comments
 (0)