package cmd import ( "fmt" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "google.golang.org/grpc/status" "github.com/netbirdio/netbird/client/proto" ) var ( allFlag bool ) var stateCmd = &cobra.Command{ Use: "state", Short: "Manage daemon state", Long: "Provides commands for managing and inspecting the Netbird daemon state.", } var stateListCmd = &cobra.Command{ Use: "list", Aliases: []string{"ls"}, Short: "List all stored states", Long: "Lists all registered states with their status and basic information.", Example: " netbird state list", RunE: stateList, } var stateCleanCmd = &cobra.Command{ Use: "clean [state-name]", Short: "Clean stored states", Long: `Clean specific state or all states. The daemon must not be running. This will perform cleanup operations and remove the state.`, Example: ` netbird state clean dns_state netbird state clean --all`, RunE: stateClean, PreRunE: func(cmd *cobra.Command, args []string) error { // Check mutual exclusivity between --all flag and state-name argument if allFlag && len(args) > 0 { return fmt.Errorf("cannot specify both --all flag and state name") } if !allFlag && len(args) != 1 { return fmt.Errorf("requires a state name argument or --all flag") } return nil }, } var stateDeleteCmd = &cobra.Command{ Use: "delete [state-name]", Short: "Delete stored states", Long: `Delete specific state or all states from storage. The daemon must not be running. This will remove the state without performing any cleanup operations.`, Example: ` netbird state delete dns_state netbird state delete --all`, RunE: stateDelete, PreRunE: func(cmd *cobra.Command, args []string) error { // Check mutual exclusivity between --all flag and state-name argument if allFlag && len(args) > 0 { return fmt.Errorf("cannot specify both --all flag and state name") } if !allFlag && len(args) != 1 { return fmt.Errorf("requires a state name argument or --all flag") } return nil }, } func init() { rootCmd.AddCommand(stateCmd) stateCmd.AddCommand(stateListCmd, stateCleanCmd, stateDeleteCmd) stateCleanCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Clean all states") stateDeleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete all states") } func stateList(cmd *cobra.Command, _ []string) error { conn, err := getClient(cmd) if err != nil { return err } defer func() { if err := conn.Close(); err != nil { log.Errorf(errCloseConnection, err) } }() client := proto.NewDaemonServiceClient(conn) resp, err := client.ListStates(cmd.Context(), &proto.ListStatesRequest{}) if err != nil { return fmt.Errorf("failed to list states: %v", status.Convert(err).Message()) } cmd.Printf("\nStored states:\n\n") for _, state := range resp.States { cmd.Printf("- %s\n", state.Name) } return nil } func stateClean(cmd *cobra.Command, args []string) error { var stateName string if !allFlag { stateName = args[0] } conn, err := getClient(cmd) if err != nil { return err } defer func() { if err := conn.Close(); err != nil { log.Errorf(errCloseConnection, err) } }() client := proto.NewDaemonServiceClient(conn) resp, err := client.CleanState(cmd.Context(), &proto.CleanStateRequest{ StateName: stateName, All: allFlag, }) if err != nil { return fmt.Errorf("failed to clean state: %v", status.Convert(err).Message()) } if resp.CleanedStates == 0 { cmd.Println("No states were cleaned") return nil } if allFlag { cmd.Printf("Successfully cleaned %d states\n", resp.CleanedStates) } else { cmd.Printf("Successfully cleaned state %q\n", stateName) } return nil } func stateDelete(cmd *cobra.Command, args []string) error { var stateName string if !allFlag { stateName = args[0] } conn, err := getClient(cmd) if err != nil { return err } defer func() { if err := conn.Close(); err != nil { log.Errorf(errCloseConnection, err) } }() client := proto.NewDaemonServiceClient(conn) resp, err := client.DeleteState(cmd.Context(), &proto.DeleteStateRequest{ StateName: stateName, All: allFlag, }) if err != nil { return fmt.Errorf("failed to delete state: %v", status.Convert(err).Message()) } if resp.DeletedStates == 0 { cmd.Println("No states were deleted") return nil } if allFlag { cmd.Printf("Successfully deleted %d states\n", resp.DeletedStates) } else { cmd.Printf("Successfully deleted state %q\n", stateName) } return nil }