github.com/MetalBlockchain/metalgo@v1.11.9/tests/fixture/tmpnet/cmd/main.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io/fs"
    11  	"os"
    12  	"path/filepath"
    13  	"time"
    14  
    15  	"github.com/spf13/cobra"
    16  
    17  	"github.com/MetalBlockchain/metalgo/tests/fixture/tmpnet"
    18  	"github.com/MetalBlockchain/metalgo/version"
    19  )
    20  
    21  const cliVersion = "0.0.1"
    22  
    23  var (
    24  	errAvalancheGoRequired = fmt.Errorf("--metalgo-path or %s are required", tmpnet.AvalancheGoPathEnvName)
    25  	errNetworkDirRequired  = fmt.Errorf("--network-dir or %s are required", tmpnet.NetworkDirEnvName)
    26  )
    27  
    28  func main() {
    29  	var networkDir string
    30  	rootCmd := &cobra.Command{
    31  		Use:   "tmpnetctl",
    32  		Short: "tmpnetctl commands",
    33  	}
    34  	rootCmd.PersistentFlags().StringVar(&networkDir, "network-dir", os.Getenv(tmpnet.NetworkDirEnvName), "The path to the configuration directory of a temporary network")
    35  
    36  	versionCmd := &cobra.Command{
    37  		Use:   "version",
    38  		Short: "Print version details",
    39  		RunE: func(*cobra.Command, []string) error {
    40  			msg := cliVersion
    41  			if len(version.GitCommit) > 0 {
    42  				msg += ", commit=" + version.GitCommit
    43  			}
    44  			fmt.Fprintf(os.Stdout, msg+"\n")
    45  			return nil
    46  		},
    47  	}
    48  	rootCmd.AddCommand(versionCmd)
    49  
    50  	var (
    51  		rootDir         string
    52  		networkOwner    string
    53  		avalancheGoPath string
    54  		pluginDir       string
    55  		nodeCount       uint8
    56  	)
    57  	startNetworkCmd := &cobra.Command{
    58  		Use:   "start-network",
    59  		Short: "Start a new temporary network",
    60  		RunE: func(*cobra.Command, []string) error {
    61  			if len(avalancheGoPath) == 0 {
    62  				return errAvalancheGoRequired
    63  			}
    64  
    65  			// Root dir will be defaulted on start if not provided
    66  
    67  			network := &tmpnet.Network{
    68  				Owner: networkOwner,
    69  				Nodes: tmpnet.NewNodesOrPanic(int(nodeCount)),
    70  			}
    71  
    72  			// Extreme upper bound, should never take this long
    73  			networkStartTimeout := 2 * time.Minute
    74  
    75  			ctx, cancel := context.WithTimeout(context.Background(), networkStartTimeout)
    76  			defer cancel()
    77  			err := tmpnet.BootstrapNewNetwork(
    78  				ctx,
    79  				os.Stdout,
    80  				network,
    81  				rootDir,
    82  				avalancheGoPath,
    83  				pluginDir,
    84  			)
    85  			if err != nil {
    86  				return err
    87  			}
    88  
    89  			// Symlink the new network to the 'latest' network to simplify usage
    90  			networkRootDir := filepath.Dir(network.Dir)
    91  			networkDirName := filepath.Base(network.Dir)
    92  			latestSymlinkPath := filepath.Join(networkRootDir, "latest")
    93  			if err := os.Remove(latestSymlinkPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
    94  				return err
    95  			}
    96  			if err := os.Symlink(networkDirName, latestSymlinkPath); err != nil {
    97  				return err
    98  			}
    99  
   100  			fmt.Fprintln(os.Stdout, "\nConfigure tmpnetctl to target this network by default with one of the following statements:")
   101  			fmt.Fprintf(os.Stdout, " - source %s\n", network.EnvFilePath())
   102  			fmt.Fprintf(os.Stdout, " - %s\n", network.EnvFileContents())
   103  			fmt.Fprintf(os.Stdout, " - export %s=%s\n", tmpnet.NetworkDirEnvName, latestSymlinkPath)
   104  
   105  			return nil
   106  		},
   107  	}
   108  	startNetworkCmd.PersistentFlags().StringVar(&rootDir, "root-dir", os.Getenv(tmpnet.RootDirEnvName), "The path to the root directory for temporary networks")
   109  	startNetworkCmd.PersistentFlags().StringVar(&avalancheGoPath, "metalgo-path", os.Getenv(tmpnet.AvalancheGoPathEnvName), "The path to a metalgo binary")
   110  	startNetworkCmd.PersistentFlags().StringVar(&pluginDir, "plugin-dir", os.ExpandEnv("$HOME/.avalanchego/plugins"), "[optional] the dir containing VM plugins")
   111  	startNetworkCmd.PersistentFlags().Uint8Var(&nodeCount, "node-count", tmpnet.DefaultNodeCount, "Number of nodes the network should initially consist of")
   112  	startNetworkCmd.PersistentFlags().StringVar(&networkOwner, "network-owner", "", "The string identifying the intended owner of the network")
   113  	rootCmd.AddCommand(startNetworkCmd)
   114  
   115  	stopNetworkCmd := &cobra.Command{
   116  		Use:   "stop-network",
   117  		Short: "Stop a temporary network",
   118  		RunE: func(*cobra.Command, []string) error {
   119  			if len(networkDir) == 0 {
   120  				return errNetworkDirRequired
   121  			}
   122  			ctx, cancel := context.WithTimeout(context.Background(), tmpnet.DefaultNetworkTimeout)
   123  			defer cancel()
   124  			if err := tmpnet.StopNetwork(ctx, networkDir); err != nil {
   125  				return err
   126  			}
   127  			fmt.Fprintf(os.Stdout, "Stopped network configured at: %s\n", networkDir)
   128  			return nil
   129  		},
   130  	}
   131  	rootCmd.AddCommand(stopNetworkCmd)
   132  
   133  	restartNetworkCmd := &cobra.Command{
   134  		Use:   "restart-network",
   135  		Short: "Restart a temporary network",
   136  		RunE: func(*cobra.Command, []string) error {
   137  			if len(networkDir) == 0 {
   138  				return errNetworkDirRequired
   139  			}
   140  			ctx, cancel := context.WithTimeout(context.Background(), tmpnet.DefaultNetworkTimeout)
   141  			defer cancel()
   142  			return tmpnet.RestartNetwork(ctx, os.Stdout, networkDir)
   143  		},
   144  	}
   145  	rootCmd.AddCommand(restartNetworkCmd)
   146  
   147  	if err := rootCmd.Execute(); err != nil {
   148  		fmt.Fprintf(os.Stderr, "tmpnetctl failed: %v\n", err)
   149  		os.Exit(1)
   150  	}
   151  	os.Exit(0)
   152  }