Skip to content

Commit 917327d

Browse files
authored
Merge pull request #4889 from mn-ram/fix/guestagent-client-leak
hostagent: close stale GuestAgentClient on reconnect to stop ClientConn leak
2 parents f121314 + 714becb commit 917327d

2 files changed

Lines changed: 45 additions & 4 deletions

File tree

pkg/guestagent/api/client/client.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import (
1818
)
1919

2020
type GuestAgentClient struct {
21-
cli api.GuestServiceClient
21+
cli api.GuestServiceClient
22+
conn *grpc.ClientConn
2223
}
2324

2425
func NewGuestAgentClient(dialFn func(ctx context.Context) (net.Conn, error)) (*GuestAgentClient, error) {
@@ -44,10 +45,20 @@ func NewGuestAgentClient(dialFn func(ctx context.Context) (net.Conn, error)) (*G
4445
}
4546
client := api.NewGuestServiceClient(clientConn)
4647
return &GuestAgentClient{
47-
cli: client,
48+
cli: client,
49+
conn: clientConn,
4850
}, nil
4951
}
5052

53+
// Close releases the underlying gRPC connection. It is safe to call on a nil
54+
// receiver or a client whose connection has already been closed.
55+
func (c *GuestAgentClient) Close() error {
56+
if c == nil || c.conn == nil {
57+
return nil
58+
}
59+
return c.conn.Close()
60+
}
61+
5162
func (c *GuestAgentClient) Info(ctx context.Context) (*api.Info, error) {
5263
return c.cli.GetInfo(ctx, &emptypb.Empty{})
5364
}

pkg/hostagent/hostagent.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
728728

729729
go func() {
730730
if a.instConfig.MountInotify != nil && *a.instConfig.MountInotify {
731-
if a.client == nil || !isGuestAgentSocketAccessible(ctx, a.client) {
731+
client := a.getClient()
732+
if client == nil || !isGuestAgentSocketAccessible(ctx, client) {
732733
if a.driver.ForwardGuestAgent() {
733734
sshAddress, sshPort := a.sshAddressPort()
734735
_ = forwardSSH(ctx, a.sshConfig, sshAddress, sshPort, localUnix, remoteUnix, verbForward, false)
@@ -743,9 +744,20 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
743744

744745
// ensure close before ctx is cancelled
745746
a.cleanUp(a.grpcPortForwarder.Close)
747+
a.cleanUp(func() error {
748+
a.clientMu.Lock()
749+
defer a.clientMu.Unlock()
750+
if a.client == nil {
751+
return nil
752+
}
753+
err := a.client.Close()
754+
a.client = nil
755+
return err
756+
})
746757

747758
for {
748-
if a.client == nil || !isGuestAgentSocketAccessible(ctx, a.client) {
759+
client := a.getClient()
760+
if client == nil || !isGuestAgentSocketAccessible(ctx, client) {
749761
if a.driver.ForwardGuestAgent() {
750762
sshAddress, sshPort := a.sshAddressPort()
751763
_ = forwardSSH(ctx, a.sshConfig, sshAddress, sshPort, localUnix, remoteUnix, verbForward, false)
@@ -820,12 +832,30 @@ func isGuestAgentSocketAccessible(ctx context.Context, client *guestagentclient.
820832
return err == nil
821833
}
822834

835+
// getClient returns the current guest agent client under the clientMu lock,
836+
// so callers observe a consistent (non-mid-transition) snapshot.
837+
func (a *HostAgent) getClient() *guestagentclient.GuestAgentClient {
838+
a.clientMu.Lock()
839+
defer a.clientMu.Unlock()
840+
return a.client
841+
}
842+
823843
func (a *HostAgent) getOrCreateClient(ctx context.Context) (*guestagentclient.GuestAgentClient, error) {
824844
a.clientMu.Lock()
825845
defer a.clientMu.Unlock()
826846
if a.client != nil && isGuestAgentSocketAccessible(ctx, a.client) {
827847
return a.client, nil
828848
}
849+
// The previous client (if any) is unreachable: close its underlying gRPC
850+
// ClientConn before replacing it, otherwise the resolver/transport
851+
// goroutines and the dialed net.Conn (e.g. forwarded ga.sock) leak across
852+
// every guest agent restart or VM reboot.
853+
if a.client != nil {
854+
if err := a.client.Close(); err != nil {
855+
logrus.WithError(err).Debug("failed to close stale guest agent client")
856+
}
857+
a.client = nil
858+
}
829859
var err error
830860
a.client, err = guestagentclient.NewGuestAgentClient(a.createConnection)
831861
return a.client, err

0 commit comments

Comments
 (0)