mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-02 04:51:29 +02:00
Split the status summary into per-section helpers and scope retrackConn to service mode
This commit is contained in:
@@ -449,68 +449,17 @@ func (o *OutputOverview) YAML() (string, error) {
|
||||
|
||||
// GeneralSummary returns a general summary of the status overview.
|
||||
func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameServers bool, showSessions bool) string {
|
||||
var managementConnString string
|
||||
if o.ManagementState.Connected {
|
||||
managementConnString = "Connected"
|
||||
if showURL {
|
||||
managementConnString = fmt.Sprintf("%s to %s", managementConnString, o.ManagementState.URL)
|
||||
}
|
||||
} else {
|
||||
managementConnString = "Disconnected"
|
||||
if o.ManagementState.Error != "" {
|
||||
managementConnString = fmt.Sprintf("%s, reason: %s", managementConnString, o.ManagementState.Error)
|
||||
}
|
||||
}
|
||||
managementConnString := connectionSummary(o.ManagementState.Connected, o.ManagementState.URL, o.ManagementState.Error, showURL)
|
||||
signalConnString := connectionSummary(o.SignalState.Connected, o.SignalState.URL, o.SignalState.Error, showURL)
|
||||
|
||||
var signalConnString string
|
||||
if o.SignalState.Connected {
|
||||
signalConnString = "Connected"
|
||||
if showURL {
|
||||
signalConnString = fmt.Sprintf("%s to %s", signalConnString, o.SignalState.URL)
|
||||
}
|
||||
} else {
|
||||
signalConnString = "Disconnected"
|
||||
if o.SignalState.Error != "" {
|
||||
signalConnString = fmt.Sprintf("%s, reason: %s", signalConnString, o.SignalState.Error)
|
||||
}
|
||||
}
|
||||
|
||||
interfaceTypeString := "Userspace"
|
||||
interfaceIP := o.IP
|
||||
if o.KernelInterface {
|
||||
interfaceTypeString = "Kernel"
|
||||
} else if o.IP == "" {
|
||||
interfaceTypeString = "N/A"
|
||||
interfaceIP = "N/A"
|
||||
}
|
||||
interfaceTypeString, interfaceIP := o.interfaceSummary()
|
||||
|
||||
ipv6Line := ""
|
||||
if o.IPv6 != "" {
|
||||
ipv6Line = fmt.Sprintf("NetBird IPv6: %s\n", o.IPv6)
|
||||
}
|
||||
|
||||
var relaysString string
|
||||
if showRelays {
|
||||
for _, relay := range o.Relays.Details {
|
||||
available := "Available"
|
||||
reason := ""
|
||||
|
||||
if !relay.Available {
|
||||
if relay.Error == probeRelay.ErrCheckInProgress.Error() {
|
||||
available = "Checking..."
|
||||
} else {
|
||||
available = "Unavailable"
|
||||
reason = fmt.Sprintf(", reason: %s", relay.Error)
|
||||
}
|
||||
} else if relay.Transport != "" {
|
||||
available = fmt.Sprintf("%s via %s", available, relay.Transport)
|
||||
}
|
||||
|
||||
relaysString += fmt.Sprintf("\n [%s] is %s%s", relay.URI, available, reason)
|
||||
}
|
||||
} else {
|
||||
relaysString = fmt.Sprintf("%d/%d Available", o.Relays.Available, o.Relays.Total)
|
||||
}
|
||||
relaysString := o.relaysSummary(showRelays)
|
||||
|
||||
networks := "-"
|
||||
if len(o.Networks) > 0 {
|
||||
@@ -518,34 +467,7 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS
|
||||
networks = strings.Join(o.Networks, ", ")
|
||||
}
|
||||
|
||||
var dnsServersString string
|
||||
if showNameServers {
|
||||
for _, nsServerGroup := range o.NSServerGroups {
|
||||
enabled := "Available"
|
||||
if !nsServerGroup.Enabled {
|
||||
enabled = "Unavailable"
|
||||
}
|
||||
errorString := ""
|
||||
if nsServerGroup.Error != "" {
|
||||
errorString = fmt.Sprintf(", reason: %s", nsServerGroup.Error)
|
||||
errorString = strings.TrimSpace(errorString)
|
||||
}
|
||||
|
||||
domainsString := strings.Join(nsServerGroup.Domains, ", ")
|
||||
if domainsString == "" {
|
||||
domainsString = "." // Show "." for the default zone
|
||||
}
|
||||
dnsServersString += fmt.Sprintf(
|
||||
"\n [%s] for [%s] is %s%s",
|
||||
strings.Join(nsServerGroup.Servers, ", "),
|
||||
domainsString,
|
||||
enabled,
|
||||
errorString,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
dnsServersString = fmt.Sprintf("%d/%d Available", countEnabled(o.NSServerGroups), len(o.NSServerGroups))
|
||||
}
|
||||
dnsServersString := o.nameserversSummary(showNameServers)
|
||||
|
||||
rosenpassEnabledStatus := "false"
|
||||
if o.RosenpassEnabled {
|
||||
@@ -560,63 +482,8 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS
|
||||
lazyConnectionEnabledStatus = "true"
|
||||
}
|
||||
|
||||
sshServerStatus := "Disabled"
|
||||
if o.SSHServerState.Enabled {
|
||||
sessionCount := len(o.SSHServerState.Sessions)
|
||||
if sessionCount > 0 {
|
||||
sessionWord := "session"
|
||||
if sessionCount > 1 {
|
||||
sessionWord = "sessions"
|
||||
}
|
||||
sshServerStatus = fmt.Sprintf("Enabled (%d active %s)", sessionCount, sessionWord)
|
||||
} else {
|
||||
sshServerStatus = "Enabled"
|
||||
}
|
||||
|
||||
if showSessions && sessionCount > 0 {
|
||||
for _, session := range o.SSHServerState.Sessions {
|
||||
var sessionDisplay string
|
||||
if session.JWTUsername != "" {
|
||||
sessionDisplay = fmt.Sprintf("[%s@%s -> %s] %s",
|
||||
session.JWTUsername,
|
||||
session.RemoteAddress,
|
||||
session.Username,
|
||||
session.Command,
|
||||
)
|
||||
} else {
|
||||
sessionDisplay = fmt.Sprintf("[%s@%s] %s",
|
||||
session.Username,
|
||||
session.RemoteAddress,
|
||||
session.Command,
|
||||
)
|
||||
}
|
||||
sshServerStatus += "\n " + sessionDisplay
|
||||
for _, pf := range session.PortForwards {
|
||||
sshServerStatus += "\n " + pf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vncServerStatus := "Disabled"
|
||||
if o.VNCServerState.Enabled {
|
||||
vncSessionCount := len(o.VNCServerState.Sessions)
|
||||
if vncSessionCount > 0 {
|
||||
sessionWord := "session"
|
||||
if vncSessionCount > 1 {
|
||||
sessionWord = "sessions"
|
||||
}
|
||||
vncServerStatus = fmt.Sprintf("Enabled (%d active %s)", vncSessionCount, sessionWord)
|
||||
} else {
|
||||
vncServerStatus = "Enabled"
|
||||
}
|
||||
|
||||
if showSessions && vncSessionCount > 0 {
|
||||
for _, sess := range o.VNCServerState.Sessions {
|
||||
vncServerStatus += "\n " + formatVNCSessionLine(sess)
|
||||
}
|
||||
}
|
||||
}
|
||||
sshServerStatus := o.sshServerSummary(showSessions)
|
||||
vncServerStatus := o.vncServerSummary(showSessions)
|
||||
|
||||
peersCountString := fmt.Sprintf("%d/%d Connected", o.Peers.Connected, o.Peers.Total)
|
||||
|
||||
@@ -634,22 +501,7 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS
|
||||
forwardingRulesString = fmt.Sprintf("Forwarding rules: %d\n", o.NumberOfForwardingRules)
|
||||
}
|
||||
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
goarm := ""
|
||||
if goarch == "arm" {
|
||||
goarm = fmt.Sprintf(" (ARMv%s)", os.Getenv("GOARM"))
|
||||
}
|
||||
|
||||
daemonVersion := "N/A"
|
||||
if o.DaemonVersion != "" {
|
||||
daemonVersion = o.DaemonVersion
|
||||
}
|
||||
|
||||
cliVersion := version.NetbirdVersion()
|
||||
if o.CliVersion != "" {
|
||||
cliVersion = o.CliVersion
|
||||
}
|
||||
osString, daemonVersion, cliVersion := o.versionSummary()
|
||||
|
||||
wgPortString := "N/A"
|
||||
if o.WgPort > 0 {
|
||||
@@ -678,7 +530,7 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS
|
||||
"%s"+
|
||||
"%s"+
|
||||
"Peers count: %s\n",
|
||||
fmt.Sprintf("%s/%s%s", goos, goarch, goarm),
|
||||
osString,
|
||||
daemonVersion,
|
||||
cliVersion,
|
||||
o.ProfileName,
|
||||
@@ -703,6 +555,169 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS
|
||||
return summary
|
||||
}
|
||||
|
||||
// connectionSummary describes a management or signal connection in one line:
|
||||
// where it is connected to, or why it is not.
|
||||
func connectionSummary(connected bool, url, errMsg string, showURL bool) string {
|
||||
if !connected {
|
||||
if errMsg != "" {
|
||||
return fmt.Sprintf("Disconnected, reason: %s", errMsg)
|
||||
}
|
||||
return "Disconnected"
|
||||
}
|
||||
if showURL {
|
||||
return fmt.Sprintf("Connected to %s", url)
|
||||
}
|
||||
return "Connected"
|
||||
}
|
||||
|
||||
// interfaceSummary reports the WireGuard interface type and the address to
|
||||
// print for it.
|
||||
func (o *OutputOverview) interfaceSummary() (string, string) {
|
||||
if o.KernelInterface {
|
||||
return "Kernel", o.IP
|
||||
}
|
||||
if o.IP == "" {
|
||||
return "N/A", "N/A"
|
||||
}
|
||||
return "Userspace", o.IP
|
||||
}
|
||||
|
||||
// relaysSummary lists each relay and its availability when showRelays is set,
|
||||
// and otherwise reduces them to an available-of-total count.
|
||||
func (o *OutputOverview) relaysSummary(showRelays bool) string {
|
||||
if !showRelays {
|
||||
return fmt.Sprintf("%d/%d Available", o.Relays.Available, o.Relays.Total)
|
||||
}
|
||||
|
||||
var summary string
|
||||
for _, relay := range o.Relays.Details {
|
||||
available := "Available"
|
||||
reason := ""
|
||||
|
||||
if !relay.Available {
|
||||
if relay.Error == probeRelay.ErrCheckInProgress.Error() {
|
||||
available = "Checking..."
|
||||
} else {
|
||||
available = "Unavailable"
|
||||
reason = fmt.Sprintf(", reason: %s", relay.Error)
|
||||
}
|
||||
} else if relay.Transport != "" {
|
||||
available = fmt.Sprintf("%s via %s", available, relay.Transport)
|
||||
}
|
||||
|
||||
summary += fmt.Sprintf("\n [%s] is %s%s", relay.URI, available, reason)
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
// nameserversSummary lists each nameserver group and the domains it serves
|
||||
// when showNameServers is set, and otherwise reduces them to a count.
|
||||
func (o *OutputOverview) nameserversSummary(showNameServers bool) string {
|
||||
if !showNameServers {
|
||||
return fmt.Sprintf("%d/%d Available", countEnabled(o.NSServerGroups), len(o.NSServerGroups))
|
||||
}
|
||||
|
||||
var summary string
|
||||
for _, nsServerGroup := range o.NSServerGroups {
|
||||
enabled := "Available"
|
||||
if !nsServerGroup.Enabled {
|
||||
enabled = "Unavailable"
|
||||
}
|
||||
errorString := ""
|
||||
if nsServerGroup.Error != "" {
|
||||
errorString = strings.TrimSpace(fmt.Sprintf(", reason: %s", nsServerGroup.Error))
|
||||
}
|
||||
|
||||
domainsString := strings.Join(nsServerGroup.Domains, ", ")
|
||||
if domainsString == "" {
|
||||
domainsString = "." // Show "." for the default zone
|
||||
}
|
||||
summary += fmt.Sprintf(
|
||||
"\n [%s] for [%s] is %s%s",
|
||||
strings.Join(nsServerGroup.Servers, ", "),
|
||||
domainsString,
|
||||
enabled,
|
||||
errorString,
|
||||
)
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
// sshServerSummary reports whether the SSH server runs and how many sessions
|
||||
// it carries, listing them when showSessions is set.
|
||||
func (o *OutputOverview) sshServerSummary(showSessions bool) string {
|
||||
if !o.SSHServerState.Enabled {
|
||||
return "Disabled"
|
||||
}
|
||||
|
||||
sessions := o.SSHServerState.Sessions
|
||||
summary := serverEnabledLine(len(sessions))
|
||||
if !showSessions {
|
||||
return summary
|
||||
}
|
||||
|
||||
for _, session := range sessions {
|
||||
summary += "\n " + formatSSHSessionLine(session)
|
||||
for _, pf := range session.PortForwards {
|
||||
summary += "\n " + pf
|
||||
}
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
// vncServerSummary is sshServerSummary for the VNC server.
|
||||
func (o *OutputOverview) vncServerSummary(showSessions bool) string {
|
||||
if !o.VNCServerState.Enabled {
|
||||
return "Disabled"
|
||||
}
|
||||
|
||||
sessions := o.VNCServerState.Sessions
|
||||
summary := serverEnabledLine(len(sessions))
|
||||
if !showSessions {
|
||||
return summary
|
||||
}
|
||||
|
||||
for _, sess := range sessions {
|
||||
summary += "\n " + formatVNCSessionLine(sess)
|
||||
}
|
||||
return summary
|
||||
}
|
||||
|
||||
// serverEnabledLine states that a remote-access server is enabled, naming the
|
||||
// session count when it carries any.
|
||||
func serverEnabledLine(sessionCount int) string {
|
||||
if sessionCount == 0 {
|
||||
return "Enabled"
|
||||
}
|
||||
sessionWord := "session"
|
||||
if sessionCount > 1 {
|
||||
sessionWord = "sessions"
|
||||
}
|
||||
return fmt.Sprintf("Enabled (%d active %s)", sessionCount, sessionWord)
|
||||
}
|
||||
|
||||
// versionSummary reports the platform this binary runs on, plus the daemon and
|
||||
// CLI versions to print.
|
||||
func (o *OutputOverview) versionSummary() (string, string, string) {
|
||||
goarch := runtime.GOARCH
|
||||
goarm := ""
|
||||
if goarch == "arm" {
|
||||
goarm = fmt.Sprintf(" (ARMv%s)", os.Getenv("GOARM"))
|
||||
}
|
||||
osString := fmt.Sprintf("%s/%s%s", runtime.GOOS, goarch, goarm)
|
||||
|
||||
daemonVersion := "N/A"
|
||||
if o.DaemonVersion != "" {
|
||||
daemonVersion = o.DaemonVersion
|
||||
}
|
||||
|
||||
cliVersion := version.NetbirdVersion()
|
||||
if o.CliVersion != "" {
|
||||
cliVersion = o.CliVersion
|
||||
}
|
||||
return osString, daemonVersion, cliVersion
|
||||
}
|
||||
|
||||
// FullDetailSummary returns a full detailed summary with peer details and events.
|
||||
func (o *OutputOverview) FullDetailSummary() string {
|
||||
parsedPeersString := parsePeers(o.Peers, o.RosenpassEnabled, o.RosenpassPermissive)
|
||||
@@ -1058,6 +1073,26 @@ func anonymizePeerDetail(a *anonymize.Anonymizer, peer *PeerStateDetailOutput) {
|
||||
}
|
||||
}
|
||||
|
||||
// formatSSHSessionLine renders a single SSH session row for the detailed
|
||||
// status output. A JWT-authenticated session names both the identity that
|
||||
// authenticated and the OS user it landed on; a key-authenticated one has only
|
||||
// the latter.
|
||||
func formatSSHSessionLine(session SSHSessionOutput) string {
|
||||
if session.JWTUsername != "" {
|
||||
return fmt.Sprintf("[%s@%s -> %s] %s",
|
||||
session.JWTUsername,
|
||||
session.RemoteAddress,
|
||||
session.Username,
|
||||
session.Command,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf("[%s@%s] %s",
|
||||
session.Username,
|
||||
session.RemoteAddress,
|
||||
session.Command,
|
||||
)
|
||||
}
|
||||
|
||||
// formatVNCSessionLine renders a single VNC session row for the detailed
|
||||
// status output. The leading slot identifies the initiator (display name
|
||||
// when known, hashed UserID otherwise); the post-arrow slot is the OS
|
||||
|
||||
@@ -294,3 +294,14 @@ func dialAgentWithRetry(ctx context.Context, addr string) (net.Conn, error) {
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
// retrackConn replaces a tracked raw connection with the wrapper its handler
|
||||
// will actually hold, so shutdown and the handler's own untrackConn agree on
|
||||
// which object is registered. Service mode only: that is where an accepted
|
||||
// connection is wrapped before the handler sees it.
|
||||
func (s *Server) retrackConn(raw, wrapped net.Conn) {
|
||||
s.sessionsMu.Lock()
|
||||
delete(s.acceptedConns, raw)
|
||||
s.acceptedConns[wrapped] = struct{}{}
|
||||
s.sessionsMu.Unlock()
|
||||
}
|
||||
|
||||
@@ -459,16 +459,6 @@ func (s *Server) trackConn(c net.Conn) {
|
||||
s.sessionsMu.Unlock()
|
||||
}
|
||||
|
||||
// retrackConn replaces a tracked raw connection with the wrapper its handler
|
||||
// will actually hold, so shutdown and the handler's own untrackConn agree on
|
||||
// which object is registered.
|
||||
func (s *Server) retrackConn(raw, wrapped net.Conn) {
|
||||
s.sessionsMu.Lock()
|
||||
delete(s.acceptedConns, raw)
|
||||
s.acceptedConns[wrapped] = struct{}{}
|
||||
s.sessionsMu.Unlock()
|
||||
}
|
||||
|
||||
// untrackConn forgets a connection once its handler is returning.
|
||||
func (s *Server) untrackConn(c net.Conn) {
|
||||
s.sessionsMu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user