@@ -20,7 +20,9 @@ import (
2020 "fmt"
2121 "os"
2222 "os/exec"
23+ "strconv"
2324 "sync"
25+ "time"
2426
2527 . "github.com/onsi/ginkgo/v2"
2628 . "github.com/onsi/gomega"
@@ -31,6 +33,7 @@ import (
3133)
3234
3335var _ = Describe ("etcd-operator" , Ordered , func () {
36+ dir , _ := utils .GetProjectDir ()
3437
3538 BeforeAll (func () {
3639 var err error
@@ -55,7 +58,7 @@ var _ = Describe("etcd-operator", Ordered, func() {
5558 By ("wait while etcd-operator is ready" , func () {
5659 cmd := exec .Command ("kubectl" , "wait" , "--namespace" ,
5760 "etcd-operator-system" , "deployment/etcd-operator-controller-manager" ,
58- "--for" , "jsonpath={.status.availableReplicas }=1" , "--timeout=5m" )
61+ "--for" , "jsonpath={.status.readyReplicas }=1" , "--timeout=5m" )
5962 _ , err = utils .Run (cmd )
6063 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
6164 })
@@ -73,17 +76,12 @@ var _ = Describe("etcd-operator", Ordered, func() {
7376
7477 Context ("Simple" , func () {
7578 It ("should deploy etcd cluster" , func () {
76- var err error
7779 const namespace = "test-simple-etcd-cluster"
7880 var wg sync.WaitGroup
7981 wg .Add (1 )
8082
81- By ("create namespace" , func () {
82- cmd := exec .Command ("sh" , "-c" ,
83- fmt .Sprintf ("kubectl create namespace %s --dry-run=client -o yaml | kubectl apply -f -" , namespace )) // nolint:lll
84- _ , err = utils .Run (cmd )
85- ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
86- })
83+ CreateNamespace (namespace )
84+ DeferCleanup (DeleteNamespaceCB (namespace ))
8785
8886 By ("apply simple etcd cluster manifest" , func () {
8987 dir , _ := utils .GetProjectDir ()
@@ -95,16 +93,9 @@ var _ = Describe("etcd-operator", Ordered, func() {
9593 ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
9694 })
9795
98- By ("wait for statefulset is ready" , func () {
99- cmd := exec .Command ("kubectl" , "wait" ,
100- "statefulset/test" ,
101- "--for" , "jsonpath={.status.readyReplicas}=3" ,
102- "--namespace" , namespace ,
103- "--timeout" , "5m" ,
104- )
105- _ , err = utils .Run (cmd )
106- ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
107- })
96+ WaitSTSReady ("statefulset/test" , namespace )
97+
98+ // CheckEtcdClusterHealthy("service/test", namespace)
10899
109100 client , err := utils .GetEtcdClient (ctx , client.ObjectKey {Namespace : namespace , Name : "test" })
110101 Expect (err ).NotTo (HaveOccurred ())
@@ -187,4 +178,149 @@ var _ = Describe("etcd-operator", Ordered, func() {
187178 })
188179 })
189180
181+ DescribeTable ("Upgrade" ,
182+ func (namespace string , fileName string , version string ) {
183+ CreateNamespace (namespace )
184+ DeferCleanup (DeleteNamespaceCB (namespace ))
185+
186+ By ("apply upgrade etcd cluster manifest" )
187+
188+ cmd := exec .Command ("kubectl" , "apply" ,
189+ "--filename" , dir + fileName ,
190+ "--namespace" , namespace ,
191+ )
192+ _ , err := utils .Run (cmd )
193+
194+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
195+
196+ WaitSTSReady ("statefulset/test" , namespace )
197+ CheckEtcdClusterHealthy ("service/test" , namespace )
198+
199+ By ("upgrade etcd cluster to one patch version" )
200+ cmd = exec .Command ("kubectl" , "patch" ,
201+ "etcdcluster/test" ,
202+ "--type" , "json" ,
203+ // Strategic Merge Patch is not currently supported by the etcd-operator
204+ // "--patch",
205+ // fmt.Sprintf(
206+ // "{\"spec\":{\"podTemplate\":{\"containers\":[{\"name\":\"etcd\",\"image\":\"quay.io/coreos/etcd:%s\"}]}}}",
207+ // version,
208+ // ),
209+ "--patch" ,
210+ fmt .Sprintf (
211+ "[{\" op\" : \" replace\" , \" path\" : \" /spec/podTemplate/spec/containers/0/image\" , " +
212+ "\" value\" :\" quay.io/coreos/etcd:%s\" }]" ,
213+ version ,
214+ ),
215+ "--namespace" , namespace ,
216+ )
217+ _ , err = utils .Run (cmd )
218+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
219+
220+ // Give the operator some time to update the sts
221+ time .Sleep (2 * time .Second )
222+
223+ WaitSTSReady ("statefulset/test" , namespace )
224+ CheckEtcdClusterHealthy ("service/test" , namespace )
225+ },
226+ Entry (
227+ "should upgrade etcd cluster patch version" ,
228+ "test-upgrade-3-5-11--3-5-12" ,
229+ "/test/e2e/testdata/etcdcluster-3.5.yaml" ,
230+ "v3.5.12" ,
231+ ),
232+ Entry (
233+ "should downgrade etcd cluster patch version" ,
234+ "test-downgrade-3-5-11--3-5-10" ,
235+ "/test/e2e/testdata/etcdcluster-3.5.yaml" ,
236+ "v3.5.10" ,
237+ ),
238+ Entry (
239+ "should upgrade etcd cluster to one minor version" ,
240+ "test-upgrade-3-4-32--3-5-10" ,
241+ "/test/e2e/testdata/etcdcluster-3.4.yaml" ,
242+ "v3.5.10" ,
243+ ),
244+ Entry (
245+ "should downgrade etcd cluster to one minor version" ,
246+ "test-downgrade-3-5-11--3-4-32" ,
247+ "/test/e2e/testdata/etcdcluster-3.5.yaml" ,
248+ "v3.4.32" ,
249+ ),
250+ Entry (
251+ "should upgrade etcd cluster to multiple minor version" ,
252+ "test-upgrade-3-3-27--3-5-11" ,
253+ "/test/e2e/testdata/etcdcluster-3.3.yaml" ,
254+ "v3.5.11" ,
255+ ),
256+ Entry (
257+ "should downgrade etcd cluster to multiple minor version" ,
258+ "test-downgrade-3-5-11--3-3-27" ,
259+ "/test/e2e/testdata/etcdcluster-3.5.yaml" ,
260+ "v3.3.27" ,
261+ ),
262+ )
263+
190264})
265+
266+ func DeleteNamespaceCB (namespace string ) func () error {
267+ return func () error {
268+ return DeleteNamespace (namespace )
269+ }
270+ }
271+
272+ func DeleteNamespace (namespace string ) error {
273+ By ("delete namespace" )
274+
275+ cmd := exec .Command ("kubectl" , "delete" , "namespace" , namespace )
276+ _ , err := utils .Run (cmd )
277+
278+ return err
279+ }
280+
281+ func CreateNamespace (namespace string ) {
282+ By ("create namespace" )
283+
284+ cmd := exec .Command ("kubectl" , "create" , "namespace" , namespace )
285+ _ , err := utils .Run (cmd )
286+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
287+ }
288+
289+ func WaitSTSReady (stsName , namespace string ) {
290+ By ("wait for statefulset is ready" )
291+
292+ cmd := exec .Command ("kubectl" , "wait" ,
293+ stsName ,
294+ "--for" , "jsonpath={.status.availableReplicas}=3" ,
295+ "--namespace" , namespace ,
296+ "--timeout" , "5m" ,
297+ )
298+ _ , err := utils .Run (cmd )
299+
300+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
301+ }
302+
303+ func CheckEtcdClusterHealthy (serviceName , namespace string ) {
304+ var wg sync.WaitGroup
305+ wg .Add (1 )
306+
307+ By ("port-forward service to localhost" )
308+ port , _ := utils .GetFreePort ()
309+ go func () {
310+ defer GinkgoRecover ()
311+ defer wg .Done ()
312+
313+ cmd := exec .Command ("kubectl" , "port-forward" ,
314+ serviceName , strconv .Itoa (port )+ ":2379" ,
315+ "--namespace" , namespace ,
316+ )
317+ _ , err := utils .Run (cmd )
318+ ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
319+ }()
320+
321+ By ("check etcd cluster is healthy" )
322+ endpoints := []string {"localhost:" + strconv .Itoa (port )}
323+ for i := 0 ; i < 3 ; i ++ {
324+ Expect (utils .IsEtcdClusterHealthy (endpoints )).To (BeTrue ())
325+ }
326+ }
0 commit comments