Skip to content

Commit

Permalink
add subnet alias (#1987)
Browse files Browse the repository at this point in the history
* add api for fuji

* put old code back

* add subnet alias

* avoid github api if custom version is set

* add publicAPI to network

* fixes

* fix golang template newline

* switch to host network

* fix template

* rm host mode for monitoring

* add e2e support back to template

* fix e2e indent

* make sure that all API hosts can receive traffic on IP and not localhost

* lint

* change subnet-alias implementation after join refactor

* mv public access config to clusterconf and address other felipe feedback

* lint

* check for err

* fix wiz

* additional subnet aliases

* address felipe feedback

* add helperfunc to template

* fix

* fix text/template instead of html

* use text/template
  • Loading branch information
arturrez authored Aug 1, 2024
1 parent bf5d157 commit ae18785
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 9 deletions.
6 changes: 4 additions & 2 deletions cmd/nodecmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import (
)

var (
subnetOnly bool
avoidChecks bool
subnetOnly bool
avoidChecks bool
subnetAliases []string
)

func newDeployCmd() *cobra.Command {
Expand All @@ -33,6 +34,7 @@ It saves the deploy info both locally and remotely.
}
cmd.Flags().BoolVar(&subnetOnly, "subnet-only", false, "only create a subnet")
cmd.Flags().BoolVar(&avoidChecks, "no-checks", false, "do not check for healthy status or rpc compatibility of nodes against subnet")
cmd.Flags().StringSliceVar(&subnetAliases, "subnet-aliases", nil, "additional subnet aliases to be used for RPC calls in addition to subnet blockchain name")
return cmd
}

Expand Down
13 changes: 13 additions & 0 deletions cmd/nodecmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ You can check the subnet bootstrap status by calling avalanche node status <clus

cmd.Flags().StringSliceVar(&validators, "validators", []string{}, "sync subnet into given comma separated list of validators. defaults to all cluster nodes")
cmd.Flags().BoolVar(&avoidChecks, "no-checks", false, "do not check for bootstrapped/healthy status or rpc compatibility of nodes against subnet")
cmd.Flags().StringSliceVar(&subnetAliases, "subnet-aliases", nil, "subnet alias to be used for RPC calls. defaults to subnet blockchain ID")

return cmd
}
Expand Down Expand Up @@ -124,15 +125,27 @@ func trackSubnet(
// and get list of subnets
allSubnets := utils.Unique(append(clusterConf.Subnets, subnetName))

// load sidecar to get subnet blockchain ID
sc, err := app.LoadSidecar(subnetName)
if err != nil {
return nil, err
}
blockchainID := sc.Networks[network.Name()].BlockchainID

wg := sync.WaitGroup{}
wgResults := models.NodeResults{}
subnetAliases := append([]string{subnetName}, subnetAliases...)
for _, host := range hosts {
wg.Add(1)
go func(nodeResults *models.NodeResults, host *models.Host) {
defer wg.Done()
if err := ssh.RunSSHStopNode(host); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
}

if err := ssh.RunSSHRenderAvagoAliasConfigFile(host, blockchainID.String(), subnetAliases); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
}
if err := ssh.RunSSHRenderAvalancheNodeConfig(app, host, network, allSubnets); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
}
Expand Down
1 change: 1 addition & 0 deletions cmd/nodecmd/wiz.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ The node wiz command creates a devnet and deploys, sync and validate a subnet in
cmd.Flags().BoolVar(&deployTeleporterRegistry, "deploy-teleporter-registry", true, "deploy Teleporter Registry")
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().StringSliceVar(&subnetAliases, "subnet-aliases", nil, "additional subnet aliases to be used for RPC calls in addition to subnet blockchain name")
return cmd
}

Expand Down
1 change: 1 addition & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
SuffixSeparator = "_"
SidecarFileName = "sidecar.json"
GenesisFileName = "genesis.json"
AliasesFileName = "aliases.json"
SidecarSuffix = SuffixSeparator + SidecarFileName
GenesisSuffix = SuffixSeparator + GenesisFileName
NodeFileName = "node.json"
Expand Down
2 changes: 1 addition & 1 deletion pkg/docker/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"bytes"
"embed"
"fmt"
"html/template"
"os"
"path/filepath"
"strings"
"text/template"
"time"

"github.com/ava-labs/avalanche-cli/pkg/constants"
Expand Down
27 changes: 23 additions & 4 deletions pkg/remoteconfig/avalanche.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package remoteconfig

import (
"bytes"
"html/template"
"path/filepath"
"strings"
"text/template"

"github.com/ava-labs/avalanche-cli/pkg/constants"
)
Expand All @@ -22,6 +22,8 @@ type AvalancheConfigInputs struct {
PublicIP string
StateSyncEnabled bool
PruningEnabled bool
Aliases []string
BlockChainID string
TrackSubnets string
BootstrapIDs string
BootstrapIPs string
Expand All @@ -38,6 +40,8 @@ func PrepareAvalancheConfig(publicIP string, networkID string, subnets []string)
StateSyncEnabled: true,
PruningEnabled: false,
TrackSubnets: strings.Join(subnets, ","),
Aliases: nil,
BlockChainID: "",
}
}

