@@ -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+
823843func (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