Skip to content

Commit

Permalink
Node local status more info (#2288)
Browse files Browse the repository at this point in the history
* wip

* added blockchain status support
fix typos

* address raymond feedback

* improve ux

* Your blockchain
  • Loading branch information
arturrez authored Oct 30, 2024
1 parent fb10008 commit d6c5705
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.lcov

# ignore GoLand metafiles directory
.idea/
Expand Down
2 changes: 1 addition & 1 deletion cmd/blockchaincmd/prompt_owners.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func promptOwners(
return nil, 0, fmt.Errorf("user cancelled operation")
}
}
ux.Logger.PrintToUser("Your Subnet's control keys: %s", controlKeys)
ux.Logger.PrintToUser("Your blockchain control keys: %s", controlKeys)
// validate and prompt for threshold
if threshold == 0 && subnetAuthKeys != nil {
threshold = uint32(len(subnetAuthKeys))
Expand Down
13 changes: 11 additions & 2 deletions cmd/nodecmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package nodecmd

import (
"fmt"
"os"

"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
Expand Down Expand Up @@ -119,13 +120,18 @@ func newLocalDestroyCmd() *cobra.Command {
}

func newLocalStatusCmd() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "status",
Short: "(ALPHA Warning) Get status of local node",
Long: `Get status of local node.`,
Args: cobra.MaximumNArgs(1),
RunE: localStatus,
}

cmd.Flags().StringVar(&blockchainName, "subnet", "", "specify the blockchain the node is syncing with")
cmd.Flags().StringVar(&blockchainName, "blockchain", "", "specify the blockchain the node is syncing with")

return cmd
}

