-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsabakan_state_setter_test.go
151 lines (134 loc) · 4.27 KB
/
sabakan_state_setter_test.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
147
148
149
150
151
package dctest
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strconv"
"github.com/cybozu-go/log"
"github.com/cybozu-go/neco"
"github.com/cybozu-go/neco/storage"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// testSabakanStateSetter tests the behavior of sabakan-state-setter in bootstrapping
func testSabakanStateSetter() {
It("should wait for all nodes to join serf", func() {
By("getting machines list")
machines, err := getSabakanMachines("--without-role=boot")
Expect(err).NotTo(HaveOccurred())
availableNodeCount := len(machines)
Expect(availableNodeCount).NotTo(Equal(0))
By("checking all serf members are active")
Eventually(func() error {
m, err := getSerfWorkerMembers()
if err != nil {
return err
}
if len(m.Members) != availableNodeCount {
return fmt.Errorf("too few serf members. expected %d, actual %d", availableNodeCount, len(m.Members))
}
return nil
}).Should(Succeed())
})
It("should wait for all machines to become healthy", func() {
Eventually(func() error {
machines, err := getSabakanMachines()
if err != nil {
return err
}
for _, m := range machines {
if m.Spec.Rack >= 3 && m.Spec.Role == "boot" {
continue
}
if m.Status.State.String() != "healthy" {
return errors.New(m.Spec.Serial + " is not healthy:" + m.Status.State.String())
}
}
return nil
}).Should(Succeed())
})
It("should switch the leader", func() {
By("getting leader node name")
var leaderNodeBefore string
Eventually(func() error {
node, err := getLeaderNode(storage.KeySabakanStateSetterLeader)
if err != nil {
return err
}
leaderNodeBefore = node
return nil
}).Should(Succeed())
By("restarting sabakan-state-setter on " + leaderNodeBefore)
index, err := strconv.Atoi(leaderNodeBefore[len(leaderNodeBefore)-1:])
Expect(err).ShouldNot(HaveOccurred(), "data=%s", leaderNodeBefore[len(leaderNodeBefore)-1:])
stdout, stderr, err := execAt(bootServers[index], "sudo", "systemctl", "restart", "sabakan-state-setter.service")
Expect(err).NotTo(HaveOccurred(), "stdout=%s, stderr=%s", stdout, stderr)
By("getting leader node name again")
Eventually(func() error {
leaderNodeAfter, err := getLeaderNode(storage.KeySabakanStateSetterLeader)
if err != nil {
return err
}
if leaderNodeAfter == leaderNodeBefore {
return errors.New("leader is not changed")
}
return nil
}).Should(Succeed())
})
It("should change shutdown job schedule", func() {
// Run the shutdown job every minute in dctest.
for _, boot := range bootServers {
execSafeAt(boot, "sudo", "sed", "-i", "'s/shutdown-schedule:.*/shutdown-schedule: \"@every 1m\"/'", "/usr/share/neco/sabakan-state-setter.yml")
execSafeAt(boot, "sudo", "systemctl", "restart", "sabakan-state-setter.service")
}
By("checking status of sabakan-state-setter")
Eventually(func() error {
for _, boot := range bootServers {
stdout, _, err := execAt(boot, "systemctl", "is-active", "sabakan-state-setter.service")
if err != nil {
return fmt.Errorf("sabakan-state-setter on %s is not active: %s", boot, stdout)
}
}
return nil
}).Should(Succeed())
})
}
func getLeaderNode(leaderKeyPrefix string) (string, error) {
stdout, _, err := execEtcdctlAt(bootServers[0], "-w", "json", "get", neco.NecoPrefix+leaderKeyPrefix, "--prefix")
if err != nil {
return "", err
}
var result struct {
KVS []*struct {
CreateRevision int `json:"create_revision"`
Value string `json:"value"`
} `json:"kvs"`
}
err = json.Unmarshal(stdout, &result)
if err != nil {
return "", err
}
if len(result.KVS) == 0 {
return "", errors.New("there is no candidate")
}
var revision int
var value string
for _, kvs := range result.KVS {
val, err := base64.StdEncoding.DecodeString(kvs.Value)
if err != nil {
return "", err
}
log.Info("sabakan-state-setter: leader key revision of "+string(val), map[string]interface{}{
"revision": kvs.CreateRevision,
})
// revision starts at 1
// https://github.com/etcd-io/website/blob/master/content/docs/v3.4.0/learning/glossary.md#revision
if revision == 0 || kvs.CreateRevision < revision {
revision = kvs.CreateRevision
value = string(val)
}
}
log.Info("sabakan-state-setter: leader is "+value, nil)
return value, nil
}