-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
node.go
146 lines (134 loc) · 3.72 KB
/
node.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package e2eutil
import (
"fmt"
"time"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/helper/uuid"
)
// AgentRestart is a test helper function that restarts a client node
// running under systemd using a raw_exec job. Returns the job ID of
// the restart job so that callers can clean it up.
func AgentRestart(client *api.Client, nodeID string) (string, error) {
ok, err := isUbuntu(client, nodeID)
if !ok {
// TODO(tgross): we're checking this because we want to use
// systemctl to restart the node, but we should also figure
// out a way to detect dev mode targets.
return "", fmt.Errorf("AgentRestart only works against ubuntu targets")
}
if err != nil {
return "", err
}
job := newRestartJob(nodeID)
jobID := *job.ID
_, _, err = client.Jobs().Register(job, nil)
if err != nil {
return jobID, err
}
reasonErr := fmt.Errorf("timed out")
retries := 30
for retries > 0 {
time.Sleep(1 * time.Second)
retries--
allocStubs, _, err := client.Jobs().Allocations(jobID, true, nil)
if err != nil {
reasonErr = err
continue
}
if len(allocStubs) > 0 {
INNER:
for _, state := range allocStubs[0].TaskStates {
if state.State == "dead" {
node, _, err := client.Nodes().Info(nodeID, nil)
if err != nil {
reasonErr = err
break INNER
}
if node != nil && node.Status == "ready" {
return jobID, nil
}
reasonErr = fmt.Errorf("node status not ready")
}
}
}
}
return jobID, fmt.Errorf("node did not become ready: %v", reasonErr)
}
func isUbuntu(client *api.Client, nodeID string) (bool, error) {
node, _, err := client.Nodes().Info(nodeID, nil)
if err != nil || node == nil {
return false, err
}
if name, ok := node.Attributes["os.name"]; ok {
return name == "ubuntu", nil
}
return false, nil
}
func newRestartJob(nodeID string) *api.Job {
jobType := "batch"
name := "restart"
jobID := "restart-" + uuid.Generate()[0:8]
attempts := 0
job := &api.Job{
Name: &name,
ID: &jobID,
Datacenters: []string{"dc1"},
Type: &jobType,
TaskGroups: []*api.TaskGroup{
{
Name: &name,
Constraints: []*api.Constraint{
{
LTarget: "${node.unique.id}",
RTarget: nodeID,
Operand: "=",
},
},
RestartPolicy: &api.RestartPolicy{
Attempts: &attempts,
},
Tasks: []*api.Task{
{
Name: name,
Driver: "raw_exec",
Config: map[string]interface{}{
"command": "systemctl",
"args": []string{"restart", "nomad"},
},
},
},
},
},
}
job.Canonicalize()
return job
}
// ListWindowsClientNodes returns a list of Windows client IDs, so that tests
// can skip operating-specific tests if there are no Windows clients available.
// Returns an error only on client errors.
func ListWindowsClientNodes(client *api.Client) ([]string, error) {
return listClientNodesByOS(client, "windows")
}
// ListLinuxClientNodes returns a list of Linux client IDs, so that tests
// can skip operating-specific tests if there are no Linux clients available
// Returns an error only on client errors.
func ListLinuxClientNodes(client *api.Client) ([]string, error) {
return listClientNodesByOS(client, "linux")
}
func listClientNodesByOS(client *api.Client, osName string) ([]string, error) {
nodeIDs := []string{}
nodes, _, err := client.Nodes().List(&api.QueryOptions{})
if err != nil {
return nodeIDs, fmt.Errorf("could not query nodes: %v", err)
}
for _, stubNode := range nodes {
node, _, err := client.Nodes().Info(stubNode.ID, nil)
if err != nil {
return nodeIDs, fmt.Errorf("could not query nodes: %v", err)
}
if name, ok := node.Attributes["kernel.name"]; ok && name == osName {
nodeIDs = append(nodeIDs, stubNode.ID)
}
}
return nodeIDs, nil
}