Skip to content

Commit

Permalink
add custom bootrap conf to node create
Browse files Browse the repository at this point in the history
  • Loading branch information
arturrez committed Oct 9, 2024
1 parent 3029c48 commit c401829
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 28 deletions.
89 changes: 76 additions & 13 deletions cmd/nodecmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package nodecmd
import (
"fmt"
"math"
"net/netip"
"os"
"os/user"
"path/filepath"
Expand Down Expand Up @@ -76,6 +77,12 @@ var (
grafanaPkg string
wizSubnet string
publicHTTPPortAccess bool

bootstrapIDs []string
bootstrapIPs []string
genesisPath string
upgradePath string
useEtnaDevnet bool
)

func newCreateCmd() *cobra.Command {
Expand Down Expand Up @@ -128,6 +135,11 @@ will apply to all nodes in the cluster`,
cmd.Flags().IntVar(&volumeSize, "aws-volume-size", constants.CloudServerStorageSize, "AWS volume size in GB")
cmd.Flags().BoolVar(&replaceKeyPair, "auto-replace-keypair", false, "automatically replaces key pair to access node if previous key pair is not found")
cmd.Flags().BoolVar(&publicHTTPPortAccess, "public-http-port", false, "allow public access to avalanchego HTTP port")
cmd.Flags().StringArrayVar(&bootstrapIDs, "bootstrap-id", []string{}, "nodeIDs of bootstrap nodes")
cmd.Flags().StringArrayVar(&bootstrapIPs, "bootstrap-ip", []string{}, "IP:port pairs of bootstrap nodes")
cmd.Flags().StringVar(&genesisPath, "genesis", "", "path to genesis file")
cmd.Flags().StringVar(&upgradePath, "upgrade", "", "path to upgrade file")
cmd.Flags().BoolVar(&useEtnaDevnet, "etna-devnet", false, "use Etna devnet. Prepopulated with Etna DevNet bootstrap configuration along with genesis and upgrade files")
return cmd
}

Expand Down Expand Up @@ -199,6 +211,25 @@ func preCreateChecks(clusterName string) error {
if err := failForExternal(clusterName); err != nil {
return err
}
// bootsrap checks
if useEtnaDevnet && (len(bootstrapIDs) != 0 || len(bootstrapIPs) != 0 || genesisPath != "" || upgradePath != "") {
return fmt.Errorf("etna devnet uses predefined bootsrap configuration")
}
if len((bootstrapIDs)) != len(bootstrapIPs) {
return fmt.Errorf("number of bootstrap ids and ip:port pairs must be equal")
}
if genesisPath != "" && !utils.FileExists(genesisPath) {
return fmt.Errorf("genesis file %s does not exist", genesisPath)
}
if upgradePath != "" && !utils.FileExists(upgradePath) {
return fmt.Errorf("upgrade file %s does not exist", upgradePath)
}
// check ip:port pairs
for _, ip := range bootstrapIPs {
if _, err := netip.ParseAddrPort(ip); err != nil {
return fmt.Errorf("invalid ip:port pair %s", ip)
}
}

return nil
}
Expand Down Expand Up @@ -240,21 +271,45 @@ func stringToAWSVolumeType(input string) types.VolumeType {
}

func createNodes(cmd *cobra.Command, args []string) error {
var err error
clusterName := args[0]
network := models.UndefinedNetwork
if err := preCreateChecks(clusterName); err != nil {
return err
}
network, err := networkoptions.GetNetworkFromCmdLineFlags(
app,
"",
globalNetworkFlags,
false,
true,
createSupportedNetworkOptions,
"",
)
if err != nil {
return err
// etna devnet constants
if useEtnaDevnet {
network = models.NewDevnetNetwork(constants.EtnaDevnetEndpoint, constants.EtnaDevnetNetworkID)
bootstrapIDs = constants.EtnaDevnetBootstrapNodeIDs
bootstrapIPs = constants.EtnaDevnetBootstrapIPs
genesisTmpFile, err := os.CreateTemp("", "genesis")
if err != nil {
return err
}
genesisPath = genesisTmpFile.Name()
upgradeTmpFile, err := os.CreateTemp("", "upgrade")
if err != nil {
return err
}
upgradePath = upgradeTmpFile.Name()

defer func() {
_ = os.Remove(genesisTmpFile.Name())
_ = os.Remove(upgradeTmpFile.Name())
}()
} else {
network, err = networkoptions.GetNetworkFromCmdLineFlags(
app,
"",
globalNetworkFlags,
false,
true,
createSupportedNetworkOptions,
"",
)
if err != nil {
return err
}
}
network = models.NewNetworkFromCluster(network, clusterName)
globalNetworkFlags.UseDevnet = network.Kind == models.Devnet // set globalNetworkFlags.UseDevnet to true if network is devnet for further use
Expand Down Expand Up @@ -715,7 +770,15 @@ func createNodes(cmd *cobra.Command, args []string) error {
spinner = spinSession.SpinToUser(utils.ScriptLog(host.NodeID, "Setup AvalancheGo"))
// check if host is a API host
publicAccessToHTTPPort := slices.Contains(cloudConfigMap.GetAllAPIInstanceIDs(), host.GetCloudID()) || publicHTTPPortAccess
if err := docker.ComposeSSHSetupNode(host, network, avalancheGoVersion, addMonitoring, publicAccessToHTTPPort); err != nil {
if err := docker.ComposeSSHSetupNode(host,
network,
avalancheGoVersion,
bootstrapIDs,
bootstrapIPs,
genesisPath,
upgradePath,
addMonitoring,
publicAccessToHTTPPort); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
ux.SpinFailWithError(spinner, "", err)
return
Expand All @@ -726,7 +789,7 @@ func createNodes(cmd *cobra.Command, args []string) error {
wg.Wait()
ux.Logger.Info("Create and setup nodes time took: %s", time.Since(startTime))
spinSession.Stop()
if network.Kind == models.Devnet {
if network.Kind == models.Devnet && !useEtnaDevnet {
if err := setupDevnet(clusterName, hosts, apiNodeIPMap); err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/docker/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/ava-labs/avalanche-cli/pkg/ux"
)

type dockerComposeInputs struct {
type DockerComposeInputs struct {
WithMonitoring bool
WithAvalanchego bool
AvalanchegoVersion string
Expand All @@ -31,7 +31,7 @@ type dockerComposeInputs struct {
//go:embed templates/*.docker-compose.yml
var composeTemplate embed.FS

func renderComposeFile(composePath string, composeDesc string, templateVars dockerComposeInputs) ([]byte, error) {
func renderComposeFile(composePath string, composeDesc string, templateVars DockerComposeInputs) ([]byte, error) {
compose, err := composeTemplate.ReadFile(composePath)
if err != nil {
return nil, err
Expand Down Expand Up @@ -206,7 +206,7 @@ func ComposeOverSSH(
host *models.Host,
timeout time.Duration,
composePath string,
composeVars dockerComposeInputs,
composeVars DockerComposeInputs,
) error {
remoteComposeFile := utils.GetRemoteComposeFile()
startTime := time.Now()
Expand Down
20 changes: 19 additions & 1 deletion pkg/docker/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,36 @@ package docker

import (
"os"
"path/filepath"
"strings"

"github.com/ava-labs/avalanche-cli/pkg/constants"
"github.com/ava-labs/avalanche-cli/pkg/models"
"github.com/ava-labs/avalanche-cli/pkg/remoteconfig"
"github.com/ava-labs/avalanche-cli/pkg/utils"
)

func prepareAvalanchegoConfig(host *models.Host, network models.Network, publicAccess bool) (string, string, error) {
func prepareAvalanchegoConfig(
host *models.Host,
network models.Network,
avalanchegoBootstrapIDs []string,
avalanchegoBootstrapIPs []string,
avalanchegoGenesisFilePath string,
avalanchegoUpgradeFilePath string,
publicAccess bool,
) (string, string, error) {
avagoConf := remoteconfig.PrepareAvalancheConfig(host.IP, network.NetworkIDFlagValue(), nil)
if publicAccess || utils.IsE2E() {
avagoConf.HTTPHost = "0.0.0.0"
}
avagoConf.BootstrapIPs = strings.Join(avalanchegoBootstrapIPs, ",")
avagoConf.BootstrapIDs = strings.Join(avalanchegoBootstrapIDs, ",")
if avalanchegoGenesisFilePath != "" {
avagoConf.GenesisPath = filepath.Join(constants.DockerNodeConfigPath, constants.GenesisFileName)
}
if avalanchegoUpgradeFilePath != "" {
avagoConf.UpgradePath = filepath.Join(constants.DockerNodeConfigPath, constants.UpgradeFileName)
}
nodeConf, err := remoteconfig.RenderAvalancheNodeConfig(avagoConf)
if err != nil {
return "", "", err
Expand Down
40 changes: 34 additions & 6 deletions pkg/docker/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ func ValidateComposeFile(host *models.Host, composeFile string, timeout time.Dur
}

// ComposeSSHSetupNode sets up an AvalancheGo node and dependencies on a remote host over SSH.
func ComposeSSHSetupNode(host *models.Host, network models.Network, avalancheGoVersion string, withMonitoring bool, publicAccessToHTTPPort bool) error {
func ComposeSSHSetupNode(
host *models.Host,
network models.Network,
avalancheGoVersion string,
avalanchegoBootstrapIDs []string,
avalanchegoBootstrapIPs []string,
avalanchegoGenesisFilePath string,
avalanchegoUpgradeFilePath string,
withMonitoring bool,
publicAccessToHTTPPort bool,
) error {
startTime := time.Now()
folderStructure := remoteconfig.RemoteFoldersToCreateAvalanchego()
for _, dir := range folderStructure {
Expand All @@ -41,7 +51,15 @@ func ComposeSSHSetupNode(host *models.Host, network models.Network, avalancheGoV
return err
}
ux.Logger.Info("AvalancheGo Docker image %s ready on %s[%s] after %s", avagoDockerImage, host.NodeID, host.IP, time.Since(startTime))
nodeConfFile, cChainConfFile, err := prepareAvalanchegoConfig(host, network, publicAccessToHTTPPort)
nodeConfFile, cChainConfFile, err := prepareAvalanchegoConfig(
host,
network,
avalanchegoBootstrapIDs,
avalanchegoBootstrapIPs,
avalanchegoGenesisFilePath,
avalanchegoUpgradeFilePath,
publicAccessToHTTPPort,
)
if err != nil {
return err
}
Expand All @@ -60,12 +78,22 @@ func ComposeSSHSetupNode(host *models.Host, network models.Network, avalancheGoV
if err := host.Upload(cChainConfFile, remoteconfig.GetRemoteAvalancheCChainConfig(), constants.SSHFileOpsTimeout); err != nil {
return err
}
if avalanchegoGenesisFilePath != "" {
if err := host.Upload(avalanchegoGenesisFilePath, remoteconfig.GetRemoteAvalancheGenesis(), constants.SSHFileOpsTimeout); err != nil {
return err
}
}
if avalanchegoUpgradeFilePath != "" {
if err := host.Upload(avalanchegoUpgradeFilePath, remoteconfig.GetRemoteAvalancheUpgrade(), constants.SSHFileOpsTimeout); err != nil {
return err
}
}
ux.Logger.Info("AvalancheGo configs uploaded to %s[%s] after %s", host.NodeID, host.IP, time.Since(startTime))
return ComposeOverSSH("Compose Node",
host,
constants.SSHScriptTimeout,
"templates/avalanchego.docker-compose.yml",
dockerComposeInputs{
DockerComposeInputs{
AvalanchegoVersion: avalancheGoVersion,
WithMonitoring: withMonitoring,
WithAvalanchego: true,
Expand All @@ -80,7 +108,7 @@ func ComposeSSHSetupLoadTest(host *models.Host) error {
host,
constants.SSHScriptTimeout,
"templates/avalanchego.docker-compose.yml",
dockerComposeInputs{
DockerComposeInputs{
WithMonitoring: true,
WithAvalanchego: false,
})
Expand Down Expand Up @@ -133,13 +161,13 @@ func ComposeSSHSetupMonitoring(host *models.Host) error {
host,
constants.SSHScriptTimeout,
"templates/monitoring.docker-compose.yml",
dockerComposeInputs{})
DockerComposeInputs{})
}

func ComposeSSHSetupAWMRelayer(host *models.Host) error {
return ComposeOverSSH("Setup AWM Relayer",
host,
constants.SSHScriptTimeout,
"templates/awmrelayer.docker-compose.yml",
dockerComposeInputs{})
DockerComposeInputs{})
}
4 changes: 4 additions & 0 deletions pkg/remoteconfig/avalanche.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func GetRemoteAvalancheGenesis() string {
return filepath.Join(constants.CloudNodeConfigPath, constants.GenesisFileName)
}

func GetRemoteAvalancheUpgrade() string {
return filepath.Join(constants.CloudNodeConfigPath, constants.UpgradeFileName)
}

func GetRemoteAvalancheAliasesConfig() string {
return filepath.Join(constants.CloudNodeConfigPath, "chains", constants.AliasesFileName)
}
Expand Down
20 changes: 15 additions & 5 deletions pkg/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,18 @@ func RunSSHUpgradeAvalanchego(host *models.Host, network models.Network, avalanc
if err != nil {
return err
}

if err := docker.ComposeSSHSetupNode(host, network, avalancheGoVersion, withMonitoring, publicAccessToHTTPPort); err != nil {
if err := docker.ComposeOverSSH("Compose Node",
host,
constants.SSHScriptTimeout,
"templates/avalanchego.docker-compose.yml",
docker.DockerComposeInputs{
AvalanchegoVersion: avalancheGoVersion,
WithMonitoring: withMonitoring,
WithAvalanchego: true,
E2E: utils.IsE2E(),
E2EIP: utils.E2EConvertIP(host.IP),
E2ESuffix: utils.E2ESuffix(host.IP),
}); err != nil {
return err
}
return docker.RestartDockerCompose(host, constants.SSHLongRunningScriptTimeout)
Expand Down Expand Up @@ -424,21 +434,21 @@ func RunSSHSetupDevNet(host *models.Host, nodeInstanceDirPath string) error {
}
if err := host.Upload(
filepath.Join(nodeInstanceDirPath, constants.GenesisFileName),
filepath.Join(constants.CloudNodeConfigPath, constants.GenesisFileName),
remoteconfig.GetRemoteAvalancheGenesis(),
constants.SSHFileOpsTimeout,
); err != nil {
return err
}
if err := host.Upload(
filepath.Join(nodeInstanceDirPath, constants.UpgradeFileName),
filepath.Join(constants.CloudNodeConfigPath, constants.UpgradeFileName),
remoteconfig.GetRemoteAvalancheUpgrade(),
constants.SSHFileOpsTimeout,
); err != nil {
return err
}
if err := host.Upload(
filepath.Join(nodeInstanceDirPath, constants.NodeFileName),
filepath.Join(constants.CloudNodeConfigPath, constants.NodeFileName),
remoteconfig.GetRemoteAvalancheNodeConfig(),
constants.SSHFileOpsTimeout,
); err != nil {
return err
Expand Down

0 comments on commit c401829

Please sign in to comment.