Browse Source

improve testnet cmd (#1449)

* improve testnet cmd

* allow non-validators
* configurable prefix
* populating of persistent peers

* relax permissions

* cleanup output dir every time

* do not remove dir

* remove panic comments
pull/1451/head
Anton Kaliaev 7 years ago
committed by GitHub
parent
commit
0323b03daf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 133 additions and 50 deletions
  1. +11
    -4
      cmd/tendermint/commands/init.go
  2. +111
    -40
      cmd/tendermint/commands/testnet.go
  3. +11
    -6
      config/toml.go

+ 11
- 4
cmd/tendermint/commands/init.go View File

@ -3,6 +3,7 @@ package commands
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator" pvm "github.com/tendermint/tendermint/types/priv_validator"
@ -13,10 +14,14 @@ import (
var InitFilesCmd = &cobra.Command{ var InitFilesCmd = &cobra.Command{
Use: "init", Use: "init",
Short: "Initialize Tendermint", Short: "Initialize Tendermint",
Run: initFiles,
RunE: initFiles,
} }
func initFiles(cmd *cobra.Command, args []string) {
func initFiles(cmd *cobra.Command, args []string) error {
return initFilesWithConfig(config)
}
func initFilesWithConfig(config *cfg.Config) error {
// private validator // private validator
privValFile := config.PrivValidatorFile() privValFile := config.PrivValidatorFile()
var pv *pvm.FilePV var pv *pvm.FilePV
@ -34,7 +39,7 @@ func initFiles(cmd *cobra.Command, args []string) {
logger.Info("Found node key", "path", nodeKeyFile) logger.Info("Found node key", "path", nodeKeyFile)
} else { } else {
if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil { if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil {
panic(err)
return err
} }
logger.Info("Generated node key", "path", nodeKeyFile) logger.Info("Generated node key", "path", nodeKeyFile)
} }
@ -53,8 +58,10 @@ func initFiles(cmd *cobra.Command, args []string) {
}} }}
if err := genDoc.SaveAs(genFile); err != nil { if err := genDoc.SaveAs(genFile); err != nil {
panic(err)
return err
} }
logger.Info("Generated genesis file", "path", genFile) logger.Info("Generated genesis file", "path", genFile)
} }
return nil
} }

+ 111
- 40
cmd/tendermint/commands/testnet.go View File

@ -2,60 +2,103 @@ package commands
import ( import (
"fmt" "fmt"
"net"
"os"
"path/filepath" "path/filepath"
"strings"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config" cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator" pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
) )
//flags
var ( var (
nValidators int
dataDir string
nValidators int
nNonValidators int
outputDir string
nodeDirPrefix string
populatePersistentPeers bool
hostnamePrefix string
startingIPAddress string
p2pPort int
)
const (
nodeDirPerm = 0755
) )
func init() { func init() {
TestnetFilesCmd.Flags().IntVar(&nValidators, "n", 4,
TestnetFilesCmd.Flags().IntVar(&nValidators, "v", 4,
"Number of validators to initialize the testnet with") "Number of validators to initialize the testnet with")
TestnetFilesCmd.Flags().StringVar(&dataDir, "dir", "mytestnet",
TestnetFilesCmd.Flags().IntVar(&nNonValidators, "n", 0,
"Number of non-validators to initialize the testnet with")
TestnetFilesCmd.Flags().StringVar(&outputDir, "o", "./mytestnet",
"Directory to store initialization data for the testnet") "Directory to store initialization data for the testnet")
TestnetFilesCmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)")
TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true,
"Update config of each node with the list of persistent peers build using either hostname-prefix or starting-ip-address")
TestnetFilesCmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "node",
"Hostname prefix (node results in persistent peers list ID0@node0:46656, ID1@node1:46656, ...)")
TestnetFilesCmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
TestnetFilesCmd.Flags().IntVar(&p2pPort, "p2p-port", 46656,
"P2P Port")
} }
// TestnetFilesCmd allows initialisation of files for a
// Tendermint testnet.
// TestnetFilesCmd allows initialisation of files for a Tendermint testnet.
var TestnetFilesCmd = &cobra.Command{ var TestnetFilesCmd = &cobra.Command{
Use: "testnet", Use: "testnet",
Short: "Initialize files for a Tendermint testnet", Short: "Initialize files for a Tendermint testnet",
Run: testnetFiles,
RunE: testnetFiles,
} }
func testnetFiles(cmd *cobra.Command, args []string) {
func testnetFiles(cmd *cobra.Command, args []string) error {
config := cfg.DefaultConfig()
genVals := make([]types.GenesisValidator, nValidators) genVals := make([]types.GenesisValidator, nValidators)
defaultConfig := cfg.DefaultBaseConfig()
// Initialize core dir and priv_validator.json's
for i := 0; i < nValidators; i++ { for i := 0; i < nValidators; i++ {
mach := cmn.Fmt("mach%d", i)
err := initMachCoreDirectory(dataDir, mach)
nodeDirName := cmn.Fmt("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName)
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil { if err != nil {
cmn.Exit(err.Error())
_ = os.RemoveAll(outputDir)
return err
} }
// Read priv_validator.json to populate vals
pvFile := filepath.Join(dataDir, mach, defaultConfig.PrivValidator)
initFilesWithConfig(config)
pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator)
pv := pvm.LoadFilePV(pvFile) pv := pvm.LoadFilePV(pvFile)
genVals[i] = types.GenesisValidator{ genVals[i] = types.GenesisValidator{
PubKey: pv.GetPubKey(), PubKey: pv.GetPubKey(),
Power: 1, Power: 1,
Name: mach,
Name: nodeDirName,
} }
} }
for i := 0; i < nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i+nValidators))
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}
initFilesWithConfig(config)
}
// Generate genesis doc from generated validators // Generate genesis doc from generated validators
genDoc := &types.GenesisDoc{ genDoc := &types.GenesisDoc{
GenesisTime: time.Now(), GenesisTime: time.Now(),
@ -64,36 +107,64 @@ func testnetFiles(cmd *cobra.Command, args []string) {
} }
// Write genesis file. // Write genesis file.
for i := 0; i < nValidators; i++ {
mach := cmn.Fmt("mach%d", i)
if err := genDoc.SaveAs(filepath.Join(dataDir, mach, defaultConfig.Genesis)); err != nil {
panic(err)
for i := 0; i < nValidators+nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i))
if err := genDoc.SaveAs(filepath.Join(nodeDir, config.BaseConfig.Genesis)); err != nil {
_ = os.RemoveAll(outputDir)
return err
} }
} }
fmt.Println(cmn.Fmt("Successfully initialized %v node directories", nValidators))
if populatePersistentPeers {
err := populatePersistentPeersInConfigAndWriteIt(config)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}
}
fmt.Printf("Successfully initialized %v node directories\n", nValidators+nNonValidators)
return nil
} }
// Initialize per-machine core directory
func initMachCoreDirectory(base, mach string) error {
// Create priv_validator.json file if not present
defaultConfig := cfg.DefaultBaseConfig()
dir := filepath.Join(base, mach)
pvPath := filepath.Join(dir, defaultConfig.PrivValidator)
dir = filepath.Dir(pvPath)
err := cmn.EnsureDir(dir, 0700)
if err != nil {
return err
func hostnameOrIP(i int) string {
if startingIPAddress != "" {
ip := net.ParseIP(startingIPAddress)
ip = ip.To4()
if ip == nil {
fmt.Printf("%v: non ipv4 address\n", startingIPAddress)
os.Exit(1)
}
ip = ip.Mask(ip.DefaultMask())
for j := 0; j <= i; j++ {
ip[3]++
}
return ip.String()
} }
ensurePrivValidator(pvPath)
return nil
return fmt.Sprintf("%s%d", hostnamePrefix, i)
} }
func ensurePrivValidator(file string) {
if cmn.FileExists(file) {
return
func populatePersistentPeersInConfigAndWriteIt(config *cfg.Config) error {
persistentPeers := make([]string, nValidators+nNonValidators)
for i := 0; i < nValidators+nNonValidators; i++ {
nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
persistentPeers[i] = p2p.IDAddressString(nodeKey.ID(), fmt.Sprintf("%s:%d", hostnameOrIP(i), p2pPort))
} }
pv := pvm.GenFilePV(file)
pv.Save()
persistentPeersList := strings.Join(persistentPeers, ",")
for i := 0; i < nValidators+nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i))
config.SetRoot(nodeDir)
config.P2P.PersistentPeers = persistentPeersList
// overwrite default config
cfg.WriteConfigFile(filepath.Join(nodeDir, "config", "config.toml"), config)
}
return nil
} }

