diff --git a/client/cmd/status.go b/client/cmd/status.go index 78179c72b..3d7337eb8 100644 --- a/client/cmd/status.go +++ b/client/cmd/status.go @@ -4,22 +4,64 @@ import ( "context" "encoding/json" "fmt" - yaml2 "gopkg.in/yaml.v2" "net" "net/netip" "sort" "strings" + "time" + + "github.com/spf13/cobra" + "google.golang.org/grpc/status" + "gopkg.in/yaml.v2" "github.com/netbirdio/netbird/client/internal" "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/client/proto" - nbStatus "github.com/netbirdio/netbird/client/status" "github.com/netbirdio/netbird/client/system" "github.com/netbirdio/netbird/util" - "github.com/spf13/cobra" - "google.golang.org/grpc/status" ) +type peerStateDetailOutput struct { + IP string `json:"ip" yaml:"ip"` + PubKey string `json:"publicKey" yaml:"publicKey"` + FQDN string `json:"fqdn" yaml:"fqdn"` + ConnStatus string `json:"connectionStatus" yaml:"connectionStatus"` + ConnStatusUpdate time.Time `json:"connectionStatusUpdate" yaml:"connectionStatusUpdate"` + ConnType string `json:"connectionType" yaml:"connectionType"` + Direct bool `json:"direct" yaml:"direct"` + LocalIceCandidateType string `json:"localIceCandidateType" yaml:"localIceCandidateType"` + RemoteIceCandidateType string `json:"remoteIceCandidateType" yaml:"remoteIceCandidateType"` +} + +type peersStateOutput struct { + Total int `json:"total" yaml:"total"` + Connected int `json:"connected" yaml:"connected"` + Details []peerStateDetailOutput `json:"details" yaml:"details"` +} + +type signalStateOutput struct { + URL string `json:"url" yaml:"url"` + Connected bool `json:"connected" yaml:"connected"` +} + +type managementStateOutput struct { + URL string `json:"url" yaml:"url"` + Connected bool `json:"connected" yaml:"connected"` +} + +type statusOutputOverview struct { + Peers peersStateOutput `json:"peers" yaml:"peers"` + CliVersion string `json:"cliVersion" yaml:"cliVersion"` + DaemonVersion string `json:"daemonVersion" yaml:"daemonVersion"` + DaemonStatus string `json:"daemonStatus" yaml:"daemonStatus"` + ManagementState managementStateOutput `json:"management" yaml:"management"` + SignalState signalStateOutput `json:"signal" yaml:"signal"` + IP string `json:"ip" yaml:"ip"` + PubKey string `json:"publicKey" yaml:"publicKey"` + KernelInterface string `json:"interfaceType" yaml:"interfaceType"` + FQDN string `json:"domain" yaml:"domain"` +} + var ( detailFlag bool ipv4Flag bool @@ -64,9 +106,56 @@ func statusFunc(cmd *cobra.Command, args []string) error { ctx := internal.CtxInitState(context.Background()) + resp, _ := getStatus(ctx, cmd) + if err != nil { + return nil + } + + if resp.GetStatus() == string(internal.StatusNeedsLogin) || resp.GetStatus() == string(internal.StatusLoginFailed) { + cmd.Printf("Daemon status: %s\n\n"+ + "Run UP command to log in with SSO (interactive login):\n\n"+ + " netbird up \n\n"+ + "If you are running a self-hosted version and no SSO provider has been configured in your Management Server,\n"+ + "you can use a setup-key:\n\n netbird up --management-url --setup-key \n\n"+ + "More info: https://www.netbird.io/docs/overview/setup-keys\n\n", + resp.GetStatus(), + ) + return nil + } + + if ipv4Flag { + cmd.Print(parseInterfaceIP(resp.GetFullStatus().GetLocalPeerState().GetIP())) + return nil + } + + statusOutputOverview := convertToStatusOutputOverview(resp) + + statusOutputString := "" + if detailFlag { + statusOutputString = parseToFullDetailSummary(statusOutputOverview) + } else if jsonFlag { + statusOutputString, err = parseToJson(statusOutputOverview) + if err != nil { + return err + } + } else if yamlFlag { + statusOutputString, err = parseToYaml(statusOutputOverview) + if err != nil { + return err + } + } else { + statusOutputString = parseGeneralSummary(statusOutputOverview, false) + } + + cmd.Print(statusOutputString) + + return nil +} + +func getStatus(ctx context.Context, cmd *cobra.Command) (*proto.StatusResponse, error) { conn, err := DialClientGRPCServer(ctx, daemonAddr) if err != nil { - return fmt.Errorf("failed to connect to daemon error: %v\n"+ + return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+ "If the daemon is not running please run: "+ "\nnetbird service install \nnetbird service start\n", err) } @@ -74,49 +163,10 @@ func statusFunc(cmd *cobra.Command, args []string) error { resp, err := proto.NewDaemonServiceClient(conn).Status(cmd.Context(), &proto.StatusRequest{GetFullPeerStatus: true}) if err != nil { - return fmt.Errorf("status failed: %v", status.Convert(err).Message()) + return nil, fmt.Errorf("status failed: %v", status.Convert(err).Message()) } - daemonStatus := fmt.Sprintf("Daemon status: %s\n", resp.GetStatus()) - if resp.GetStatus() == string(internal.StatusNeedsLogin) || resp.GetStatus() == string(internal.StatusLoginFailed) { - - cmd.Printf("%s\n"+ - "Run UP command to log in with SSO (interactive login):\n\n"+ - " netbird up \n\n"+ - "If you are running a self-hosted version and no SSO provider has been configured in your Management Server,\n"+ - "you can use a setup-key:\n\n netbird up --management-url --setup-key \n\n"+ - "More info: https://www.netbird.io/docs/overview/setup-keys\n\n", - daemonStatus, - ) - return nil - } - - pbFullStatus := resp.GetFullStatus() - fullStatus := fromProtoFullStatus(pbFullStatus) - - statusOutputString := "" - if detailFlag { - statusOutputString = parseToHumanReadable(fullStatus, daemonStatus, resp.GetDaemonVersion()) - } - if jsonFlag { - statusOutputString, err = parseToJson(fullStatus) - if err != nil { - return fmt.Errorf("json marshal failed") - } - } - if yamlFlag { - statusOutputString, err = parseToYaml(fullStatus) - if err != nil { - return fmt.Errorf("yaml marshal failed") - } - } - if ipv4Flag { - statusOutputString = parseInterfaceIP(fullStatus.LocalPeerState.IP) - } - - cmd.Print(statusOutputString) - - return nil + return resp, nil } func parseFilters() error { @@ -138,43 +188,104 @@ func parseFilters() error { return nil } -func fromProtoFullStatus(pbFullStatus *proto.FullStatus) nbStatus.FullStatus { - var fullStatus nbStatus.FullStatus +func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverview { + pbFullStatus := resp.GetFullStatus() + managementState := pbFullStatus.GetManagementState() - fullStatus.ManagementState.URL = managementState.GetURL() - fullStatus.ManagementState.Connected = managementState.GetConnected() + managementOverview := managementStateOutput{ + URL: managementState.GetURL(), + Connected: managementState.GetConnected(), + } signalState := pbFullStatus.GetSignalState() - fullStatus.SignalState.URL = signalState.GetURL() - fullStatus.SignalState.Connected = signalState.GetConnected() + signalOverview := signalStateOutput{ + URL: signalState.GetURL(), + Connected: signalState.GetConnected(), + } - localPeerState := pbFullStatus.GetLocalPeerState() - fullStatus.LocalPeerState.IP = localPeerState.GetIP() - fullStatus.LocalPeerState.PubKey = localPeerState.GetPubKey() - fullStatus.LocalPeerState.KernelInterface = localPeerState.GetKernelInterface() - fullStatus.LocalPeerState.FQDN = localPeerState.GetFqdn() + peersOverview := mapPeers(resp.GetFullStatus().GetPeers()) - var peersState []nbStatus.PeerState + interfaceTypeString := "Userspace" + interfaceIP := pbFullStatus.GetLocalPeerState().GetIP() + if pbFullStatus.LocalPeerState.KernelInterface { + interfaceTypeString = "Kernel" + } else if pbFullStatus.LocalPeerState.IP == "" { + interfaceTypeString = "N/A" + interfaceIP = "N/A" + } + + overview := statusOutputOverview{ + Peers: peersOverview, + CliVersion: system.NetbirdVersion(), + DaemonVersion: resp.GetDaemonVersion(), + DaemonStatus: resp.GetStatus(), + ManagementState: managementOverview, + SignalState: signalOverview, + IP: interfaceIP, + PubKey: pbFullStatus.GetLocalPeerState().GetPubKey(), + KernelInterface: interfaceTypeString, + FQDN: pbFullStatus.GetLocalPeerState().GetFqdn(), + } + + return overview +} + +func mapPeers(peers []*proto.PeerState) peersStateOutput { + var peersStateDetail []peerStateDetailOutput + localICE := "-" + remoteICE := "-" + connType := "-" + peersConnected := 0 + for _, pbPeerState := range peers { + isPeerConnected := pbPeerState.ConnStatus == peer.StatusConnected.String() + if skipDetailByFilters(pbPeerState, isPeerConnected) { + continue + } + if isPeerConnected { + peersConnected = peersConnected + 1 + + localICE = pbPeerState.GetLocalIceCandidateType() + remoteICE = pbPeerState.GetRemoteIceCandidateType() + connType = "P2P" + if pbPeerState.Relayed { + connType = "Relayed" + } + } - for _, pbPeerState := range pbFullStatus.GetPeers() { timeLocal := pbPeerState.GetConnStatusUpdate().AsTime().Local() - peerState := nbStatus.PeerState{ + peerState := peerStateDetailOutput{ IP: pbPeerState.GetIP(), PubKey: pbPeerState.GetPubKey(), ConnStatus: pbPeerState.GetConnStatus(), - ConnStatusUpdate: timeLocal, - Relayed: pbPeerState.GetRelayed(), + ConnStatusUpdate: timeLocal.UTC(), + ConnType: connType, Direct: pbPeerState.GetDirect(), - LocalIceCandidateType: pbPeerState.GetLocalIceCandidateType(), - RemoteIceCandidateType: pbPeerState.GetRemoteIceCandidateType(), + LocalIceCandidateType: localICE, + RemoteIceCandidateType: remoteICE, FQDN: pbPeerState.GetFqdn(), } - peersState = append(peersState, peerState) + + peersStateDetail = append(peersStateDetail, peerState) } - fullStatus.Peers = peersState + sortPeersByIp(peersStateDetail) - return fullStatus + peersOverview := peersStateOutput{ + Total: len(peersStateDetail), + Connected: peersConnected, + Details: peersStateDetail, + } + return peersOverview +} + +func sortPeersByIp(peersStateDetail []peerStateDetailOutput) { + if len(peersStateDetail) > 0 { + sort.SliceStable(peersStateDetail, func(i, j int) bool { + iAddr, _ := netip.ParseAddr(peersStateDetail[i].IP) + jAddr, _ := netip.ParseAddr(peersStateDetail[j].IP) + return iAddr.Compare(jAddr) == -1 + }) + } } func parseInterfaceIP(interfaceIP string) string { @@ -185,81 +296,68 @@ func parseInterfaceIP(interfaceIP string) string { return fmt.Sprintf("%s\n", ip) } -func parseToJson(fullStatus nbStatus.FullStatus) (string, error) { - jsonBytes, err := json.Marshal(fullStatus) +func parseToJson(overview statusOutputOverview) (string, error) { + jsonBytes, err := json.Marshal(overview) + if err != nil { + return "", fmt.Errorf("json marshal failed") + } return string(jsonBytes), err } -func parseToYaml(fullStatus nbStatus.FullStatus) (string, error) { - yamlBytes, err := yaml2.Marshal(fullStatus) - return string(yamlBytes), err -} - -func countConnectedPeers(peers []nbStatus.PeerState) int { - peersConnected := 0 - for _, peerState := range peers { - if peerState.ConnStatus == peer.StatusConnected.String() { - peersConnected = peersConnected + 1 - } +func parseToYaml(overview statusOutputOverview) (string, error) { + yamlBytes, err := yaml.Marshal(overview) + if err != nil { + return "", fmt.Errorf("yaml marshal failed") } - return peersConnected + return string(yamlBytes), nil } -func parseGeneralSummary(fullStatus nbStatus.FullStatus, daemonStatus string, daemonVersion string) string { - - managementStatusURL := fmt.Sprintf(" to %s", fullStatus.ManagementState.URL) - signalStatusURL := fmt.Sprintf(" to %s", fullStatus.SignalState.URL) +func parseGeneralSummary(overview statusOutputOverview, showUrl bool) string { managementConnString := "Disconnected" - if fullStatus.ManagementState.Connected { + if overview.ManagementState.Connected { managementConnString = "Connected" + if showUrl { + managementConnString = fmt.Sprintf("%s to %s", managementConnString, overview.ManagementState.URL) + } } signalConnString := "Disconnected" - if fullStatus.SignalState.Connected { + if overview.SignalState.Connected { signalConnString = "Connected" + if showUrl { + signalConnString = fmt.Sprintf("%s to %s", signalConnString, overview.SignalState.URL) + } } - interfaceTypeString := "Userspace" - interfaceIP := "" - if fullStatus.LocalPeerState.KernelInterface { - interfaceTypeString = "Kernel" - } else if fullStatus.LocalPeerState.IP == "" { - interfaceTypeString = "N/A" - interfaceIP = "N/A" - } - - peersConnected := countConnectedPeers(fullStatus.Peers) - peersCountString := fmt.Sprintf("%d/%d Connected", peersConnected, len(fullStatus.Peers)) + peersCountString := fmt.Sprintf("%d/%d Connected", overview.Peers.Connected, overview.Peers.Total) summary := fmt.Sprintf( "Daemon version: %s\n"+ "CLI version: %s\n"+ "%s"+ // daemon status - "Management: %s%s\n"+ - "Signal: %s%s\n"+ + "Management: %s\n"+ + "Signal: %s\n"+ "Domain: %s\n"+ "NetBird IP: %s\n"+ "Interface type: %s\n"+ "Peers count: %s\n", - daemonVersion, + overview.DaemonVersion, system.NetbirdVersion(), - daemonStatus, + overview.DaemonStatus, managementConnString, - managementStatusURL, signalConnString, - signalStatusURL, - fullStatus.LocalPeerState.FQDN, - interfaceIP, - interfaceTypeString, + overview.FQDN, + overview.IP, + overview.KernelInterface, peersCountString, ) return summary } -func parseToHumanReadable(fullStatus nbStatus.FullStatus, daemonStatus string, daemonVersion string) string { - parsedPeersString := parsePeers(fullStatus.Peers) - summary := parseGeneralSummary(fullStatus, daemonStatus, daemonVersion) +func parseToFullDetailSummary(overview statusOutputOverview) string { + parsedPeersString := parsePeers(overview.Peers) + summary := parseGeneralSummary(overview, true) return fmt.Sprintf( "Peers detail:"+ @@ -270,38 +368,12 @@ func parseToHumanReadable(fullStatus nbStatus.FullStatus, daemonStatus string, d ) } -func parsePeers(peers []nbStatus.PeerState) string { +func parsePeers(peers peersStateOutput) string { var ( peersString = "" ) - if len(peers) > 0 { - sort.SliceStable(peers, func(i, j int) bool { - iAddr, _ := netip.ParseAddr(peers[i].IP) - jAddr, _ := netip.ParseAddr(peers[j].IP) - return iAddr.Compare(jAddr) == -1 - }) - } - - for _, peerState := range peers { - peerConnectionStatus := peerState.ConnStatus == peer.StatusConnected.String() - if skipDetailByFilters(peerState, peerConnectionStatus) { - continue - } - - localICE := "-" - remoteICE := "-" - connType := "-" - - if peerConnectionStatus { - localICE = peerState.LocalIceCandidateType - remoteICE = peerState.RemoteIceCandidateType - connType = "P2P" - if peerState.Relayed { - connType = "Relayed" - } - } - + for _, peerState := range peers.Details { peerString := fmt.Sprintf( "\n %s:\n"+ " NetBird IP: %s\n"+ @@ -316,10 +388,10 @@ func parsePeers(peers []nbStatus.PeerState) string { peerState.IP, peerState.PubKey, peerState.ConnStatus, - connType, + peerState.ConnType, peerState.Direct, - localICE, - remoteICE, + peerState.LocalIceCandidateType, + peerState.RemoteIceCandidateType, peerState.ConnStatusUpdate.Format("2006-01-02 15:04:05"), ) @@ -328,7 +400,7 @@ func parsePeers(peers []nbStatus.PeerState) string { return peersString } -func skipDetailByFilters(peerState nbStatus.PeerState, isConnected bool) bool { +func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool { statusEval := false ipEval := false diff --git a/client/cmd/status_test.go b/client/cmd/status_test.go index ea94282c0..bc55c0e85 100644 --- a/client/cmd/status_test.go +++ b/client/cmd/status_test.go @@ -1,134 +1,292 @@ package cmd import ( - nbStatus "github.com/netbirdio/netbird/client/status" - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/netbirdio/netbird/client/proto" + "github.com/netbirdio/netbird/client/system" ) -var fullStatus = nbStatus.FullStatus{ - Peers: []nbStatus.PeerState{ - { - IP: "192.168.178.101", - PubKey: "Pubkey1", - FQDN: "peer-1.awesome-domain.com", - ConnStatus: "Connected", - ConnStatusUpdate: time.Date(2001, time.Month(1), 1, 1, 1, 1, 0, time.UTC), - Relayed: false, - LocalIceCandidateType: "-", - RemoteIceCandidateType: "-", +var resp = &proto.StatusResponse{ + Status: "Connected", + FullStatus: &proto.FullStatus{ + Peers: []*proto.PeerState{ + { + IP: "192.168.178.101", + PubKey: "Pubkey1", + Fqdn: "peer-1.awesome-domain.com", + ConnStatus: "Connected", + ConnStatusUpdate: timestamppb.New(time.Date(2001, time.Month(1), 1, 1, 1, 1, 0, time.UTC)), + Relayed: false, + Direct: true, + LocalIceCandidateType: "-", + RemoteIceCandidateType: "-", + }, + { + IP: "192.168.178.102", + PubKey: "Pubkey2", + Fqdn: "peer-2.awesome-domain.com", + ConnStatus: "Connected", + ConnStatusUpdate: timestamppb.New(time.Date(2002, time.Month(2), 2, 2, 2, 2, 0, time.UTC)), + Relayed: true, + Direct: false, + LocalIceCandidateType: "-", + RemoteIceCandidateType: "-", + }, }, - { - IP: "192.168.178.102", - PubKey: "Pubkey2", - FQDN: "peer-2.awesome-domain.com", - ConnStatus: "Connected", - ConnStatusUpdate: time.Date(2002, time.Month(2), 2, 2, 2, 2, 0, time.UTC), - Relayed: false, - LocalIceCandidateType: "-", - RemoteIceCandidateType: "-", + ManagementState: &proto.ManagementState{ + URL: "my-awesome-management.com:443", + Connected: true, + }, + SignalState: &proto.SignalState{ + URL: "my-awesome-signal.com:443", + Connected: true, + }, + LocalPeerState: &proto.LocalPeerState{ + IP: "192.168.178.100/16", + PubKey: "Some-Pub-Key", + KernelInterface: true, + Fqdn: "some-localhost.awesome-domain.com", }, }, - ManagementState: nbStatus.ManagementState{ + DaemonVersion: "0.14.1", +} + +var overview = statusOutputOverview{ + Peers: peersStateOutput{ + Total: 2, + Connected: 2, + Details: []peerStateDetailOutput{ + { + IP: "192.168.178.101", + PubKey: "Pubkey1", + FQDN: "peer-1.awesome-domain.com", + ConnStatus: "Connected", + ConnStatusUpdate: time.Date(2001, 1, 1, 1, 1, 1, 0, time.UTC), + ConnType: "P2P", + Direct: true, + LocalIceCandidateType: "-", + RemoteIceCandidateType: "-", + }, + { + IP: "192.168.178.102", + PubKey: "Pubkey2", + FQDN: "peer-2.awesome-domain.com", + ConnStatus: "Connected", + ConnStatusUpdate: time.Date(2002, 2, 2, 2, 2, 2, 0, time.UTC), + ConnType: "Relayed", + Direct: false, + LocalIceCandidateType: "-", + RemoteIceCandidateType: "-", + }, + }, + }, + CliVersion: system.NetbirdVersion(), + DaemonVersion: "0.14.1", + DaemonStatus: "Connected", + ManagementState: managementStateOutput{ URL: "my-awesome-management.com:443", Connected: true, }, - SignalState: nbStatus.SignalState{ + SignalState: signalStateOutput{ URL: "my-awesome-signal.com:443", Connected: true, }, - LocalPeerState: nbStatus.LocalPeerState{ - IP: "192.168.178.2", - PubKey: "Some-Pub-Key", - KernelInterface: false, - FQDN: "some-localhost.awesome-domain.com", - }, + IP: "192.168.178.100/16", + PubKey: "Some-Pub-Key", + KernelInterface: "Kernel", + FQDN: "some-localhost.awesome-domain.com", } -// @formatter:off -func TestParsingToJson(t *testing.T) { - json, _ := parseToJson(fullStatus) +func TestConversionFromFullStatusToOutputOverview(t *testing.T) { + convertedResult := convertToStatusOutputOverview(resp) + assert.Equal(t, overview, convertedResult) +} + +func TestSortingOfPeers(t *testing.T) { + peers := []peerStateDetailOutput{ + { + IP: "192.168.178.104", + }, + { + IP: "192.168.178.102", + }, + { + IP: "192.168.178.101", + }, + { + IP: "192.168.178.105", + }, + { + IP: "192.168.178.103", + }, + } + + sortPeersByIp(peers) + + assert.Equal(t, peers[3].IP, "192.168.178.104") +} + +func TestParsingToJson(t *testing.T) { + json, _ := parseToJson(overview) + + // @formatter:off expectedJson := "{" + - "\"Peers\":" + + "\"peers\":" + + "{" + + "\"total\":2," + + "\"connected\":2," + + "\"details\":" + "[" + "{" + - "\"IP\":\"192.168.178.101\"," + - "\"PubKey\":\"Pubkey1\"," + - "\"FQDN\":\"peer-1.awesome-domain.com\"," + - "\"ConnStatus\":\"Connected\"," + - "\"ConnStatusUpdate\":\"2001-01-01T01:01:01Z\"," + - "\"Relayed\":false," + - "\"Direct\":false," + - "\"LocalIceCandidateType\":\"-\"," + - "\"RemoteIceCandidateType\":\"-\"" + + "\"ip\":\"192.168.178.101\"," + + "\"publicKey\":\"Pubkey1\"," + + "\"fqdn\":\"peer-1.awesome-domain.com\"," + + "\"connectionStatus\":\"Connected\"" + + ",\"connectionStatusUpdate\":\"2001-01-01T01:01:01Z\"," + + "\"connectionType\":\"P2P\"," + + "\"direct\":true," + + "\"localIceCandidateType\":\"-\"," + + "\"remoteIceCandidateType\":\"-\"" + "}," + "{" + - "\"IP\":\"192.168.178.102\"," + - "\"PubKey\":\"Pubkey2\"," + - "\"FQDN\":\"peer-2.awesome-domain.com\"," + - "\"ConnStatus\":\"Connected\"," + - "\"ConnStatusUpdate\":\"2002-02-02T02:02:02Z\"," + - "\"Relayed\":false," + - "\"Direct\":false," + - "\"LocalIceCandidateType\":\"-\"," + - "\"RemoteIceCandidateType\":\"-\"" + + "\"ip\":\"192.168.178.102\"," + + "\"publicKey\":\"Pubkey2\"," + + "\"fqdn\":\"peer-2.awesome-domain.com\"," + + "\"connectionStatus\":\"Connected\"," + + "\"connectionStatusUpdate\":\"2002-02-02T02:02:02Z\"," + + "\"connectionType\":\"Relayed\"," + + "\"direct\":false," + + "\"localIceCandidateType\":\"-\"," + + "\"remoteIceCandidateType\":\"-\"" + "}" + - "]," + - "\"ManagementState\":" + - "{" + - "\"URL\":\"my-awesome-management.com:443\"," + - "\"Connected\":true" + + "]" + "}," + - "\"SignalState\":" + + "\"cliVersion\":\"development\"," + + "\"daemonVersion\":\"0.14.1\"," + + "\"daemonStatus\":\"Connected\"," + + "\"management\":" + "{" + - "\"URL\":\"my-awesome-signal.com:443\"," + - "\"Connected\":true" + + "\"url\":\"my-awesome-management.com:443\"," + + "\"connected\":true" + "}," + - "\"LocalPeerState\":" + + "\"signal\":" + "{" + - "\"IP\":\"192.168.178.2\"," + - "\"PubKey\":\"Some-Pub-Key\"," + - "\"KernelInterface\":false," + - "\"FQDN\":\"some-localhost.awesome-domain.com\"" + - "}" + + "\"url\":\"my-awesome-signal.com:443\"," + + "\"connected\":true" + + "}," + + "\"ip\":\"192.168.178.100/16\"," + + "\"publicKey\":\"Some-Pub-Key\"," + + "\"interfaceType\":\"Kernel\"," + + "\"domain\":\"some-localhost.awesome-domain.com\"" + "}" + // @formatter:on + assert.Equal(t, expectedJson, json) } func TestParsingToYaml(t *testing.T) { - yaml, _ := parseToYaml(fullStatus) + yaml, _ := parseToYaml(overview) expectedYaml := "peers:\n" + - "- ip: 192.168.178.101\n" + - " pubkey: Pubkey1\n" + - " fqdn: peer-1.awesome-domain.com\n" + - " connstatus: Connected\n" + - " connstatusupdate: 2001-01-01T01:01:01Z\n" + - " relayed: false\n" + - " direct: false\n" + - " localicecandidatetype: '-'\n" + - " remoteicecandidatetype: '-'\n" + - "- ip: 192.168.178.102\n" + - " pubkey: Pubkey2\n" + - " fqdn: peer-2.awesome-domain.com\n" + - " connstatus: Connected\n" + - " connstatusupdate: 2002-02-02T02:02:02Z\n" + - " relayed: false\n" + - " direct: false\n" + - " localicecandidatetype: '-'\n" + - " remoteicecandidatetype: '-'\n" + - "managementstate:\n" + + " total: 2\n" + + " connected: 2\n" + + " details:\n" + + " - ip: 192.168.178.101\n" + + " publicKey: Pubkey1\n" + + " fqdn: peer-1.awesome-domain.com\n" + + " connectionStatus: Connected\n" + + " connectionStatusUpdate: 2001-01-01T01:01:01Z\n" + + " connectionType: P2P\n" + + " direct: true\n" + + " localIceCandidateType: '-'\n" + + " remoteIceCandidateType: '-'\n" + + " - ip: 192.168.178.102\n" + + " publicKey: Pubkey2\n" + + " fqdn: peer-2.awesome-domain.com\n" + + " connectionStatus: Connected\n" + + " connectionStatusUpdate: 2002-02-02T02:02:02Z\n" + + " connectionType: Relayed\n" + + " direct: false\n" + + " localIceCandidateType: '-'\n" + + " remoteIceCandidateType: '-'\n" + + "cliVersion: development\n" + + "daemonVersion: 0.14.1\n" + + "daemonStatus: Connected\n" + + "management:\n" + " url: my-awesome-management.com:443\n" + " connected: true\n" + - "signalstate:\n" + + "signal:\n" + " url: my-awesome-signal.com:443\n" + " connected: true\n" + - "localpeerstate:\n" + - " ip: 192.168.178.2\n" + - " pubkey: Some-Pub-Key\n" + - " kernelinterface: false\n" + - " fqdn: some-localhost.awesome-domain.com\n" + "ip: 192.168.178.100/16\n" + + "publicKey: Some-Pub-Key\n" + + "interfaceType: Kernel\n" + + "domain: some-localhost.awesome-domain.com\n" + assert.Equal(t, expectedYaml, yaml) } + +func TestParsingToDetail(t *testing.T) { + detail := parseToFullDetailSummary(overview) + + expectedDetail := "Peers detail:\n" + + " peer-1.awesome-domain.com:\n" + + " NetBird IP: 192.168.178.101\n" + + " Public key: Pubkey1\n" + + " Status: Connected\n" + + " -- detail --\n" + + " Connection type: P2P\n" + + " Direct: true\n" + + " ICE candidate (Local/Remote): -/-\n" + + " Last connection update: 2001-01-01 01:01:01\n" + + "\n" + + " peer-2.awesome-domain.com:\n" + + " NetBird IP: 192.168.178.102\n" + + " Public key: Pubkey2\n" + + " Status: Connected\n" + + " -- detail --\n" + + " Connection type: Relayed\n" + + " Direct: false\n" + + " ICE candidate (Local/Remote): -/-\n" + + " Last connection update: 2002-02-02 02:02:02\n" + + "\n" + + "Daemon version: 0.14.1\n" + + "CLI version: development\n" + + "ConnectedManagement: Connected to my-awesome-management.com:443\n" + + "Signal: Connected to my-awesome-signal.com:443\n" + + "Domain: some-localhost.awesome-domain.com\n" + + "NetBird IP: 192.168.178.100/16\n" + + "Interface type: Kernel\n" + + "Peers count: 2/2 Connected\n" + + assert.Equal(t, expectedDetail, detail) +} + +func TestParsingToShortVersion(t *testing.T) { + shortVersion := parseGeneralSummary(overview, false) + + expectedString := "Daemon version: 0.14.1\n" + + "CLI version: development\n" + + "ConnectedManagement: Connected\n" + + "Signal: Connected\n" + + "Domain: some-localhost.awesome-domain.com\n" + + "NetBird IP: 192.168.178.100/16\n" + + "Interface type: Kernel\n" + + "Peers count: 2/2 Connected\n" + + assert.Equal(t, expectedString, shortVersion) +} + +func TestParsingOfIp(t *testing.T) { + InterfaceIp := "192.168.178.123/16" + + parsedId := parseInterfaceIP(InterfaceIp) + + assert.Equal(t, "192.168.178.123\n", parsedId) +}