[client] Add UI client event notifications (#3207)

This commit is contained in:
Viktor Liu
2025-02-20 11:00:02 +01:00
committed by GitHub
parent 87311074f1
commit 62a0c358f9
14 changed files with 1685 additions and 575 deletions

View File

@@ -39,7 +39,6 @@ type peerStateDetailOutput struct {
TransferSent int64 `json:"transferSent" yaml:"transferSent"`
Latency time.Duration `json:"latency" yaml:"latency"`
RosenpassEnabled bool `json:"quantumResistance" yaml:"quantumResistance"`
Routes []string `json:"routes" yaml:"routes"`
Networks []string `json:"networks" yaml:"networks"`
}
@@ -98,9 +97,9 @@ type statusOutputOverview struct {
FQDN string `json:"fqdn" yaml:"fqdn"`
RosenpassEnabled bool `json:"quantumResistance" yaml:"quantumResistance"`
RosenpassPermissive bool `json:"quantumResistancePermissive" yaml:"quantumResistancePermissive"`
Routes []string `json:"routes" yaml:"routes"`
Networks []string `json:"networks" yaml:"networks"`
NSServerGroups []nsServerGroupStateOutput `json:"dnsServers" yaml:"dnsServers"`
Events []systemEventOutput `json:"events" yaml:"events"`
}
var (
@@ -284,9 +283,9 @@ func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverv
FQDN: pbFullStatus.GetLocalPeerState().GetFqdn(),
RosenpassEnabled: pbFullStatus.GetLocalPeerState().GetRosenpassEnabled(),
RosenpassPermissive: pbFullStatus.GetLocalPeerState().GetRosenpassPermissive(),
Routes: pbFullStatus.GetLocalPeerState().GetNetworks(),
Networks: pbFullStatus.GetLocalPeerState().GetNetworks(),
NSServerGroups: mapNSGroups(pbFullStatus.GetDnsServers()),
Events: mapEvents(pbFullStatus.GetEvents()),
}
if anonymizeFlag {
@@ -393,7 +392,6 @@ func mapPeers(peers []*proto.PeerState) peersStateOutput {
TransferSent: transferSent,
Latency: pbPeerState.GetLatency().AsDuration(),
RosenpassEnabled: pbPeerState.GetRosenpassEnabled(),
Routes: pbPeerState.GetNetworks(),
Networks: pbPeerState.GetNetworks(),
}
@@ -559,7 +557,6 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool, showRelays
"NetBird IP: %s\n"+
"Interface type: %s\n"+
"Quantum resistance: %s\n"+
"Routes: %s\n"+
"Networks: %s\n"+
"Peers count: %s\n",
fmt.Sprintf("%s/%s%s", goos, goarch, goarm),
@@ -574,7 +571,6 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool, showRelays
interfaceTypeString,
rosenpassEnabledStatus,
networks,
networks,
peersCountString,
)
return summary
@@ -582,13 +578,17 @@ func parseGeneralSummary(overview statusOutputOverview, showURL bool, showRelays
func parseToFullDetailSummary(overview statusOutputOverview) string {
parsedPeersString := parsePeers(overview.Peers, overview.RosenpassEnabled, overview.RosenpassPermissive)
parsedEventsString := parseEvents(overview.Events)
summary := parseGeneralSummary(overview, true, true, true)
return fmt.Sprintf(
"Peers detail:"+
"%s\n"+
"Events:"+
"%s\n"+
"%s",
parsedPeersString,
parsedEventsString,
summary,
)
}
@@ -657,7 +657,6 @@ func parsePeers(peers peersStateOutput, rosenpassEnabled, rosenpassPermissive bo
" Last WireGuard handshake: %s\n"+
" Transfer status (received/sent) %s/%s\n"+
" Quantum resistance: %s\n"+
" Routes: %s\n"+
" Networks: %s\n"+
" Latency: %s\n",
peerState.FQDN,
@@ -676,7 +675,6 @@ func parsePeers(peers peersStateOutput, rosenpassEnabled, rosenpassPermissive bo
toIEC(peerState.TransferSent),
rosenpassEnabledStatus,
networks,
networks,
peerState.Latency.String(),
)
@@ -825,14 +823,6 @@ func anonymizePeerDetail(a *anonymize.Anonymizer, peer *peerStateDetailOutput) {
for i, route := range peer.Networks {
peer.Networks[i] = a.AnonymizeRoute(route)
}
for i, route := range peer.Routes {
peer.Routes[i] = a.AnonymizeIPString(route)
}
for i, route := range peer.Routes {
peer.Routes[i] = a.AnonymizeRoute(route)
}
}
func anonymizeOverview(a *anonymize.Anonymizer, overview *statusOutputOverview) {
@@ -870,9 +860,14 @@ func anonymizeOverview(a *anonymize.Anonymizer, overview *statusOutputOverview)
overview.Networks[i] = a.AnonymizeRoute(route)
}
for i, route := range overview.Routes {
overview.Routes[i] = a.AnonymizeRoute(route)
}
overview.FQDN = a.AnonymizeDomain(overview.FQDN)
for i, event := range overview.Events {
overview.Events[i].Message = a.AnonymizeString(event.Message)
overview.Events[i].UserMessage = a.AnonymizeString(event.UserMessage)
for k, v := range event.Metadata {
event.Metadata[k] = a.AnonymizeString(v)
}
}
}

View File

@@ -0,0 +1,69 @@
package cmd
import (
"fmt"
"sort"
"strings"
"time"
"github.com/netbirdio/netbird/client/proto"
)
type systemEventOutput struct {
ID string `json:"id" yaml:"id"`
Severity string `json:"severity" yaml:"severity"`
Category string `json:"category" yaml:"category"`
Message string `json:"message" yaml:"message"`
UserMessage string `json:"userMessage" yaml:"userMessage"`
Timestamp time.Time `json:"timestamp" yaml:"timestamp"`
Metadata map[string]string `json:"metadata" yaml:"metadata"`
}
func mapEvents(protoEvents []*proto.SystemEvent) []systemEventOutput {
events := make([]systemEventOutput, len(protoEvents))
for i, event := range protoEvents {
events[i] = systemEventOutput{
ID: event.GetId(),
Severity: event.GetSeverity().String(),
Category: event.GetCategory().String(),
Message: event.GetMessage(),
UserMessage: event.GetUserMessage(),
Timestamp: event.GetTimestamp().AsTime(),
Metadata: event.GetMetadata(),
}
}
return events
}
func parseEvents(events []systemEventOutput) string {
if len(events) == 0 {
return " No events recorded"
}
var eventsString strings.Builder
for _, event := range events {
timeStr := timeAgo(event.Timestamp)
metadataStr := ""
if len(event.Metadata) > 0 {
pairs := make([]string, 0, len(event.Metadata))
for k, v := range event.Metadata {
pairs = append(pairs, fmt.Sprintf("%s: %s", k, v))
}
sort.Strings(pairs)
metadataStr = fmt.Sprintf("\n Metadata: %s", strings.Join(pairs, ", "))
}
eventsString.WriteString(fmt.Sprintf("\n [%s] %s (%s)"+
"\n Message: %s"+
"\n Time: %s%s",
event.Severity,
event.Category,
event.ID,
event.Message,
timeStr,
metadataStr,
))
}
return eventsString.String()
}

View File

@@ -146,9 +146,6 @@ var overview = statusOutputOverview{
LastWireguardHandshake: time.Date(2001, 1, 1, 1, 1, 2, 0, time.UTC),
TransferReceived: 200,
TransferSent: 100,
Routes: []string{
"10.1.0.0/24",
},
Networks: []string{
"10.1.0.0/24",
},
@@ -176,6 +173,7 @@ var overview = statusOutputOverview{
},
},
},
Events: []systemEventOutput{},
CliVersion: version.NetbirdVersion(),
DaemonVersion: "0.14.1",
ManagementState: managementStateOutput{
@@ -230,9 +228,6 @@ var overview = statusOutputOverview{
Error: "timeout",
},
},
Routes: []string{
"10.10.0.0/24",
},
Networks: []string{
"10.10.0.0/24",
},
@@ -299,9 +294,6 @@ func TestParsingToJSON(t *testing.T) {
"transferSent": 100,
"latency": 10000000,
"quantumResistance": false,
"routes": [
"10.1.0.0/24"
],
"networks": [
"10.1.0.0/24"
]
@@ -327,7 +319,6 @@ func TestParsingToJSON(t *testing.T) {
"transferSent": 1000,
"latency": 10000000,
"quantumResistance": false,
"routes": null,
"networks": null
}
]
@@ -366,9 +357,6 @@ func TestParsingToJSON(t *testing.T) {
"fqdn": "some-localhost.awesome-domain.com",
"quantumResistance": false,
"quantumResistancePermissive": false,
"routes": [
"10.10.0.0/24"
],
"networks": [
"10.10.0.0/24"
],
@@ -393,7 +381,8 @@ func TestParsingToJSON(t *testing.T) {
"enabled": false,
"error": "timeout"
}
]
],
"events": []
}`
// @formatter:on
@@ -429,8 +418,6 @@ func TestParsingToYAML(t *testing.T) {
transferSent: 100
latency: 10ms
quantumResistance: false
routes:
- 10.1.0.0/24
networks:
- 10.1.0.0/24
- fqdn: peer-2.awesome-domain.com
@@ -451,7 +438,6 @@ func TestParsingToYAML(t *testing.T) {
transferSent: 1000
latency: 10ms
quantumResistance: false
routes: []
networks: []
cliVersion: development
daemonVersion: 0.14.1
@@ -479,8 +465,6 @@ usesKernelInterface: true
fqdn: some-localhost.awesome-domain.com
quantumResistance: false
quantumResistancePermissive: false
routes:
- 10.10.0.0/24
networks:
- 10.10.0.0/24
dnsServers:
@@ -497,6 +481,7 @@ dnsServers:
- example.net
enabled: false
error: timeout
events: []
`
assert.Equal(t, expectedYAML, yaml)
@@ -526,7 +511,6 @@ func TestParsingToDetail(t *testing.T) {
Last WireGuard handshake: %s
Transfer status (received/sent) 200 B/100 B
Quantum resistance: false
Routes: 10.1.0.0/24
Networks: 10.1.0.0/24
Latency: 10ms
@@ -543,10 +527,10 @@ func TestParsingToDetail(t *testing.T) {
Last WireGuard handshake: %s
Transfer status (received/sent) 2.0 KiB/1000 B
Quantum resistance: false
Routes: -
Networks: -
Latency: 10ms
Events: No events recorded
OS: %s/%s
Daemon version: 0.14.1
CLI version: %s
@@ -562,7 +546,6 @@ FQDN: some-localhost.awesome-domain.com
NetBird IP: 192.168.178.100/16
Interface type: Kernel
Quantum resistance: false
Routes: 10.10.0.0/24
Networks: 10.10.0.0/24
Peers count: 2/2 Connected
`, lastConnectionUpdate1, lastHandshake1, lastConnectionUpdate2, lastHandshake2, runtime.GOOS, runtime.GOARCH, overview.CliVersion)
@@ -584,7 +567,6 @@ FQDN: some-localhost.awesome-domain.com
NetBird IP: 192.168.178.100/16
Interface type: Kernel
Quantum resistance: false
Routes: 10.10.0.0/24
Networks: 10.10.0.0/24
Peers count: 2/2 Connected
`