kuma
190 строк · 5.8 Кб
1package graceful
2
3import (
4"fmt"
5"time"
6
7. "github.com/onsi/ginkgo/v2"
8. "github.com/onsi/gomega"
9corev1 "k8s.io/api/core/v1"
10kube_meta "k8s.io/apimachinery/pkg/apis/meta/v1"
11"k8s.io/apimachinery/pkg/util/intstr"
12
13"github.com/kumahq/kuma/pkg/plugins/policies/meshretry/api/v1alpha1"
14"github.com/kumahq/kuma/pkg/util/channels"
15"github.com/kumahq/kuma/pkg/util/pointer"
16. "github.com/kumahq/kuma/test/framework"
17"github.com/kumahq/kuma/test/framework/client"
18"github.com/kumahq/kuma/test/framework/deployments/testserver"
19"github.com/kumahq/kuma/test/framework/envs/kubernetes"
20)
21
22func ChangeService() {
23const namespace = "changesvc"
24const mesh = "changesvc"
25
26firstTestServerLabels := map[string]string{
27"app": "test-server",
28"changesvc-test-label": "first",
29}
30
31secondTestServerLabels := map[string]string{
32"app": "test-server",
33"changesvc-test-label": "second",
34}
35
36thirdTestServerLabels := map[string]string{
37"kuma.io/sidecar-injection": "disabled",
38"app": "test-server",
39"changesvc-test-label": "third",
40}
41
42newSvc := func(selector map[string]string) *corev1.Service {
43return &corev1.Service{
44TypeMeta: kube_meta.TypeMeta{
45Kind: "Service",
46APIVersion: "v1",
47},
48ObjectMeta: kube_meta.ObjectMeta{
49Name: "test-server",
50Namespace: namespace,
51},
52Spec: corev1.ServiceSpec{
53Ports: []corev1.ServicePort{
54{
55Name: "main",
56Port: int32(80),
57TargetPort: intstr.FromString("main"),
58AppProtocol: pointer.To("htt"),
59},
60},
61Selector: selector,
62},
63}
64}
65
66BeforeAll(func() {
67err := NewClusterSetup().
68Install(MTLSMeshKubernetes(mesh)).
69Install(MeshTrafficPermissionAllowAllKubernetes(mesh)).
70Install(NamespaceWithSidecarInjection(namespace)).
71Install(testserver.Install(
72testserver.WithNamespace(namespace),
73testserver.WithMesh(mesh),
74testserver.WithName("demo-client"),
75)).
76Install(testserver.Install(
77testserver.WithNamespace(namespace),
78testserver.WithMesh(mesh),
79testserver.WithName("test-server-first"),
80testserver.WithEchoArgs("echo", "--instance", "test-server-first"),
81testserver.WithoutService(),
82testserver.WithoutWaitingToBeReady(), // WaitForPods assumes that app label is name, but we change this in WithPodLabels
83testserver.WithPodLabels(firstTestServerLabels),
84)).
85Install(testserver.Install(
86testserver.WithNamespace(namespace),
87testserver.WithMesh(mesh),
88testserver.WithName("test-server-second"),
89testserver.WithEchoArgs("echo", "--instance", "test-server-second"),
90testserver.WithoutService(),
91testserver.WithoutWaitingToBeReady(), // WaitForPods assumes that app label is name, but we change this in WithPodLabels
92testserver.WithPodLabels(secondTestServerLabels),
93)).
94Install(testserver.Install(
95testserver.WithNamespace(namespace),
96testserver.WithName("test-server-third"),
97testserver.WithEchoArgs("echo", "--instance", "test-server-third"),
98testserver.WithoutService(),
99testserver.WithoutWaitingToBeReady(), // WaitForPods assumes that app label is name, but we change this in WithPodLabels
100testserver.WithPodLabels(thirdTestServerLabels),
101)).
102Install(YamlK8sObject(newSvc(firstTestServerLabels))).
103Setup(kubernetes.Cluster)
104Expect(err).To(Succeed())
105
106// remove retries to avoid covering failed request
107Expect(DeleteMeshPolicyOrError(
108kubernetes.Cluster,
109v1alpha1.MeshRetryResourceTypeDescriptor,
110fmt.Sprintf("mesh-retry-all-%s", mesh),
111)).To(Succeed())
112})
113
114E2EAfterAll(func() {
115Expect(kubernetes.Cluster.TriggerDeleteNamespace(namespace)).To(Succeed())
116Expect(kubernetes.Cluster.DeleteMesh(mesh)).To(Succeed())
117})
118
119doRequest := func() (string, error) {
120resp, err := client.CollectEchoResponse(
121kubernetes.Cluster,
122"demo-client",
123"test-server:80",
124client.FromKubernetesPod(namespace, "demo-client"),
125)
126return resp.Instance, err
127}
128
129It("should gracefully switch to other service", func() {
130// given traffic to the first server
131Eventually(func(g Gomega) {
132instance, err := doRequest()
133g.Expect(err).ToNot(HaveOccurred())
134g.Expect(instance).To(Equal("test-server-first"))
135}, "30s", "1s").Should(Succeed())
136
137// and constant traffic in the background
138var failedErr error
139closeCh := make(chan struct{})
140defer close(closeCh)
141go func() {
142for {
143if channels.IsClosed(closeCh) {
144return
145}
146if _, err := doRequest(); err != nil {
147failedErr = err
148return
149}
150// add a slight delay to not overwhelm completely the host running this test and leave more resources to other tests running in parallel.
151time.Sleep(50 * time.Millisecond)
152}
153}()
154
155// when
156err := kubernetes.Cluster.Install(YamlK8sObject(newSvc(secondTestServerLabels)))
157
158// then traffic shifted
159Expect(err).To(Succeed())
160Eventually(func(g Gomega) {
161instance, err := doRequest()
162g.Expect(err).ToNot(HaveOccurred())
163g.Expect(instance).To(Equal("test-server-second"))
164}, "30s", "1s").Should(Succeed())
165
166// and we did not drop a single request
167Expect(failedErr).ToNot(HaveOccurred())
168})
169
170It("should switch to the instance of a service that in not in the mesh", func() {
171// given
172Expect(kubernetes.Cluster.Install(YamlK8sObject(newSvc(firstTestServerLabels)))).To(Succeed())
173Eventually(func(g Gomega) {
174instance, err := doRequest()
175g.Expect(err).ToNot(HaveOccurred())
176g.Expect(instance).To(Equal("test-server-first"))
177}, "30s", "1s").Should(Succeed())
178
179// when
180err := kubernetes.Cluster.Install(YamlK8sObject(newSvc(thirdTestServerLabels)))
181
182// then
183Expect(err).To(Succeed())
184Eventually(func(g Gomega) {
185instance, err := doRequest()
186g.Expect(err).ToNot(HaveOccurred())
187g.Expect(instance).To(Equal("test-server-third"))
188}, "30s", "1s").Should(Succeed())
189})
190}
191