mirror of
https://github.com/netbirdio/netbird.git
synced 2025-07-19 15:45:03 +02:00
With the lazy connection feature, the peer will connect to target peers on-demand. The trigger can be any IP traffic. This feature can be enabled with the NB_ENABLE_EXPERIMENTAL_LAZY_CONN environment variable. When the engine receives a network map, it binds a free UDP port for every remote peer, and the system configures WireGuard endpoints for these ports. When traffic appears on a UDP socket, the system removes this listener and starts the peer connection procedure immediately. Key changes Fix slow netbird status -d command Move from engine.go file to conn_mgr.go the peer connection related code Refactor the iface interface usage and moved interface file next to the engine code Add new command line flag and UI option to enable feature The peer.Conn struct is reusable after it has been closed. Change connection states Connection states Idle: The peer is not attempting to establish a connection. This typically means it's in a lazy state or the remote peer is expired. Connecting: The peer is actively trying to establish a connection. This occurs when the peer has entered an active state and is continuously attempting to reach the remote peer. Connected: A successful peer-to-peer connection has been established and communication is active.
172 lines
5.4 KiB
Go
172 lines
5.4 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/netbirdio/netbird/client/internal"
|
|
"github.com/netbirdio/netbird/client/proto"
|
|
nbstatus "github.com/netbirdio/netbird/client/status"
|
|
"github.com/netbirdio/netbird/util"
|
|
)
|
|
|
|
var (
|
|
detailFlag bool
|
|
ipv4Flag bool
|
|
jsonFlag bool
|
|
yamlFlag bool
|
|
ipsFilter []string
|
|
prefixNamesFilter []string
|
|
statusFilter string
|
|
ipsFilterMap map[string]struct{}
|
|
prefixNamesFilterMap map[string]struct{}
|
|
)
|
|
|
|
var statusCmd = &cobra.Command{
|
|
Use: "status",
|
|
Short: "status of the Netbird Service",
|
|
RunE: statusFunc,
|
|
}
|
|
|
|
func init() {
|
|
ipsFilterMap = make(map[string]struct{})
|
|
prefixNamesFilterMap = make(map[string]struct{})
|
|
statusCmd.PersistentFlags().BoolVarP(&detailFlag, "detail", "d", false, "display detailed status information in human-readable format")
|
|
statusCmd.PersistentFlags().BoolVar(&jsonFlag, "json", false, "display detailed status information in json format")
|
|
statusCmd.PersistentFlags().BoolVar(&yamlFlag, "yaml", false, "display detailed status information in yaml format")
|
|
statusCmd.PersistentFlags().BoolVar(&ipv4Flag, "ipv4", false, "display only NetBird IPv4 of this peer, e.g., --ipv4 will output 100.64.0.33")
|
|
statusCmd.MarkFlagsMutuallyExclusive("detail", "json", "yaml", "ipv4")
|
|
statusCmd.PersistentFlags().StringSliceVar(&ipsFilter, "filter-by-ips", []string{}, "filters the detailed output by a list of one or more IPs, e.g., --filter-by-ips 100.64.0.100,100.64.0.200")
|
|
statusCmd.PersistentFlags().StringSliceVar(&prefixNamesFilter, "filter-by-names", []string{}, "filters the detailed output by a list of one or more peer FQDN or hostnames, e.g., --filter-by-names peer-a,peer-b.netbird.cloud")
|
|
statusCmd.PersistentFlags().StringVar(&statusFilter, "filter-by-status", "", "filters the detailed output by connection status(idle|connecting|connected), e.g., --filter-by-status connected")
|
|
}
|
|
|
|
func statusFunc(cmd *cobra.Command, args []string) error {
|
|
SetFlagsFromEnvVars(rootCmd)
|
|
|
|
cmd.SetOut(cmd.OutOrStdout())
|
|
|
|
err := parseFilters()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = util.InitLog(logLevel, "console")
|
|
if err != nil {
|
|
return fmt.Errorf("failed initializing log %v", err)
|
|
}
|
|
|
|
ctx := internal.CtxInitState(cmd.Context())
|
|
|
|
resp, err := getStatus(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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 <YOUR_MANAGEMENT_URL> --setup-key <YOUR_SETUP_KEY>\n\n"+
|
|
"More info: https://docs.netbird.io/how-to/register-machines-using-setup-keys\n\n",
|
|
resp.GetStatus(),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
if ipv4Flag {
|
|
cmd.Print(parseInterfaceIP(resp.GetFullStatus().GetLocalPeerState().GetIP()))
|
|
return nil
|
|
}
|
|
|
|
var outputInformationHolder = nbstatus.ConvertToStatusOutputOverview(resp, anonymizeFlag, statusFilter, prefixNamesFilter, prefixNamesFilterMap, ipsFilterMap)
|
|
var statusOutputString string
|
|
switch {
|
|
case detailFlag:
|
|
statusOutputString = nbstatus.ParseToFullDetailSummary(outputInformationHolder)
|
|
case jsonFlag:
|
|
statusOutputString, err = nbstatus.ParseToJSON(outputInformationHolder)
|
|
case yamlFlag:
|
|
statusOutputString, err = nbstatus.ParseToYAML(outputInformationHolder)
|
|
default:
|
|
statusOutputString = nbstatus.ParseGeneralSummary(outputInformationHolder, false, false, false)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Print(statusOutputString)
|
|
|
|
return nil
|
|
}
|
|
|
|
func getStatus(ctx context.Context) (*proto.StatusResponse, error) {
|
|
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
|
if err != nil {
|
|
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)
|
|
}
|
|
defer conn.Close()
|
|
|
|
resp, err := proto.NewDaemonServiceClient(conn).Status(ctx, &proto.StatusRequest{GetFullPeerStatus: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("status failed: %v", status.Convert(err).Message())
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func parseFilters() error {
|
|
switch strings.ToLower(statusFilter) {
|
|
case "", "idle", "connecting", "connected":
|
|
if strings.ToLower(statusFilter) != "" {
|
|
enableDetailFlagWhenFilterFlag()
|
|
}
|
|
default:
|
|
return fmt.Errorf("wrong status filter, should be one of connected|connecting|idle, got: %s", statusFilter)
|
|
}
|
|
|
|
if len(ipsFilter) > 0 {
|
|
for _, addr := range ipsFilter {
|
|
_, err := netip.ParseAddr(addr)
|
|
if err != nil {
|
|
return fmt.Errorf("got an invalid IP address in the filter: address %s, error %s", addr, err)
|
|
}
|
|
ipsFilterMap[addr] = struct{}{}
|
|
enableDetailFlagWhenFilterFlag()
|
|
}
|
|
}
|
|
|
|
if len(prefixNamesFilter) > 0 {
|
|
for _, name := range prefixNamesFilter {
|
|
prefixNamesFilterMap[strings.ToLower(name)] = struct{}{}
|
|
}
|
|
enableDetailFlagWhenFilterFlag()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func enableDetailFlagWhenFilterFlag() {
|
|
if !detailFlag && !jsonFlag && !yamlFlag {
|
|
detailFlag = true
|
|
}
|
|
}
|
|
|
|
func parseInterfaceIP(interfaceIP string) string {
|
|
ip, _, err := net.ParseCIDR(interfaceIP)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("%s\n", ip)
|
|
}
|