diff --git a/lib/reversetunnel/remotesite.go b/lib/reversetunnel/remotesite.go index abe1e63d8cc..6586e365b98 100644 --- a/lib/reversetunnel/remotesite.go +++ b/lib/reversetunnel/remotesite.go @@ -44,7 +44,7 @@ import ( // the local reverse tunnel server, and now it can provide access to the // cluster behind it. type remoteSite struct { - sync.Mutex + sync.RWMutex *log.Entry domainName string @@ -73,14 +73,14 @@ func (s *remoteSite) String() string { } func (s *remoteSite) connectionCount() int { - s.Lock() - defer s.Unlock() + s.RLock() + defer s.RUnlock() return len(s.connections) } func (s *remoteSite) hasValidConnections() bool { - s.Lock() - defer s.Unlock() + s.RLock() + defer s.RUnlock() for _, conn := range s.connections { if !conn.isInvalid() { @@ -156,10 +156,17 @@ func (s *remoteSite) GetStatus() string { return RemoteSiteStatusOffline } +func (s *remoteSite) copyConnInfo() services.TunnelConnection { + s.RLock() + defer s.RUnlock() + return s.connInfo.Clone() +} + func (s *remoteSite) registerHeartbeat(t time.Time) { - s.connInfo.SetLastHeartbeat(t) - s.connInfo.SetExpiry(s.clock.Now().Add(defaults.ReverseTunnelOfflineThreshold)) - err := s.srv.AccessPoint.UpsertTunnelConnection(s.connInfo) + connInfo := s.copyConnInfo() + connInfo.SetLastHeartbeat(t) + connInfo.SetExpiry(s.clock.Now().Add(defaults.ReverseTunnelOfflineThreshold)) + err := s.srv.AccessPoint.UpsertTunnelConnection(connInfo) if err != nil { s.Warningf("failed to register heartbeat: %v", err) } diff --git a/lib/services/tunnelconn.go b/lib/services/tunnelconn.go index f7127bf12b2..7186ddd9181 100644 --- a/lib/services/tunnelconn.go +++ b/lib/services/tunnelconn.go @@ -35,6 +35,8 @@ type TunnelConnection interface { CheckAndSetDefaults() error // String returns user friendly representation of this connection String() string + // Clone returns a copy of this tunnel connection + Clone() TunnelConnection } // MustCreateTunnelConnection returns new connection from V2 spec or panics if @@ -76,6 +78,12 @@ type TunnelConnectionV2 struct { Spec TunnelConnectionSpecV2 `json:"spec"` } +// Clone returns a copy of this tunnel connection +func (r *TunnelConnectionV2) Clone() TunnelConnection { + out := *r + return &out +} + // String returns user-friendly description of this connection func (r *TunnelConnectionV2) String() string { return fmt.Sprintf("TunnelConnection(name=%v, cluster=%v, proxy=%v)", r.Metadata.Name, r.Spec.ClusterName, r.Spec.ProxyName)