Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Acp77 remote etna devnet #2233

Merged
merged 20 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion cmd/blockchaincmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ func getChainsInSubnet(blockchainName string) ([]string, error) {
}

func checkSubnetEVMDefaultAddressNotInAlloc(network models.Network, chain string) error {
if network.Kind != models.Local && network.Kind != models.Devnet && os.Getenv(constants.SimulatePublicNetwork) == "" {
if network.Kind != models.Local && network.Kind != models.Devnet && network.Kind != models.EtnaDevnet && os.Getenv(constants.SimulatePublicNetwork) == "" {
genesis, err := app.LoadEvmGenesis(chain)
if err != nil {
return err
Expand Down Expand Up @@ -410,6 +410,26 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
}
}

if sidecar.Sovereign && bootstrapValidatorsJSONFilePath == "" {
// TODO: add check for local cluster from another PR
if len(bootstrapValidators) == 0 && globalNetworkFlags.ClusterName != "" {
// get bootstrap validators from cluster
changeOwnerAddr, err := getKeyForChangeOwner("", "", network)
if err != nil {
return err
}
bootstrapValidators, err = getClusterBootstrapValidators(globalNetworkFlags.ClusterName, changeOwnerAddr)
if err != nil {
return err
}
} else {
bootstrapValidators, err = promptBootstrapValidators(network)
if err != nil {
return err
}
}
}

ux.Logger.PrintToUser("Deploying %s to %s", chains, network.Name())

if network.Kind == models.Local {
Expand Down
26 changes: 26 additions & 0 deletions cmd/blockchaincmd/prompt_genesis_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package blockchaincmd

import (
"encoding/hex"
"fmt"

"github.com/ava-labs/avalanche-cli/pkg/application"
Expand Down Expand Up @@ -120,6 +121,31 @@ func generateNewNodeAndBLS() (string, string, string, error) {
return nodeID.String(), publicKey, pop, nil
}

func getClusterBootstrapValidators(clusterName string, changeOwnerAddr string) ([]models.SubnetValidator, error) {
clusterConf, err := app.GetClusterConfig(clusterName)
if err != nil {
return nil, err
}
subnetValidators := []models.SubnetValidator{}
hostIDs := utils.Filter(clusterConf.GetCloudIDs(), clusterConf.IsAvalancheGoHost)
for _, h := range hostIDs {
id, pub, pop, err := utils.GetNodeParams(app.GetNodeInstanceDirPath(h))
if err != nil {
return nil, err
}
ux.Logger.Info("Bootstrap validator info for Host: %s | Node ID: %s | Public Key: %s | Proof of Possession: %s", h, id, hex.EncodeToString(pub), hex.EncodeToString(pop))
subnetValidators = append(subnetValidators, models.SubnetValidator{
NodeID: id.String(),
Weight: constants.BootstrapValidatorWeight,
Balance: constants.BootstrapValidatorBalance,
BLSPublicKey: fmt.Sprintf("%s%s", "0x", hex.EncodeToString(pub)),
BLSProofOfPossession: fmt.Sprintf("%s%s", "0x", hex.EncodeToString(pop)),
ChangeOwnerAddr: changeOwnerAddr,
})
}
return subnetValidators, nil
}

func promptBootstrapValidators(network models.Network) ([]models.SubnetValidator, error) {
var subnetValidators []models.SubnetValidator
numBootstrapValidators, err := app.Prompt.CaptureInt(
Expand Down
77 changes: 70 additions & 7 deletions cmd/nodecmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const (
)

var (
createSupportedNetworkOptions = []networkoptions.NetworkOption{networkoptions.Fuji, networkoptions.Devnet}
createSupportedNetworkOptions = []networkoptions.NetworkOption{networkoptions.Fuji, networkoptions.Devnet, networkoptions.EtnaDevnet}
globalNetworkFlags networkoptions.NetworkFlags
useAWS bool
useGCP bool
Expand Down Expand Up @@ -125,6 +125,10 @@ 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-ids", []string{}, "nodeIDs of bootstrap nodes")
cmd.Flags().StringArrayVar(&bootstrapIPs, "bootstrap-ips", []string{}, "IP:port pairs of bootstrap nodes")
Comment on lines +128 to +129
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we need to even enable flags for bootstrap ids and bootstrap ips. Lets just set these values to hardcoded values if users want join etna devnet.

cmd.Flags().StringVar(&genesisPath, "genesis", "", "path to genesis file")
cmd.Flags().StringVar(&upgradePath, "upgrade", "", "path to upgrade file")
return cmd
}

Expand Down Expand Up @@ -202,8 +206,27 @@ func preCreateChecks(clusterName string) error {
return err
}
if clusterConfig.Local {
return notImplementedForLocal("addDashboard")
return notImplementedForLocal("create")
} // bootsrap checks
if globalNetworkFlags.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 _, ipPortPair := range bootstrapIPs {
if ok := utils.IsValidIPPort(ipPortPair); !ok {
return fmt.Errorf("invalid ip:port pair %s", ipPortPair)
}
}

return nil
}

Expand Down Expand Up @@ -245,9 +268,6 @@ func stringToAWSVolumeType(input string) types.VolumeType {

func createNodes(cmd *cobra.Command, args []string) error {
clusterName := args[0]
if err := preCreateChecks(clusterName); err != nil {
return err
}
network, err := networkoptions.GetNetworkFromCmdLineFlags(
app,
"",
Expand All @@ -257,9 +277,44 @@ func createNodes(cmd *cobra.Command, args []string) error {
createSupportedNetworkOptions,
"",
)
if err != nil {
if err := preCreateChecks(clusterName); err != nil {
return err
}
if network.Kind == models.EtnaDevnet {
publicHTTPPortAccess = true // public http port access for etna devnet api for PoAManagerDeployment
bootstrapIDs = constants.EtnaDevnetBootstrapNodeIDs
bootstrapIPs = constants.EtnaDevnetBootstrapIPs

// create genesis and upgrade files
genesisTmpFile, err := os.CreateTemp("", "genesis")
if err != nil {
return err
}
if _, err := genesisTmpFile.Write(constants.EtnaDevnetGenesisData); err != nil {
return err
}
if err := genesisTmpFile.Close(); err != nil {
return err
}
genesisPath = genesisTmpFile.Name()

upgradeTmpFile, err := os.CreateTemp("", "upgrade")
if err != nil {
return err
}
if _, err := upgradeTmpFile.Write(constants.EtnaDevnetUpgradeData); err != nil {
return err
}
if err := upgradeTmpFile.Close(); err != nil {
return err
}
upgradePath = upgradeTmpFile.Name()

defer func() {
_ = os.Remove(genesisTmpFile.Name())
_ = os.Remove(upgradeTmpFile.Name())
}()
}
network = models.NewNetworkFromCluster(network, clusterName)
globalNetworkFlags.UseDevnet = network.Kind == models.Devnet // set globalNetworkFlags.UseDevnet to true if network is devnet for further use
avaGoVersionSetting := node.AvalancheGoVersionSettings{
Expand Down Expand Up @@ -725,7 +780,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 Down
1 change: 0 additions & 1 deletion cmd/nodecmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ status by running avalanche node status local
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")
cmd.Flags().StringVar(&stakingTLSKeyPath, "staking-tls-key-path", "", "path to provided staking tls key for node")
cmd.Flags().StringVar(&stakingCertKeyPath, "staking-cert-key-path", "", "path to provided staking cert key for node")
cmd.Flags().StringVar(&stakingSignerKeyPath, "staking-signer-key-path", "", "path to provided staking signer key for node")
Expand Down
9 changes: 2 additions & 7 deletions cmd/nodecmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ func upgrade(_ *cobra.Command, args []string) error {
if clusterConfig.Local {
return notImplementedForLocal("upgrade")
}
network := clusterConfig.Network
hosts, err := ansible.GetInventoryFromAnsibleInventoryFile(app.GetAnsibleInventoryDirPath(clusterName))
if err != nil {
return err
Expand All @@ -73,9 +72,7 @@ func upgrade(_ *cobra.Command, args []string) error {
for host, upgradeInfo := range toUpgradeNodesMap {
if upgradeInfo.AvalancheGoVersion != "" {
spinner := spinSession.SpinToUser(utils.ScriptLog(host.NodeID, fmt.Sprintf("Upgrading avalanchego to version %s...", upgradeInfo.AvalancheGoVersion)))
// check if host is API host
publicAccessToHTTPPort := clusterConfig.IsAPIHost(host.GetCloudID()) || clusterConfig.HTTPAccess == constants.PublicAccess
if err := upgradeAvalancheGo(host, network, upgradeInfo.AvalancheGoVersion, publicAccessToHTTPPort); err != nil {
if err := upgradeAvalancheGo(host, upgradeInfo.AvalancheGoVersion); err != nil {
ux.SpinFailWithError(spinner, "", err)
return err
}
Expand Down Expand Up @@ -221,11 +218,9 @@ func checkIfKeyIsStandardVMName(vmName string) bool {

func upgradeAvalancheGo(
host *models.Host,
network models.Network,
avaGoVersionToUpdateTo string,
publicAccessToHTTPPort bool,
) error {
if err := ssh.RunSSHUpgradeAvalanchego(host, network, avaGoVersionToUpdateTo, publicAccessToHTTPPort); err != nil {
if err := ssh.RunSSHUpgradeAvalanchego(host, avaGoVersionToUpdateTo); err != nil {
return err
}
return nil
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
26 changes: 24 additions & 2 deletions pkg/docker/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,40 @@ 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) {
type AvalancheGoConfigOptions struct {
BootstrapIPs []string
BootstrapIDs []string
GenesisPath string
UpgradePath string
AllowPublicAccess bool
}

func prepareAvalanchegoConfig(
host *models.Host,
network models.Network,
avalancheGoConfig AvalancheGoConfigOptions,
) (string, string, error) {
avagoConf := remoteconfig.PrepareAvalancheConfig(host.IP, network.NetworkIDFlagValue(), nil)
if publicAccess || utils.IsE2E() {
if avalancheGoConfig.AllowPublicAccess || utils.IsE2E() {
avagoConf.HTTPHost = "0.0.0.0"
}
avagoConf.BootstrapIPs = strings.Join(avalancheGoConfig.BootstrapIPs, ",")
avagoConf.BootstrapIDs = strings.Join(avalancheGoConfig.BootstrapIDs, ",")
if avalancheGoConfig.GenesisPath != "" {
avagoConf.GenesisPath = filepath.Join(constants.DockerNodeConfigPath, constants.GenesisFileName)
}
if avalancheGoConfig.UpgradePath != "" {
avagoConf.UpgradePath = filepath.Join(constants.DockerNodeConfigPath, constants.UpgradeFileName)
}
nodeConf, err := remoteconfig.RenderAvalancheNodeConfig(avagoConf)
if err != nil {
return "", "", err
Expand Down
42 changes: 36 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,
Comment on lines +32 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth encapsulating all of these options in an AvalancheGoConfigOptions struct so that they don't need to be passed around individually?

withMonitoring bool,
publicAccessToHTTPPort bool,
) error {
startTime := time.Now()
folderStructure := remoteconfig.RemoteFoldersToCreateAvalanchego()
for _, dir := range folderStructure {
Expand All @@ -41,7 +51,17 @@ 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,
AvalancheGoConfigOptions{
BootstrapIDs: avalanchegoBootstrapIDs,
BootstrapIPs: avalanchegoBootstrapIPs,
GenesisPath: avalanchegoGenesisFilePath,
UpgradePath: avalanchegoUpgradeFilePath,
AllowPublicAccess: publicAccessToHTTPPort,
},
)
if err != nil {
return err
}
Expand All @@ -60,12 +80,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 +110,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 +163,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{})
}
Loading
Loading