func localStartNode(_ *cobra.Command, args []string) error {
Expand Down Expand Up @@ -185,7 +191,10 @@ func localStatus(_ *cobra.Command, args []string) error {
if len(args) > 0 {
clusterName = args[0]
}
return node.LocalStatus(app, clusterName)
if blockchainName != "" && clusterName == "" {
return fmt.Errorf("--blockchain flag is only supported if clusterName is specified")
}
return node.LocalStatus(app, clusterName, blockchainName)
}

func notImplementedForLocal(what string) error {
Expand Down
96 changes: 93 additions & 3 deletions pkg/node/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
package node

import (
"encoding/hex"
"fmt"
"os"
"path/filepath"
"slices"
"strings"

"github.com/ava-labs/avalanche-cli/pkg/application"
"github.com/ava-labs/avalanche-cli/pkg/binutils"
Expand All @@ -20,9 +22,12 @@ import (
"github.com/ava-labs/avalanche-cli/pkg/ux"
"github.com/ava-labs/avalanche-network-runner/client"
anrutils "github.com/ava-labs/avalanche-network-runner/utils"
"github.com/ava-labs/avalanchego/api/info"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm"
"github.com/ava-labs/avalanchego/vms/platformvm/signer"
)

func TrackSubnetWithLocalMachine(
Expand Down Expand Up @@ -510,7 +515,7 @@ func listLocalClusters(app *application.Avalanche, clusterNamesToInclude []strin
return localClusters, nil
}

func LocalStatus(app *application.Avalanche, clusterName string) error {
func LocalStatus(app *application.Avalanche, clusterName string, blockchainName string) error {
clustersToList := make([]string, 0)
if clusterName != "" {
if ok, err := checkClusterIsLocal(app, clusterName); err != nil || !ok {
Expand All @@ -529,39 +534,124 @@ func LocalStatus(app *application.Avalanche, clusterName string) error {
binutils.WithAvoidRPCVersionCheck(true),
binutils.WithDialTimeout(constants.FastGRPCDialTimeout),
)
runningAvagoURIs := []string{}
if cli != nil {
status, _ := cli.Status(ctx) // ignore error as ANR might be not running
if status != nil && status.ClusterInfo != nil {
if status.ClusterInfo.RootDataDir != "" {
currentlyRunningRootDir = status.ClusterInfo.RootDataDir
}
isHealthy = status.ClusterInfo.Healthy
// get list of the nodes
for _, nodeInfo := range status.ClusterInfo.NodeInfos {
runningAvagoURIs = append(runningAvagoURIs, nodeInfo.Uri)
}
}
}
localClusters, err := listLocalClusters(app, clustersToList)
if err != nil {
return fmt.Errorf("failed to list local clusters: %w", err)
}
if clusterName != "" {
ux.Logger.PrintToUser("%s %s", logging.LightBlue.Wrap("Local cluster:"), logging.Green.Wrap(clusterName))
ux.Logger.PrintToUser("%s %s", logging.Blue.Wrap("Local cluster:"), logging.Green.Wrap(clusterName))
} else {
ux.Logger.PrintToUser(logging.LightBlue.Wrap("Local clusters:"))
ux.Logger.PrintToUser(logging.Blue.Wrap("Local clusters:"))
}
for clusterName, rootDir := range localClusters {
currenlyRunning := ""
healthStatus := ""
avagoURIOuput := ""

// load sidecar and cluster config for the cluster if blockchainName is not empty
blockchainID := ids.Empty
if blockchainName != "" {
clusterConf, err := app.GetClusterConfig(clusterName)
if err != nil {
return fmt.Errorf("failed to get cluster config: %w", err)
}
sc, err := app.LoadSidecar(blockchainName)
if err != nil {
return err
}
blockchainID = sc.Networks[clusterConf.Network.Name()].BlockchainID
}
if rootDir == currentlyRunningRootDir {
currenlyRunning = fmt.Sprintf(" [%s]", logging.Blue.Wrap("Running"))
if isHealthy {
healthStatus = fmt.Sprintf(" [%s]", logging.Green.Wrap("Healthy"))
} else {
healthStatus = fmt.Sprintf(" [%s]", logging.Red.Wrap("Unhealthy"))
}
for _, avagoURI := range runningAvagoURIs {
nodeID, nodePOP, isBoot, err := GetInfo(avagoURI, blockchainID.String())
if err != nil {
ux.Logger.RedXToUser("failed to get node %s info: %v", avagoURI, err)
continue
}
nodePOPPubKey := "0x" + hex.EncodeToString(nodePOP.PublicKey[:])
nodePOPProof := "0x" + hex.EncodeToString(nodePOP.ProofOfPossession[:])

isBootStr := "Primary:" + logging.Red.Wrap("Not Bootstrapped")
if isBoot {
isBootStr = "Primary:" + logging.Green.Wrap("Bootstrapped")
}

blockchainStatus := ""
if blockchainID != ids.Empty {
blockchainStatus, _ = GetBlockchainStatus(avagoURI, blockchainID.String()) // silence errors
}

avagoURIOuput += fmt.Sprintf(" - %s [%s] [%s]\n publicKey: %s \n proofOfPossession: %s \n",
logging.LightBlue.Wrap(avagoURI),
nodeID,
strings.TrimRight(strings.Join([]string{isBootStr, "L1:" + logging.Orange.Wrap(blockchainStatus)}, " "), " "),
nodePOPPubKey,
nodePOPProof,
)
}
} else {
currenlyRunning = fmt.Sprintf(" [%s]", logging.Black.Wrap("Stopped"))
}
ux.Logger.PrintToUser("- %s: %s %s %s", clusterName, rootDir, currenlyRunning, healthStatus)
ux.Logger.PrintToUser(avagoURIOuput)
}

return nil
}

func GetInfo(uri string, blockchainID string) (
ids.NodeID, // nodeID
*signer.ProofOfPossession, // nodePOP
bool, // isBootstrapped
error, // error
) {
client := info.NewClient(uri)
ctx, cancel := utils.GetAPILargeContext()
defer cancel()
nodeID, nodePOP, err := client.GetNodeID(ctx)
if err != nil {
return ids.EmptyNodeID, &signer.ProofOfPossession{}, false, err
}
isBootstrapped, err := client.IsBootstrapped(ctx, blockchainID)
if err != nil {
return nodeID, nodePOP, isBootstrapped, err
}
return nodeID, nodePOP, isBootstrapped, err
}

func GetBlockchainStatus(uri string, blockchainID string) (
string, // status
error, // error
) {
client := platformvm.NewClient(uri)
ctx, cancel := utils.GetAPILargeContext()
defer cancel()
status, err := client.GetBlockchainStatus(ctx, blockchainID)
if err != nil {
return "", err
}
if status.String() == "" {
return "Not Syncing", nil
}
return status.String(), nil
}

0 comments on commit d6c5705

Please # to comment.