Skip to content

Commit 930d665

Browse files
committed
chore(e2e): create multiple VMs in one go through the CLI
1 parent 8442d5b commit 930d665

File tree

1 file changed

+43
-81
lines changed

1 file changed

+43
-81
lines changed

e2e/cluster/cmx/cluster.go

Lines changed: 43 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"sync"
1313
"testing"
1414
"time"
15-
16-
"github.com/google/uuid"
1715
)
1816

1917
type ClusterInput struct {
@@ -35,77 +33,41 @@ type Cluster struct {
3533
}
3634

3735
type Node struct {
38-
ID string `json:"id"`
39-
Name string `json:"name"`
36+
ID string `json:"id"`
37+
Name string `json:"name"`
38+
NetworkID string `json:"network_id"`
4039

4140
privateIP string `json:"-"`
4241
sshEndpoint string `json:"-"`
4342
adminConsoleURL string `json:"-"`
4443
}
4544

4645
type Network struct {
47-
ID string `json:"id"`
48-
Name string `json:"name"`
46+
ID string `json:"id"`
4947
}
5048

5149
func NewCluster(in *ClusterInput) *Cluster {
5250
c := &Cluster{t: in.T, supportBundleNodeIndex: in.SupportBundleNodeIndex}
5351
c.t.Cleanup(c.Destroy)
5452

55-
c.Nodes = make([]Node, in.Nodes)
56-
57-
network, err := NewNetwork(in)
53+
nodes, err := NewNodes(in)
5854
if err != nil {
59-
in.T.Fatalf("failed to create network: %v", err)
60-
}
61-
c.network = network
62-
63-
for i := range c.Nodes {
64-
node, err := NewNode(in, i, network.ID)
65-
if node != nil {
66-
c.Nodes[i] = *node
67-
}
68-
if err != nil {
69-
in.T.Fatalf("create node %d: %v", i, err)
70-
}
71-
in.T.Logf("node%d created with ID %s", i, node.ID)
55+
in.T.Fatalf("failed to create nodes: %v", err)
7256
}
57+
in.T.Logf("cluster created with network ID %s", nodes[0].NetworkID)
58+
c.Nodes = nodes
59+
c.network = &Network{ID: nodes[0].NetworkID}
7360

7461
return c
7562
}
7663

77-
func NewNetwork(in *ClusterInput) (*Network, error) {
78-
name := fmt.Sprintf("ec-e2e-%s", uuid.New().String())
79-
in.T.Logf("creating network %s", name)
80-
81-
output, err := exec.Command("replicated", "network", "create", "--name", name, "--wait", "5m", "-ojson").Output() // stderr can break json parsing
82-
if err != nil {
83-
if exitErr, ok := err.(*exec.ExitError); ok {
84-
return nil, fmt.Errorf("create network %s: %w: stderr: %s: stdout: %s", name, err, string(exitErr.Stderr), string(output))
85-
}
86-
return nil, fmt.Errorf("create network %s: %w: stdout: %s", name, err, string(output))
87-
}
88-
89-
var networks []Network
90-
if err := json.Unmarshal(output, &networks); err != nil {
91-
return nil, fmt.Errorf("parse networks output: %v: %s", err, string(output))
92-
}
93-
if len(networks) != 1 {
94-
return nil, fmt.Errorf("expected 1 network, got %d", len(networks))
95-
}
96-
network := &networks[0]
97-
in.T.Logf("Network created with ID %s", network.ID)
98-
return network, nil
99-
}
100-
101-
func NewNode(in *ClusterInput, index int, networkID string) (node *Node, err error) {
102-
nodeName := fmt.Sprintf("node%d", index)
103-
in.T.Logf("creating node %s", nodeName)
64+
func NewNodes(in *ClusterInput) ([]Node, error) {
65+
in.T.Logf("creating %s nodes", strconv.Itoa(in.Nodes))
10466

10567
args := []string{
10668
"vm", "create",
107-
"--name", nodeName,
108-
"--network", networkID,
69+
"--name", "ec-test-suite",
70+
"--count", strconv.Itoa(in.Nodes),
10971
"--wait", "5m",
11072
"-ojson",
11173
}
@@ -128,54 +90,54 @@ func NewNode(in *ClusterInput, index int, networkID string) (node *Node, err err
12890
output, err := exec.Command("replicated", args...).Output() // stderr can break json parsing
12991
if err != nil {
13092
if exitErr, ok := err.(*exec.ExitError); ok {
131-
return nil, fmt.Errorf("create node %s: %w: stderr: %s: stdout: %s", nodeName, err, string(exitErr.Stderr), string(output))
93+
return nil, fmt.Errorf("create nodes: %w: stderr: %s: stdout: %s", err, string(exitErr.Stderr), string(output))
13294
}
133-
return nil, fmt.Errorf("create node %s: %w: stdout: %s", nodeName, err, string(output))
95+
return nil, fmt.Errorf("create nodes: %w: stdout: %s", err, string(output))
13496
}
13597

13698
var nodes []Node
13799
if err := json.Unmarshal(output, &nodes); err != nil {
138100
return nil, fmt.Errorf("unmarshal node: %v: %s", err, string(output))
139101
}
140-
if len(nodes) != 1 {
141-
return nil, fmt.Errorf("expected 1 node, got %d", len(nodes))
142-
}
143-
node = &nodes[0]
144102

145103
// TODO (@salah): remove this once the bug is fixed in CMX
146104
// note: the vm gets marked as ready before the services are actually running
147105
time.Sleep(30 * time.Second)
148106

149-
sshEndpoint, err := getSSHEndpoint(node.ID)
150-
if err != nil {
151-
return node, fmt.Errorf("get ssh endpoint for node %s: %v", nodeName, err)
152-
}
153-
node.sshEndpoint = sshEndpoint
107+
for i := range nodes {
108+
sshEndpoint, err := getSSHEndpoint(nodes[i].ID)
109+
if err != nil {
110+
return nil, fmt.Errorf("get ssh endpoint for node %s: %v", nodes[i].ID, err)
111+
}
112+
nodes[i].sshEndpoint = sshEndpoint
154113

155-
privateIP, err := discoverPrivateIP(*node)
156-
if err != nil {
157-
return node, fmt.Errorf("discover node private IP: %v", err)
158-
}
159-
node.privateIP = privateIP
114+
privateIP, err := discoverPrivateIP(nodes[i])
115+
if err != nil {
116+
return nil, fmt.Errorf("discover node private IP: %v", err)
117+
}
118+
nodes[i].privateIP = privateIP
160119

161-
if err := ensureAssetsDir(*node); err != nil {
162-
return node, fmt.Errorf("ensure assets dir on node %s: %v", node.Name, err)
163-
}
120+
if err := ensureAssetsDir(nodes[i]); err != nil {
121+
return nil, fmt.Errorf("ensure assets dir on node %s: %v", nodes[i].ID, err)
122+
}
164123

165-
if err := copyScriptsToNode(*node); err != nil {
166-
return node, fmt.Errorf("copy scripts to node %s: %v", node.Name, err)
167-
}
124+
if err := copyScriptsToNode(nodes[i]); err != nil {
125+
return nil, fmt.Errorf("copy scripts to node %s: %v", nodes[i].ID, err)
126+
}
168127

169-
if index == 0 {
170-
in.T.Logf("exposing port 30003 on node %s", node.Name)
171-
hostname, err := exposePort(*node, "30003")
172-
if err != nil {
173-
return node, fmt.Errorf("expose port: %v", err)
128+
if in.Nodes == 1 {
129+
in.T.Logf("exposing port 30003 on node %s", nodes[i].ID)
130+
hostname, err := exposePort(nodes[i], "30003")
131+
if err != nil {
132+
return nil, fmt.Errorf("expose port: %v", err)
133+
}
134+
nodes[i].adminConsoleURL = fmt.Sprintf("http://%s", hostname)
174135
}
175-
node.adminConsoleURL = fmt.Sprintf("http://%s", hostname)
136+
137+
in.T.Logf("node %d created with ID %s and private IP %s", i, nodes[i].ID, nodes[i].privateIP)
176138
}
177139

178-
return node, nil
140+
return nodes, nil
179141
}
180142

181143
func discoverPrivateIP(node Node) (string, error) {
@@ -344,7 +306,7 @@ func (c *Cluster) removeNode(node Node) {
344306
func (c *Cluster) removeNetwork(network Network) {
345307
output, err := exec.Command("replicated", "network", "rm", network.ID).CombinedOutput()
346308
if err != nil {
347-
c.t.Logf("failed to destroy network %s: %v: %s", network.Name, err, string(output))
309+
c.t.Logf("failed to destroy network %s: %v: %s", network.ID, err, string(output))
348310
}
349311
}
350312

0 commit comments

Comments
 (0)