1
16
17 package apps
18
19 import (
20 "context"
21
22 "github.com/onsi/ginkgo/v2"
23
24 appsv1 "k8s.io/api/apps/v1"
25 v1 "k8s.io/api/core/v1"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/util/version"
28
29 "k8s.io/kubernetes/test/e2e/framework"
30 e2estatefulset "k8s.io/kubernetes/test/e2e/framework/statefulset"
31 "k8s.io/kubernetes/test/e2e/upgrades"
32 )
33
34
35 func createStatefulSetService(name string, labels map[string]string) *v1.Service {
36 headlessService := &v1.Service{
37 ObjectMeta: metav1.ObjectMeta{
38 Name: name,
39 },
40 Spec: v1.ServiceSpec{
41 Selector: labels,
42 },
43 }
44 headlessService.Spec.Ports = []v1.ServicePort{
45 {Port: 80, Name: "http", Protocol: v1.ProtocolTCP},
46 }
47 headlessService.Spec.ClusterIP = "None"
48 return headlessService
49 }
50
51
52 type StatefulSetUpgradeTest struct {
53 service *v1.Service
54 set *appsv1.StatefulSet
55 }
56
57
58 func (StatefulSetUpgradeTest) Name() string { return "[sig-apps] statefulset-upgrade" }
59
60
61 func (StatefulSetUpgradeTest) Skip(upgCtx upgrades.UpgradeContext) bool {
62 minVersion := version.MustParseSemantic("1.5.0")
63
64 for _, vCtx := range upgCtx.Versions {
65 if vCtx.Version.LessThan(minVersion) {
66 return true
67 }
68 }
69 return false
70 }
71
72
73 func (t *StatefulSetUpgradeTest) Setup(ctx context.Context, f *framework.Framework) {
74 ssName := "ss"
75 labels := map[string]string{
76 "foo": "bar",
77 "baz": "blah",
78 }
79 headlessSvcName := "test"
80 statefulPodMounts := []v1.VolumeMount{{Name: "datadir", MountPath: "/data/"}}
81 podMounts := []v1.VolumeMount{{Name: "home", MountPath: "/home"}}
82 ns := f.Namespace.Name
83 t.set = e2estatefulset.NewStatefulSet(ssName, ns, headlessSvcName, 2, statefulPodMounts, podMounts, labels)
84 t.service = createStatefulSetService(ssName, labels)
85 *(t.set.Spec.Replicas) = 3
86 e2estatefulset.PauseNewPods(t.set)
87
88 ginkgo.By("Creating service " + headlessSvcName + " in namespace " + ns)
89 _, err := f.ClientSet.CoreV1().Services(ns).Create(ctx, t.service, metav1.CreateOptions{})
90 framework.ExpectNoError(err)
91
92 ginkgo.By("Creating statefulset " + ssName + " in namespace " + ns)
93 *(t.set.Spec.Replicas) = 3
94 _, err = f.ClientSet.AppsV1().StatefulSets(ns).Create(ctx, t.set, metav1.CreateOptions{})
95 framework.ExpectNoError(err)
96
97 ginkgo.By("Saturating stateful set " + t.set.Name)
98 e2estatefulset.Saturate(ctx, f.ClientSet, t.set)
99 t.verify(ctx, f)
100 t.restart(ctx, f)
101 t.verify(ctx, f)
102 }
103
104
105 func (t *StatefulSetUpgradeTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
106 <-done
107 t.verify(ctx, f)
108 }
109
110
111 func (t *StatefulSetUpgradeTest) Teardown(ctx context.Context, f *framework.Framework) {
112 e2estatefulset.DeleteAllStatefulSets(ctx, f.ClientSet, t.set.Name)
113 }
114
115 func (t *StatefulSetUpgradeTest) verify(ctx context.Context, f *framework.Framework) {
116 ginkgo.By("Verifying statefulset mounted data directory is usable")
117 framework.ExpectNoError(e2estatefulset.CheckMount(ctx, f.ClientSet, t.set, "/data"))
118
119 ginkgo.By("Verifying statefulset provides a stable hostname for each pod")
120 framework.ExpectNoError(e2estatefulset.CheckHostname(ctx, f.ClientSet, t.set))
121
122 ginkgo.By("Verifying statefulset set proper service name")
123 framework.ExpectNoError(e2estatefulset.CheckServiceName(t.set, t.set.Spec.ServiceName))
124
125 cmd := "echo $(hostname) > /data/hostname; sync;"
126 ginkgo.By("Running " + cmd + " in all stateful pods")
127 framework.ExpectNoError(e2estatefulset.ExecInStatefulPods(ctx, f.ClientSet, t.set, cmd))
128 }
129
130 func (t *StatefulSetUpgradeTest) restart(ctx context.Context, f *framework.Framework) {
131 ginkgo.By("Restarting statefulset " + t.set.Name)
132 e2estatefulset.Restart(ctx, f.ClientSet, t.set)
133 e2estatefulset.WaitForRunningAndReady(ctx, f.ClientSet, *t.set.Spec.Replicas, t.set)
134 }
135
View as plain text