Expand All @@ -46,7 +50,10 @@ func RenderAvalancheTemplate(templateName string, config AvalancheConfigInputs)
if err != nil {
return nil, err
}
tmpl, err := template.New("config").Parse(string(templateBytes))
helperFuncs := template.FuncMap{
"join": strings.Join,
}
tmpl, err := template.New("config").Funcs(helperFuncs).Parse(string(templateBytes))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -75,16 +82,28 @@ func RenderAvalancheCChainConfig(config AvalancheConfigInputs) ([]byte, error) {
}
}

func RenderAvalancheAliasesConfig(config AvalancheConfigInputs) ([]byte, error) {
if output, err := RenderAvalancheTemplate("templates/avalanche-aliases.tmpl", config); err != nil {
return nil, err
} else {
return output, nil
}
}

func GetRemoteAvalancheNodeConfig() string {
return filepath.Join(constants.CloudNodeConfigPath, "node.json")
return filepath.Join(constants.CloudNodeConfigPath, constants.NodeFileName)
}

func GetRemoteAvalancheCChainConfig() string {
return filepath.Join(constants.CloudNodeConfigPath, "chains", "C", "config.json")
}

func GetRemoteAvalancheGenesis() string {
return filepath.Join(constants.CloudNodeConfigPath, "genesis.json")
return filepath.Join(constants.CloudNodeConfigPath, constants.GenesisFileName)
}

func GetRemoteAvalancheAliasesConfig() string {
return filepath.Join(constants.CloudNodeConfigPath, "chains", constants.AliasesFileName)
}

func AvalancheFolderToCreate() []string {
Expand Down
3 changes: 3 additions & 0 deletions pkg/remoteconfig/templates/avalanche-aliases.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"{{.BlockChainID}}": ["{{join .Aliases "\", \""}}"]
}
65 changes: 64 additions & 1 deletion pkg/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,51 @@ func RunSSHUploadStakingFiles(host *models.Host, nodeInstanceDirPath string) err
)
}

// RunSSHRenderAvagoAliasConfigFile renders avalanche alias config to a remote host via SSH.
func RunSSHRenderAvagoAliasConfigFile(
host *models.Host,
blockchainID string,
subnetAliases []string,
) error {
aliasConf, err := remoteconfig.RenderAvalancheAliasesConfig(remoteconfig.AvalancheConfigInputs{
BlockChainID: blockchainID,
Aliases: subnetAliases,
})
if err != nil {
return err
}
// merge alias config into remote config
if aliasConfigFileExists(host) {
// read remote aliases
remoteAliases, err := getAvalancheGoAliasData(host)
if err != nil {
return err
}
localAliases := make(map[string]interface{})
if err := json.Unmarshal(aliasConf, &localAliases); err != nil {
return err
}
// merge with local aliases presedence. Result is in remoteAliases
maps.Copy(remoteAliases, localAliases)
aliasConf, err = json.MarshalIndent(remoteAliases, "", " ")
if err != nil {
return err
}
}
aliasConfFile, err := os.CreateTemp("", "avalanchecli-alias-*.yml")
if err != nil {
return err
}
defer os.Remove(aliasConfFile.Name())
if err := os.WriteFile(aliasConfFile.Name(), aliasConf, constants.DefaultPerms755); err != nil {
return err
}
if err := host.Upload(aliasConfFile.Name(), remoteconfig.GetRemoteAvalancheAliasesConfig(), constants.SSHFileOpsTimeout); err != nil {
return err
}
return nil
}

// RunSSHRenderAvalancheNodeConfig renders avalanche node config to a remote host via SSH.
func RunSSHRenderAvalancheNodeConfig(app *application.Avalanche, host *models.Host, network models.Network, trackSubnets []string) error {
// get subnet ids
Expand Down Expand Up @@ -851,9 +896,14 @@ func nodeConfigFileExists(host *models.Host) bool {
return nodeConfigFileExists
}

func aliasConfigFileExists(host *models.Host) bool {
aliasConfigFileExists, _ := host.FileExists(remoteconfig.GetRemoteAvalancheAliasesConfig())
return aliasConfigFileExists
}

func getAvalancheGoConfigData(host *models.Host) (map[string]interface{}, error) {
// get remote node.json file
nodeJSONPath := filepath.Join(constants.CloudNodeConfigPath, constants.NodeFileName)
nodeJSONPath := filepath.Join(constants.CloudNodeConfigPath, constants.NodeConfigJSONFile)
// parse node.json file
nodeJSON, err := host.ReadFileBytes(nodeJSONPath, constants.SSHFileOpsTimeout)
if err != nil {
Expand All @@ -865,3 +915,16 @@ func getAvalancheGoConfigData(host *models.Host) (map[string]interface{}, error)
}
return avagoConfig, nil
}

func getAvalancheGoAliasData(host *models.Host) (map[string]interface{}, error) {
// parse aliases.json file
aliasesJSON, err := host.ReadFileBytes(remoteconfig.GetRemoteAvalancheAliasesConfig(), constants.SSHFileOpsTimeout)
if err != nil {
return nil, err
}
var aliases map[string]interface{}
if err := json.Unmarshal(aliasesJSON, &aliases); err != nil {
return nil, err
}
return aliases, nil
}
2 changes: 1 addition & 1 deletion pkg/utils/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"bytes"
"encoding/base64"
"fmt"
"html/template"
"os"
"os/exec"
"regexp"
"strings"
"text/template"

"github.com/ava-labs/avalanche-cli/pkg/constants"
)
Expand Down

0 comments on commit ae18785

Please sign in to comment.