+ 11
- 6
config/toml.go View File

@ -37,16 +37,21 @@ func EnsureRoot(rootDir string) {
// Write default config file if missing. // Write default config file if missing.
if !cmn.FileExists(configFilePath) { if !cmn.FileExists(configFilePath) {
writeConfigFile(configFilePath)
writeDefaultCondigFile(configFilePath)
} }
} }
// XXX: this func should probably be called by cmd/tendermint/commands/init.go // XXX: this func should probably be called by cmd/tendermint/commands/init.go
// alongside the writing of the genesis.json and priv_validator.json // alongside the writing of the genesis.json and priv_validator.json
func writeConfigFile(configFilePath string) {
func writeDefaultCondigFile(configFilePath string) {
WriteConfigFile(configFilePath, DefaultConfig())
}
// WriteConfigFile renders config using the template and writes it to configFilePath.
func WriteConfigFile(configFilePath string, config *Config) {
var buffer bytes.Buffer var buffer bytes.Buffer
if err := configTemplate.Execute(&buffer, DefaultConfig()); err != nil {
if err := configTemplate.Execute(&buffer, config); err != nil {
panic(err) panic(err)
} }
@ -124,11 +129,11 @@ unsafe = {{ .RPC.Unsafe }}
laddr = "{{ .P2P.ListenAddress }}" laddr = "{{ .P2P.ListenAddress }}"
# Comma separated list of seed nodes to connect to # Comma separated list of seed nodes to connect to
seeds = ""
seeds = "{{ .P2P.Seeds }}"
# Comma separated list of nodes to keep persistent connections to # Comma separated list of nodes to keep persistent connections to
# Do not add private peers to this list if you don't want them advertised # Do not add private peers to this list if you don't want them advertised
persistent_peers = ""
persistent_peers = "{{ .P2P.PersistentPeers }}"
# Path to address book # Path to address book
addr_book_file = "{{ .P2P.AddrBook }}" addr_book_file = "{{ .P2P.AddrBook }}"
@ -262,7 +267,7 @@ func ResetTestRoot(testName string) *Config {
// Write default config file if missing. // Write default config file if missing.
if !cmn.FileExists(configFilePath) { if !cmn.FileExists(configFilePath) {
writeConfigFile(configFilePath)
writeDefaultCondigFile(configFilePath)
} }
if !cmn.FileExists(genesisFilePath) { if !cmn.FileExists(genesisFilePath) {
cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644) cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)


Loading…
Cancel
Save