Skip to content

Commit

Permalink
Node local status (#2261)
Browse files Browse the repository at this point in the history
* node local init

* hardcode etna devnet config

* wip

* rm not needed utils

* ready for draft PR

* nits
rm unused struct

* refactor - wip

* make sure we can resume without prompts

* add custom network and local cluster

* devnet instead of custom network, rm custom

* go mod tidy

* upgrade.json for etna devnet

* more local cluster

* separate between local network and local cluster

* working

* nit

* fix plugin

* nit

* improve snapshot management

* fix bug

* nit

* proper etna devnet boostrappers

* fix bug with local rootdir

* remove global node config stuff

* destroy node data and processes if bad start

* nit

* always use fresh staking keys

* nit

* so less flags

* add back fast boot time

* add checks for local cluster. minor refactor (#2239)

* add checks for local cluster
minor refactoring

* fix test

* addressed Felipe feedback

---------

Signed-off-by: arturrez <[email protected]>

* bump anr

* fixes for convert flow

* add check for already initialized error on PoA init

* nit

* use anr main

* fix merge

* Local mkdir rootdir (#2245)

* make sure rootDir exists

* mv it to proper location

* it's done before the start

* update anr

* add `node local status` command

* add logging.Green.Wrap(
lint

* lint

* fix merge

* make `node status` works with local clusters
more lint fixes

* detect Stopped state for local clusterName passed as arg

* add stopped status to all local clusters

* undo change

---------

Signed-off-by: arturrez <[email protected]>
Signed-off-by: sukantoraymond <[email protected]>
Co-authored-by: Felipe Madero <[email protected]>
Co-authored-by: sukantoraymond <[email protected]>
  • Loading branch information
3 people authored Oct 16, 2024
1 parent 8888202 commit 93ba0c6
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 67 deletions.
26 changes: 10 additions & 16 deletions cmd/blockchaincmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/ava-labs/avalanchego/api/info"
"os"
"path/filepath"
"strings"
"time"

"github.com/ava-labs/avalanche-cli/pkg/evm"
"github.com/ava-labs/avalanchego/api/info"

"github.com/ava-labs/avalanche-cli/pkg/evm"
"github.com/ava-labs/avalanche-cli/pkg/node"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/message"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -135,9 +135,10 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`,
cmd.Flags().StringVar(&icmSpec.RegistryBydecodePath, "teleporter-registry-bytecode-path", "", "path to an interchain messenger registry bytecode file")
cmd.Flags().StringVar(&bootstrapValidatorsJSONFilePath, "bootstrap-filepath", "", "JSON file path that provides details about bootstrap validators, leave Node-ID and BLS values empty if using --generate-node-id=true")
cmd.Flags().BoolVar(&generateNodeID, "generate-node-id", false, "whether to create new node id for bootstrap validators (Node-ID and BLS values in bootstrap JSON file will be overridden if --bootstrap-filepath flag is used)")
cmd.Flags().StringSliceVar(&bootstrapEndpoints, "bootstrap-enu dpoints", nil, "take validator node info from the given endpoints")
cmd.Flags().StringSliceVar(&bootstrapEndpoints, "bootstrap-endpoints", nil, "take validator node info from the given endpoints")
cmd.Flags().BoolVar(&useLocalMachine, "use-local-machine", false, "use local machine as a blockchain validator")
cmd.Flags().StringVar(&localMachineCluster, "local-machine-cluster", "", "existing local machine to be used as a blockchain validator")

return cmd
}

Expand Down Expand Up @@ -489,21 +490,16 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
if localMachineCluster != "" {
// don't destroy cluster if local cluster name is provided
clusterName = localMachineCluster
} else {
// destroy any cluster with same name before we start local node
// we don't want to reuse snapshots from previous sessions
if utils.DirectoryExists(app.GetLocalDir(clusterName)) {
_ = node.DestroyLocalNode(app, clusterName)
}
} else if utils.DirectoryExists(app.GetLocalDir(clusterName)) {
_ = node.DestroyLocalNode(app, clusterName)
}
// destroy any cluster with same name before we start local node
// we don't want to reuse snapshots from previous sessions
// TODO: replace bootstrapEndpoints with dynamic port number
bootstrapEndpoints = []string{"http://127.0.0.1:9650"}
anrSettings := node.ANRSettings{}
avagoVersionSettings := node.AvalancheGoVersionSettings{}
useEtnaDevnet := false
if network.Kind == models.EtnaDevnet {
useEtnaDevnet = true
}
useEtnaDevnet := network.Kind == models.EtnaDevnet
if avagoBinaryPath == "" {
ux.Logger.PrintToUser("Local build of Avalanche Go is required to create an Avalanche node using local machine")
ux.Logger.PrintToUser("Please download Avalanche Go repo at https://github.com/ava-labs/avalanchego and build from source through ./scripts/build.sh")
Expand All @@ -519,7 +515,6 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
return err
}
}

if len(bootstrapEndpoints) > 0 {
var changeAddr string
for _, endpoint := range bootstrapEndpoints {
Expand All @@ -545,8 +540,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
ChangeOwnerAddr: changeAddr,
})
}
}
if len(bootstrapValidators) == 0 {
} else {
bootstrapValidators, err = promptBootstrapValidators(network)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/nodecmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ func addNodeToClustersConfig(network models.Network, nodeID, clusterName string,
}
clusterConfig := clustersConfig.Clusters[clusterName]
// if supplied network in argument is empty, don't change current cluster network in cluster_config.json
if network != models.UndefinedNetwork {
if !network.IsUndefined() {
clusterConfig.Network = network
}
clusterConfig.HTTPAccess = constants.HTTPAccess(publicHTTPPortAccess)
Expand Down
34 changes: 0 additions & 34 deletions cmd/nodecmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package nodecmd
import (
"errors"
"fmt"
"github.com/ava-labs/avalanche-cli/pkg/models"
"os"
"strings"

Expand Down Expand Up @@ -325,36 +324,3 @@ func getClusterMonitoringNode(clusterName string) (string, error) {
}
return clustersConfig.Clusters[clusterName].MonitoringInstance, nil
}

func checkCluster(clusterName string) error {
_, err := getClusterNodes(clusterName)
return err
}

func checkClusterExists(clusterName string) (bool, error) {
clustersConfig := models.ClustersConfig{}
if app.ClustersConfigExists() {
var err error
clustersConfig, err = app.LoadClustersConfig()
if err != nil {
return false, err
}
}
_, ok := clustersConfig.Clusters[clusterName]
return ok, nil
}

func getClusterNodes(clusterName string) ([]string, error) {
if exists, err := checkClusterExists(clusterName); err != nil || !exists {
return nil, fmt.Errorf("cluster %q not found", clusterName)
}
clustersConfig, err := app.LoadClustersConfig()
if err != nil {
return nil, err
}
clusterNodes := clustersConfig.Clusters[clusterName].Nodes
if len(clusterNodes) == 0 {
return nil, fmt.Errorf("no nodes found in cluster %s", clusterName)
}
return clusterNodes, nil
}
10 changes: 6 additions & 4 deletions cmd/nodecmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ func list(_ *cobra.Command, _ []string) error {
if err := node.CheckCluster(app, clusterName); err != nil {
return err
}
cloudIDs := clusterConf.GetCloudIDs()
nodeIDs := []string{}
for _, cloudID := range clusterConf.GetCloudIDs() {
for _, cloudID := range cloudIDs {
nodeIDStr := "----------------------------------------"
if clusterConf.IsAvalancheGoHost(cloudID) {
if nodeID, err := getNodeID(app.GetNodeInstanceDirPath(cloudID)); err != nil {
Expand All @@ -56,11 +57,12 @@ func list(_ *cobra.Command, _ []string) error {
}
nodeIDs = append(nodeIDs, nodeIDStr)
}
if clusterConf.External {
switch {
case clusterConf.External:
ux.Logger.PrintToUser("cluster %q (%s) EXTERNAL", clusterName, clusterConf.Network.Kind.String())
} else if clusterConf.Local {
case clusterConf.Local:
ux.Logger.PrintToUser("cluster %q (%s) LOCAL", clusterName, clusterConf.Network.Kind.String())
} else {
default:
ux.Logger.PrintToUser("Cluster %q (%s)", clusterName, clusterConf.Network.Kind.String())
}
for i, cloudID := range clusterConf.GetCloudIDs() {
Expand Down
20 changes: 20 additions & 0 deletions cmd/nodecmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ The node local command suite provides a collection of commands related to local
cmd.AddCommand(newLocalDestroyCmd())
// node local track
cmd.AddCommand(newLocalTrackCmd())
// node local status
cmd.AddCommand(newLocalStatusCmd())
return cmd
}

Expand Down Expand Up @@ -110,6 +112,16 @@ func newLocalDestroyCmd() *cobra.Command {
}
}

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

func localStartNode(_ *cobra.Command, args []string) error {
clusterName := args[0]
anrSettings := node.ANRSettings{
Expand Down Expand Up @@ -143,6 +155,14 @@ func localTrack(_ *cobra.Command, args []string) error {
return node.TrackSubnetWithLocalMachine(app, args[0], args[1])
}

func localStatus(_ *cobra.Command, args []string) error {
clusterName := ""
if len(args) > 0 {
clusterName = args[0]
}
return node.LocalStatus(app, clusterName)
}

func notImplementedForLocal(what string) error {
ux.Logger.PrintToUser("Unsupported cmd: %s is not supported by local clusters", logging.LightBlue.Wrap(what))
return nil
Expand Down
4 changes: 2 additions & 2 deletions internal/mocks/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pkg/models/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func NewNetwork(kind NetworkKind, id uint32, endpoint string, clusterName string
}
}

func (n Network) IsUndefined() bool {
return n.Kind == Undefined
}

func NewLocalNetwork() Network {
return NewNetwork(Local, constants.LocalNetworkID, constants.LocalAPIEndpoint, "")
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/node/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"encoding/json"
"errors"
"fmt"
"sync"
"time"

"github.com/ava-labs/avalanche-cli/pkg/binutils"
"github.com/ava-labs/avalanche-cli/pkg/subnet"
"github.com/ava-labs/avalanche-cli/pkg/vm"
"sync"
"time"

"github.com/ava-labs/avalanche-cli/pkg/ansible"

Expand Down Expand Up @@ -58,12 +59,12 @@ func GetClusterNodes(app *application.Avalanche, clusterName string) ([]string,
if exists, err := CheckClusterExists(app, clusterName); err != nil || !exists {
return nil, fmt.Errorf("cluster %q not found", clusterName)
}
clustersConfig, err := app.LoadClustersConfig()
clusterConfig, err := app.GetClusterConfig(clusterName)
if err != nil {
return nil, err
}
clusterNodes := clustersConfig.Clusters[clusterName].Nodes
if len(clusterNodes) == 0 {
clusterNodes := clusterConfig.Nodes
if len(clusterNodes) == 0 && !clusterConfig.Local {
return nil, fmt.Errorf("no nodes found in cluster %s", clusterName)
}
return clusterNodes, nil
Expand Down Expand Up @@ -416,7 +417,6 @@ func promptAvalancheGoVersionChoice(app *application.Avalanche, latestReleaseVer
ux.Logger.PrintToUser(fmt.Sprintf("no subnet named %s found", useAvalanchegoVersionFromSubnet))
}
return AvalancheGoVersionSettings{UseAvalanchegoVersionFromSubnet: useAvalanchegoVersionFromSubnet}, nil

}
}

Expand Down
83 changes: 79 additions & 4 deletions pkg/node/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ package node

import (
"fmt"
"os"
"path/filepath"
"slices"

"github.com/ava-labs/avalanche-cli/pkg/application"
"github.com/ava-labs/avalanche-cli/pkg/binutils"
"github.com/ava-labs/avalanche-cli/pkg/constants"
Expand All @@ -16,9 +20,8 @@ import (
"github.com/ava-labs/avalanche-network-runner/client"
anrutils "github.com/ava-labs/avalanche-network-runner/utils"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"
"os"
"path/filepath"
)

func TrackSubnetWithLocalMachine(app *application.Avalanche, clusterName, blockchainName string) error {
Expand Down Expand Up @@ -296,7 +299,7 @@ func StartLocalNode(app *application.Avalanche, clusterName string, useEtnaDevne
spinner := spinSession.SpinToUser("Booting Network. Wait until healthy...")
if _, err := cli.Start(ctx, avalancheGoBinPath, anrOpts...); err != nil {
ux.SpinFailWithError(spinner, "", err)
DestroyLocalNode(app, clusterName)
_ = DestroyLocalNode(app, clusterName)
return fmt.Errorf("failed to start local avalanchego: %w", err)
}
ux.SpinComplete(spinner)
Expand Down Expand Up @@ -393,7 +396,7 @@ func addLocalClusterConfig(app *application.Avalanche, network models.Network) e
}

func DestroyLocalNode(app *application.Avalanche, clusterName string) error {
StopLocalNode(app)
_ = StopLocalNode(app)

rootDir := app.GetLocalDir(clusterName)
if err := os.RemoveAll(rootDir); err != nil {
Expand Down Expand Up @@ -447,3 +450,75 @@ func StopLocalNode(app *application.Avalanche) error {
ux.Logger.GreenCheckmarkToUser("avalanchego stopped")
return nil
}

func listLocalClusters(app *application.Avalanche, clusterNamesToInclude []string) (map[string]string, error) {
localClusters := map[string]string{} // map[clusterName]rootDir
clustersConfig, err := app.GetClustersConfig()
if err != nil {
return localClusters, err
}
for clusterName := range clustersConfig.Clusters {
if len(clusterNamesToInclude) == 0 || slices.Contains(clusterNamesToInclude, clusterName) {
if ok, err := checkClusterIsLocal(app, clusterName); err == nil && ok {
localClusters[clusterName] = app.GetLocalDir(clusterName)
}
}
}
return localClusters, nil
}

func LocalStatus(app *application.Avalanche, clusterName string) error {
clustersToList := make([]string, 0)
if clusterName != "" {
if ok, err := checkClusterIsLocal(app, clusterName); err != nil || !ok {
return fmt.Errorf("local cluster %q not found", clusterName)
}
clustersToList = append(clustersToList, clusterName)
}

// get currently running local cluster
ctx, cancel := utils.GetANRContext()
defer cancel()
currentlyRunningRootDir := ""
isHealthy := false
cli, _ := binutils.NewGRPCClientWithEndpoint( // ignore error as ANR might be not running
binutils.LocalClusterGRPCServerEndpoint,
binutils.WithAvoidRPCVersionCheck(true),
binutils.WithDialTimeout(constants.FastGRPCDialTimeout),
)
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
}
}
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))
} else {
ux.Logger.PrintToUser(logging.LightBlue.Wrap("Local clusters:"))
}
for clusterName, rootDir := range localClusters {
currenlyRunning := ""
healthStatus := ""
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"))
}
} else {
currenlyRunning = fmt.Sprintf(" [%s]", logging.Black.Wrap("Stopped"))
}
ux.Logger.PrintToUser("- %s: %s %s %s", clusterName, rootDir, currenlyRunning, healthStatus)
}

return nil
}

0 comments on commit 93ba0c6

Please sign in to comment.