-
Notifications
You must be signed in to change notification settings - Fork 55
/
sync.go
119 lines (110 loc) · 3.96 KB
/
sync.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (C) 2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nodecmd
import (
"fmt"
"path/filepath"
"sync"
"github.com/ava-labs/avalanche-cli/cmd/subnetcmd"
"github.com/ava-labs/avalanche-cli/pkg/ansible"
"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
"github.com/ava-labs/avalanche-cli/pkg/constants"
"github.com/ava-labs/avalanche-cli/pkg/models"
"github.com/ava-labs/avalanche-cli/pkg/ssh"
"github.com/ava-labs/avalanche-cli/pkg/ux"
"github.com/spf13/cobra"
)
func newSyncCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "sync [clusterName] [subnetName]",
Short: "(ALPHA Warning) Sync nodes in a cluster with a subnet",
Long: `(ALPHA Warning) This command is currently in experimental mode.
The node sync command enables all nodes in a cluster to be bootstrapped to a Subnet.
You can check the subnet bootstrap status by calling avalanche node status <clusterName> --subnet <subnetName>`,
Args: cobrautils.ExactArgs(2),
RunE: syncSubnet,
}
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")
return cmd
}
func syncSubnet(_ *cobra.Command, args []string) error {
clusterName := args[0]
subnetName := args[1]
if err := checkCluster(clusterName); err != nil {
return err
}
if _, err := subnetcmd.ValidateSubnetNameAndGetChains([]string{subnetName}); err != nil {
return err
}
hosts, err := ansible.GetInventoryFromAnsibleInventoryFile(app.GetAnsibleInventoryDirPath(clusterName))
if err != nil {
return err
}
if len(validators) != 0 {
hosts, err = filterHosts(hosts, validators)
if err != nil {
return err
}
}
defer disconnectHosts(hosts)
if !avoidChecks {
if err := checkHostsAreBootstrapped(hosts); err != nil {
return err
}
if err := checkHostsAreHealthy(hosts); err != nil {
return err
}
if err := checkHostsAreRPCCompatible(hosts, subnetName); err != nil {
return err
}
}
untrackedNodes, err := trackSubnet(hosts, clusterName, subnetName)
if err != nil {
return err
}
if len(untrackedNodes) > 0 {
return fmt.Errorf("node(s) %s failed to sync with subnet %s", untrackedNodes, subnetName)
}
ux.Logger.PrintToUser("Node(s) successfully started syncing with Subnet!")
ux.Logger.PrintToUser(fmt.Sprintf("Check node subnet syncing status with avalanche node status %s --subnet %s", clusterName, subnetName))
return nil
}
// trackSubnet exports deployed subnet in user's local machine to cloud server and calls node to
// start tracking the specified subnet (similar to avalanche subnet join <subnetName> command)
func trackSubnet(
hosts []*models.Host,
clusterName string,
subnetName string,
) ([]string, error) {
subnetPath := "/tmp/" + subnetName + constants.ExportSubnetSuffix
networkFlag := "--cluster " + clusterName
if err := subnetcmd.CallExportSubnet(subnetName, subnetPath); err != nil {
return nil, err
}
wg := sync.WaitGroup{}
wgResults := models.NodeResults{}
for _, host := range hosts {
wg.Add(1)
go func(nodeResults *models.NodeResults, host *models.Host) {
defer wg.Done()
subnetExportPath := filepath.Join("/tmp", filepath.Base(subnetPath))
if err := ssh.RunSSHExportSubnet(host, subnetPath, subnetExportPath); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
return
}
if err := ssh.RunSSHUploadClustersConfig(host, app.GetClustersConfigPath()); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
}
if err := ssh.RunSSHTrackSubnet(host, subnetName, subnetExportPath, networkFlag); err != nil {
nodeResults.AddResult(host.NodeID, nil, err)
return
}
}(&wgResults, host)
}
wg.Wait()
if wgResults.HasErrors() {
return nil, fmt.Errorf("failed to track subnet for node(s) %s", wgResults.GetErrorHostMap())
}
return wgResults.GetErrorHosts(), nil
}